summaryrefslogtreecommitdiff
path: root/pystache/tests/main.py
blob: 7cfcfebf5bd12553b176b300a80dfbcd60c99ade (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# coding: utf-8

"""
Exposes a run_tests() function that runs all tests in the project.

This module is for our test console script.

"""

import os
import sys
from unittest import TestProgram

from pystache.tests.common import PACKAGE_DIR, PROJECT_DIR, SPEC_TEST_DIR
from pystache.tests.doctesting import get_doctests
# TODO: change this to pystache.tests.spectesting.
from pystache.tests.test_mustachespec import get_spec_tests


UNITTEST_FILE_PREFIX = "test_"

# TODO: enhance this function to create spec-test tests.
def run_tests(sys_argv):
    """
    Run all tests in the project.

    Arguments:

      sys_argv: a reference to sys.argv.

    """
    try:
        # TODO: use optparse command options instead.
        project_dir = sys_argv[1]
        sys_argv.pop()
    except IndexError:
        project_dir = PROJECT_DIR

    if len(sys_argv) <= 1 or sys_argv[-1].startswith("-"):
        # Then no explicit module or test names were provided, so
        # auto-detect all unit tests.
        module_names = _discover_test_modules(PACKAGE_DIR)
        sys_argv.extend(module_names)

    _PystacheTestProgram._text_doctest_dir = project_dir
    _PystacheTestProgram._spec_test_dir = SPEC_TEST_DIR

    # We pass None for the module because we do not want the unittest
    # module to resolve module names relative to a given module.
    # (This would require importing all of the unittest modules from
    # this module.)  See the loadTestsFromName() method of the
    # unittest.TestLoader class for more details on this parameter.
    _PystacheTestProgram(argv=sys_argv, module=None)
    # No need to return since unitttest.main() exits.


def _find_unittest_files(package_dir):
    """
    Return a list of paths to all unit-test files in the given package directory.

    """
    paths = []  # Return value.

    def is_unittest(file_name):
        return file_name.startswith(UNITTEST_FILE_PREFIX) and file_name.endswith('.py')

    # os.walk() is new in Python 2.3
    #   http://docs.python.org/library/os.html#os.walk
    for dir_path, dir_names, file_names in os.walk(package_dir):
        file_names = filter(is_unittest, file_names)

        for file_name in file_names:
            path = os.path.join(dir_path, file_name)
            paths.append(path)

    return paths


def _get_module_names(package_dir, paths):
    """
    Return a list of fully-qualified test module names given a list of module paths.

    """
    package_dir = os.path.abspath(package_dir)
    package_name = os.path.split(package_dir)[1]

    prefix_length = len(package_dir)

    module_names = []
    for path in paths:
        path = os.path.abspath(path)  # for example <path_to_package>/subpackage/module.py
        rel_path = path[prefix_length:]  # for example /subpackage/module.py
        rel_path = os.path.splitext(rel_path)[0]  # for example /subpackage/module

        parts = []
        while True:
            (rel_path, tail) = os.path.split(rel_path)
            if not tail:
                break
            parts.insert(0, tail)
        # We now have, for example, ['subpackage', 'module'].
        parts.insert(0, package_name)
        module = ".".join(parts)
        module_names.append(module)

    return module_names


def _get_test_module_names(package_dir):
    """
    Return a list of fully-qualified module names given a list of module paths.

    """
    paths = _find_unittest_files(package_dir)
    modules = _get_module_names(package_dir, paths)

    return modules


def _discover_test_modules(package_dir):
    """
    Discover and return a sorted list of the names of unit-test modules.

    """
    modules = _get_test_module_names(package_dir)
    modules.sort()

    # This is a sanity check to ensure that the unit-test discovery
    # methods are working.
    if len(modules) < 1:
        raise Exception("No unit-test modules found.")

    return modules


# The function unittest.main() is an alias for unittest.TestProgram's
# constructor.  TestProgram's constructor calls self.runTests() as its
# final step, which expects self.test to be set.  The constructor sets
# the self.test attribute by calling one of self.testLoader's "loadTests"
# methods prior to callint self.runTests().  Each loadTest method returns
# a unittest.TestSuite instance.  Thus, self.test is set to a TestSuite
# instance prior to calling runTests().
class _PystacheTestProgram(TestProgram):

    """
    Instantiating an instance of this class runs all tests.

    """

    def runTests(self):
        # self.test is a unittest.TestSuite instance:
        #   http://docs.python.org/library/unittest.html#unittest.TestSuite
        tests = self.test

        doctest_suites = get_doctests(self._text_doctest_dir)
        tests.addTests(doctest_suites)

        spec_testcases = get_spec_tests(self._spec_test_dir)
        tests.addTests(spec_testcases)

        TestProgram.runTests(self)