from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.test import TestCase as django_TestCase
import importlib
import unittest

class Command(BaseCommand):
  """ Command for running quick tests without a separate test database.
  
    Subclasses of django.test.Testcase are not supported since they attempt to 
    flush the database.
    
  """

  args = '<application name>'
  help = 'Run unittests for specified application without creating test \
database. Subclasses of django.test.TestCase are not supported.'
  
  INVALED_APP_MSG = 'The first argument must be a valid application name'
  NO_TESTS_MSG = 'No tests.py file was found in the application you specified'

  def handle(self, *args, **kwargs):
    """ Required for management command
    """
    
    if len(args) == 0:
      raise CommandError(self.INVALED_APP_MSG)
    
    app_name = args[0]
    
    self.TestApp(app_name)
    
  
  def TestApp(self, app_name):
    """Run tests for the specified application."""
    
    if not app_name in settings.INSTALLED_APPS:
      raise CommandError(self.INVALED_APP_MSG)
    
    try:
      tests = importlib.import_module('.'.join([app_name, 'tests']))
    except:
      raise CommandError(self.NO_TESTS_MSG)
    
    suite = self.LoadNonJangoTestsFromModule(tests)
    
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)   
    
    return result
  
  def LoadNonJangoTestsFromModule(self, module):
    """ Load tests from module which are not subclass of django.test.TestCase
    """
    
    tests = []
    loader = unittest.TestLoader()
    for name in dir(module):
      obj = getattr(module, name)
      
      if isinstance(obj, type)\
      and issubclass(obj, unittest.TestCase)\
      and not issubclass(obj, django_TestCase):
        tests += loader.loadTestsFromTestCase(obj)
    
    return unittest.TestSuite(tests)