blob: 999f40e56e6123320cf18726e9d7b2fea816de6d [file] [log] [blame]
mbligh4205d892008-07-14 16:23:20 +00001import common
mblighe8819cd2008-02-15 16:48:40 +00002import os, doctest, glob, sys
showard2e490cc2008-10-08 19:15:45 +00003from django.conf import settings
showarda5288b42009-07-28 20:06:08 +00004from django.db import connection
5import django.test.utils
mblighe8819cd2008-02-15 16:48:40 +00006
7# doctest takes a copy+paste log of a Python interactive session, runs a Python
8# interpreter, and replays all the inputs from the log, checking that the
9# outputs all match the log. This allows us to easily test behavior and
10# document functions at the same time, since the log shows exactly how functions
11# are called and what their outputs look like. See
12# http://www.python.org/doc/2.4.3/lib/module-doctest.html for more details.
13
14# In this file, we run doctest on all files found in the doctests/ directory.
15# We use django.test.utils to run the tests against a fresh test database every
16# time.
17
showard2e490cc2008-10-08 19:15:45 +000018class DoctestRunner(object):
19 _PRINT_AFTER = 'Ran %d tests from %s'
mblighe8819cd2008-02-15 16:48:40 +000020
showard2e490cc2008-10-08 19:15:45 +000021 def __init__(self, app_dir, app_module_name):
22 self._app_dir = app_dir
23 self._app_module_name = app_module_name
showard5c7e8192008-04-08 19:43:21 +000024
mblighe8819cd2008-02-15 16:48:40 +000025
showard2e490cc2008-10-08 19:15:45 +000026 def _get_doctest_paths(self):
27 doctest_dir = os.path.join(self._app_dir, 'doctests')
28 doctest_paths = [os.path.join(doctest_dir, filename) for filename
29 in os.listdir(doctest_dir)
30 if not filename.startswith('.')
31 if not filename.endswith('~')]
32 return sorted(doctest_paths)
mblighe8819cd2008-02-15 16:48:40 +000033
34
showard2e490cc2008-10-08 19:15:45 +000035 def _get_modules(self):
36 modules = []
37 module_names = [os.path.basename(filename)[:-3]
38 for filename
39 in glob.glob(os.path.join(self._app_dir, '*.py'))
40 if '__init__' not in filename
41 and 'test.py' not in filename]
42 # TODO: use common.setup_modules.import_module()
43 app_module = __import__(self._app_module_name, globals(), locals(),
44 module_names)
45 for module_name in module_names:
46 modules.append(getattr(app_module, module_name))
47 return modules
48
49
50 def run_tests(self):
51 """
52 module_list is ignored - we're just required to have this signature as a
53 Django test runner.
54 """
55 doctest_paths = self._get_doctest_paths()
56 modules = self._get_modules()
57 total_errors = 0
Mike Truty3536b982011-08-29 13:05:16 -070058 old_db = settings.DATABASES['default']['NAME']
showard2e490cc2008-10-08 19:15:45 +000059 django.test.utils.setup_test_environment()
showarda5288b42009-07-28 20:06:08 +000060 connection.creation.create_test_db()
showard2e490cc2008-10-08 19:15:45 +000061 try:
62 for module in modules:
63 failures, test_count = doctest.testmod(module)
64 print self._PRINT_AFTER % (test_count, module.__name__)
65 total_errors += failures
66 for path in doctest_paths:
67 failures, test_count = doctest.testfile(path,
68 module_relative=False)
69 print self._PRINT_AFTER % (test_count, path)
70 total_errors += failures
71 finally:
showarda5288b42009-07-28 20:06:08 +000072 connection.creation.destroy_test_db(old_db)
showard2e490cc2008-10-08 19:15:45 +000073 django.test.utils.teardown_test_environment()
74 print
75 if total_errors == 0:
76 print 'OK'
77 else:
78 print 'FAIL: %d errors' % total_errors
79 return total_errors