|
1 | 1 | import inspect |
2 | 2 | import json |
3 | 3 | import os |
4 | | -import patchtest2.tests.core as core |
| 4 | +import sys |
| 5 | +import importlib.util |
| 6 | +from pathlib import Path |
5 | 7 | from patchtest2.parser import PatchtestParser |
6 | 8 | from patchtest2.mbox import PatchSeries, TargetRepo |
7 | 9 |
|
8 | 10 |
|
9 | 11 | class Patchtest: |
10 | | - def __init__(self, target_repo, series): |
| 12 | + def __init__(self, target_repo, series, suites=None, module_paths=None): |
11 | 13 | self.target_repo = target_repo |
12 | 14 | self.series = series |
13 | | - self.core_results = { |
14 | | - k: self._results(v) |
15 | | - for (k, v) in inspect.getmembers(core, inspect.isfunction) |
16 | | - if k != "patchtest_result" |
17 | | - } |
18 | | - |
19 | | - self.results = dict( |
20 | | - [ |
21 | | - ( |
22 | | - "core", |
23 | | - self.core_results, |
24 | | - ), |
25 | | - ] |
26 | | - ) |
| 15 | + |
| 16 | + # Always include 'core' suite, then add any additional suites |
| 17 | + self.suites = ['core'] |
| 18 | + if suites: |
| 19 | + # Add additional suites, avoiding duplicates |
| 20 | + for suite in suites: |
| 21 | + if suite not in self.suites: |
| 22 | + self.suites.append(suite) |
| 23 | + |
| 24 | + # Always include src/patchtest2/tests, then add any additional paths |
| 25 | + self.module_paths = ['src/patchtest2/tests'] |
| 26 | + if module_paths: |
| 27 | + # Add additional paths, avoiding duplicates |
| 28 | + for path in module_paths: |
| 29 | + if path not in self.module_paths: |
| 30 | + self.module_paths.append(path) |
| 31 | + |
| 32 | + # Load all test modules and their functions |
| 33 | + self.results = {} |
| 34 | + self._load_test_modules() |
| 35 | + |
| 36 | + def _load_test_modules(self): |
| 37 | + """Load test functions from all specified suites and module paths""" |
| 38 | + for suite_name in self.suites: |
| 39 | + suite_results = {} |
| 40 | + |
| 41 | + # Look for the suite module in all specified paths |
| 42 | + module_found = False |
| 43 | + for module_path in self.module_paths: |
| 44 | + module_file = Path(module_path) / f"{suite_name}.py" |
| 45 | + |
| 46 | + if module_file.exists(): |
| 47 | + module_found = True |
| 48 | + # Load the module dynamically |
| 49 | + spec = importlib.util.spec_from_file_location( |
| 50 | + f"patchtest2.tests.{suite_name}", |
| 51 | + module_file |
| 52 | + ) |
| 53 | + module = importlib.util.module_from_spec(spec) |
| 54 | + |
| 55 | + # Add to sys.modules to handle imports within the module |
| 56 | + sys.modules[f"patchtest2.tests.{suite_name}"] = module |
| 57 | + spec.loader.exec_module(module) |
| 58 | + |
| 59 | + # Extract test functions from the module |
| 60 | + test_functions = { |
| 61 | + k: v for (k, v) in inspect.getmembers(module, inspect.isfunction) |
| 62 | + if k != "patchtest_result" and k.startswith("test_") |
| 63 | + } |
| 64 | + |
| 65 | + # Run tests and collect results |
| 66 | + for func_name, func in test_functions.items(): |
| 67 | + suite_results[func_name] = self._results(func) |
| 68 | + |
| 69 | + break # Found the module, no need to check other paths |
| 70 | + |
| 71 | + if not module_found: |
| 72 | + print(f"Warning: Suite '{suite_name}' not found in any of the specified module paths") |
| 73 | + continue |
| 74 | + |
| 75 | + self.results[suite_name] = suite_results |
27 | 76 |
|
28 | 77 | def _results(self, testname): |
| 78 | + """Run a test function against all patches in the series""" |
29 | 79 | return [testname(patch) for patch in self.series.patchdata] |
30 | 80 |
|
31 | 81 | def _print_result(self, category, tag): |
| 82 | + """Print results for a specific test function""" |
32 | 83 | for value in self.results[category][tag]: |
33 | 84 | print(value) |
34 | 85 |
|
35 | 86 | def _print_results(self, category): |
| 87 | + """Print all results for a specific suite""" |
36 | 88 | for tag in self.results[category].keys(): |
37 | 89 | self._print_result(category, tag) |
38 | 90 |
|
39 | 91 | def print_results(self): |
| 92 | + """Print all results from all suites""" |
40 | 93 | for category in self.results.keys(): |
41 | 94 | self._print_results(category) |
42 | 95 |
|
43 | 96 | def _log_results(self, logfile): |
| 97 | + """Log results to a text file""" |
44 | 98 | result_str = "" |
45 | 99 | for category in self.results.keys(): |
46 | 100 | for tag in self.results[category].keys(): |
47 | 101 | for value in self.results[category][tag]: |
48 | 102 | result_str += value + "\n" |
49 | | - |
50 | 103 | with open(logfile + ".testresult", "w") as f: |
51 | 104 | f.write(result_str) |
52 | 105 |
|
53 | 106 | def _log_json(self, logfile): |
| 107 | + """Log results to a JSON file""" |
54 | 108 | with open(logfile + ".testresult", "w") as f: |
55 | 109 | f.write(json.dumps(self.results, indent=4, sort_keys=True)) |
56 | 110 |
|
57 | 111 | def log_results(self, logfile, mode=None): |
| 112 | + """Log results in specified format""" |
58 | 113 | if mode == "json": |
59 | 114 | self._log_json(logfile) |
60 | 115 | else: |
61 | 116 | self._log_results(logfile) |
62 | 117 |
|
63 | 118 |
|
64 | 119 | def run(): |
| 120 | + """Main entry point for patchtest""" |
65 | 121 | parser = PatchtestParser.get_parser() |
66 | 122 | args = parser.parse_args() |
| 123 | + |
| 124 | + # Parse suites argument |
| 125 | + suites = None |
| 126 | + if hasattr(args, 'suites') and args.suites: |
| 127 | + suites = [suite.strip() for suite in args.suites.split(',')] |
| 128 | + |
| 129 | + # Parse module paths argument |
| 130 | + module_paths = None |
| 131 | + if hasattr(args, 'module_paths') and args.module_paths: |
| 132 | + module_paths = [path.strip() for path in args.module_paths.split(',')] |
| 133 | + |
67 | 134 | target_repo = TargetRepo(args.repodir) |
68 | 135 | series = PatchSeries(args.patch_path) |
69 | | - results = Patchtest(target_repo, series) |
| 136 | + results = Patchtest(target_repo, series, suites=suites, module_paths=module_paths) |
70 | 137 |
|
71 | 138 | results.print_results() |
| 139 | + |
72 | 140 | if args.log_json: |
73 | 141 | results.log_results(os.path.basename(args.patch_path), mode="json") |
74 | | - |
75 | 142 | if args.log_results: |
76 | 143 | results.log_results(os.path.basename(args.patch_path)) |
0 commit comments