• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2import sys, os, os.path, types, traceback, pprint
3
4DATA = 'tests/data'
5
6has_ucs4 = sys.maxunicode > 0xffff
7
8def find_test_functions(collections):
9    if not isinstance(collections, list):
10        collections = [collections]
11    functions = []
12    for collection in collections:
13        if not isinstance(collection, dict):
14            collection = vars(collection)
15        keys = collection.keys()
16        keys.sort()
17        for key in keys:
18            value = collection[key]
19            if isinstance(value, types.FunctionType) and hasattr(value, 'unittest'):
20                functions.append(value)
21    return functions
22
23def find_test_filenames(directory):
24    filenames = {}
25    for filename in os.listdir(directory):
26        if os.path.isfile(os.path.join(directory, filename)):
27            base, ext = os.path.splitext(filename)
28            if base.endswith('-py3'):
29                continue
30            if not has_ucs4 and base.find('-ucs4-') > -1:
31                continue
32            filenames.setdefault(base, []).append(ext)
33    filenames = filenames.items()
34    filenames.sort()
35    return filenames
36
37def parse_arguments(args):
38    if args is None:
39        args = sys.argv[1:]
40    verbose = False
41    if '-v' in args:
42        verbose = True
43        args.remove('-v')
44    if '--verbose' in args:
45        verbose = True
46        args.remove('--verbose')
47    if 'YAML_TEST_VERBOSE' in os.environ:
48        verbose = True
49    include_functions = []
50    if args:
51        include_functions.append(args.pop(0))
52    if 'YAML_TEST_FUNCTIONS' in os.environ:
53        include_functions.extend(os.environ['YAML_TEST_FUNCTIONS'].split())
54    include_filenames = []
55    include_filenames.extend(args)
56    if 'YAML_TEST_FILENAMES' in os.environ:
57        include_filenames.extend(os.environ['YAML_TEST_FILENAMES'].split())
58    return include_functions, include_filenames, verbose
59
60def execute(function, filenames, verbose):
61    if hasattr(function, 'unittest_name'):
62        name = function.unittest_name
63    else:
64        name = function.func_name
65    if verbose:
66        sys.stdout.write('='*75+'\n')
67        sys.stdout.write('%s(%s)...\n' % (name, ', '.join(filenames)))
68    try:
69        function(verbose=verbose, *filenames)
70    except Exception, exc:
71        info = sys.exc_info()
72        if isinstance(exc, AssertionError):
73            kind = 'FAILURE'
74        else:
75            kind = 'ERROR'
76        if verbose:
77            traceback.print_exc(limit=1, file=sys.stdout)
78        else:
79            sys.stdout.write(kind[0])
80            sys.stdout.flush()
81    else:
82        kind = 'SUCCESS'
83        info = None
84        if not verbose:
85            sys.stdout.write('.')
86    sys.stdout.flush()
87    return (name, filenames, kind, info)
88
89def display(results, verbose):
90    if results and not verbose:
91        sys.stdout.write('\n')
92    total = len(results)
93    failures = 0
94    errors = 0
95    for name, filenames, kind, info in results:
96        if kind == 'SUCCESS':
97            continue
98        if kind == 'FAILURE':
99            failures += 1
100        if kind == 'ERROR':
101            errors += 1
102        sys.stdout.write('='*75+'\n')
103        sys.stdout.write('%s(%s): %s\n' % (name, ', '.join(filenames), kind))
104        if kind == 'ERROR':
105            traceback.print_exception(file=sys.stdout, *info)
106        else:
107            sys.stdout.write('Traceback (most recent call last):\n')
108            traceback.print_tb(info[2], file=sys.stdout)
109            sys.stdout.write('%s: see below\n' % info[0].__name__)
110            sys.stdout.write('~'*75+'\n')
111            for arg in info[1].args:
112                pprint.pprint(arg, stream=sys.stdout)
113        for filename in filenames:
114            sys.stdout.write('-'*75+'\n')
115            sys.stdout.write('%s:\n' % filename)
116            data = open(filename, 'rb').read()
117            sys.stdout.write(data)
118            if data and data[-1] != '\n':
119                sys.stdout.write('\n')
120    sys.stdout.write('='*75+'\n')
121    sys.stdout.write('TESTS: %s\n' % total)
122    if failures:
123        sys.stdout.write('FAILURES: %s\n' % failures)
124    if errors:
125        sys.stdout.write('ERRORS: %s\n' % errors)
126    return not (failures or errors)
127
128def run(collections, args=None):
129    test_functions = find_test_functions(collections)
130    test_filenames = find_test_filenames(DATA)
131    include_functions, include_filenames, verbose = parse_arguments(args)
132    results = []
133    for function in test_functions:
134        if include_functions and function.func_name not in include_functions:
135            continue
136        if function.unittest:
137            for base, exts in test_filenames:
138                if include_filenames and base not in include_filenames:
139                    continue
140                filenames = []
141                for ext in function.unittest:
142                    if ext not in exts:
143                        break
144                    filenames.append(os.path.join(DATA, base+ext))
145                else:
146                    skip_exts = getattr(function, 'skip', [])
147                    for skip_ext in skip_exts:
148                        if skip_ext in exts:
149                            break
150                    else:
151                        result = execute(function, filenames, verbose)
152                        results.append(result)
153        else:
154            result = execute(function, [], verbose)
155            results.append(result)
156    return display(results, verbose=verbose)
157
158