8
8
calculate_mutation ,
9
9
)
10
10
from python_tool_competition_2024 .config import Config
11
+ from python_tool_competition_2024 .errors import CommandFailedError
11
12
from python_tool_competition_2024 .results import RatioResult
12
13
from python_tool_competition_2024 .target_finder import find_targets
13
14
@@ -72,6 +73,99 @@ def test_cosmic_ray_calculator(tmp_path: Path) -> None:
72
73
}
73
74
74
75
76
+ def test_cosmic_ray_calculator_with_failing_baseline (tmp_path : Path ) -> None :
77
+ with mock .patch (
78
+ "python_tool_competition_2024.calculation.mutation_calculator.cosmic_ray_calculator.run_command"
79
+ ) as run_command_mock :
80
+ run_command_mock .side_effect = _OutputCounter (fail_baseline = True )
81
+ mock .seal (run_command_mock )
82
+ generated_tests = tmp_path / "dummy" / "generated_tests"
83
+ generated_tests .mkdir (parents = True )
84
+ (generated_tests / "test_example1.py" ).touch ()
85
+ (generated_tests / "test_example2.py" ).touch ()
86
+ config = get_test_config (
87
+ show_commands = False ,
88
+ show_failures = False ,
89
+ targets_dir = TARGETS_DIR ,
90
+ results_dir = tmp_path ,
91
+ )
92
+ targets = find_targets (config )
93
+ with config .console .capture () as capture :
94
+ assert {
95
+ target .source_module : calculate_mutation (target , config )
96
+ for target in targets
97
+ } == {
98
+ "example1" : RatioResult (10 , 0 ),
99
+ "example2" : RatioResult (11 , 1 ),
100
+ "sub_example" : RatioResult (12 , 2 ),
101
+ "sub_example.example3" : RatioResult (13 , 3 ),
102
+ }
103
+ assert tuple (capture .get ().splitlines ()) == tuple (
104
+ (
105
+ f"Could not run mutation testing for { module } . "
106
+ "Add -vv to show the console output."
107
+ )
108
+ for module in (
109
+ "example1" ,
110
+ "example2" ,
111
+ "sub_example" ,
112
+ "sub_example.example3" ,
113
+ )
114
+ )
115
+
116
+ assert run_command_mock .call_args_list == [
117
+ * _cr_calls (config , "example1" , skip_exec = True ),
118
+ * _cr_calls (config , "example2" , skip_exec = True ),
119
+ * _cr_calls (config , "sub_example" , skip_exec = True ),
120
+ * _cr_calls (config , "sub_example.example3" , skip_exec = True ),
121
+ ]
122
+
123
+
124
+ def test_cosmic_ray_calculator_with_failing_baseline_and_output (tmp_path : Path ) -> None :
125
+ with mock .patch (
126
+ "python_tool_competition_2024.calculation.mutation_calculator.cosmic_ray_calculator.run_command"
127
+ ) as run_command_mock :
128
+ run_command_mock .side_effect = _OutputCounter (fail_baseline = True )
129
+ mock .seal (run_command_mock )
130
+ generated_tests = tmp_path / "dummy" / "generated_tests"
131
+ generated_tests .mkdir (parents = True )
132
+ (generated_tests / "test_example1.py" ).touch ()
133
+ (generated_tests / "test_example2.py" ).touch ()
134
+ config = get_test_config (
135
+ show_commands = True ,
136
+ show_failures = False ,
137
+ targets_dir = TARGETS_DIR ,
138
+ results_dir = tmp_path ,
139
+ )
140
+ targets = find_targets (config )
141
+ with config .console .capture () as capture :
142
+ assert {
143
+ target .source_module : calculate_mutation (target , config )
144
+ for target in targets
145
+ } == {
146
+ "example1" : RatioResult (10 , 0 ),
147
+ "example2" : RatioResult (11 , 1 ),
148
+ "sub_example" : RatioResult (12 , 2 ),
149
+ "sub_example.example3" : RatioResult (13 , 3 ),
150
+ }
151
+ assert tuple (capture .get ().splitlines ()) == tuple (
152
+ f"Could not run mutation testing for { module } ."
153
+ for module in (
154
+ "example1" ,
155
+ "example2" ,
156
+ "sub_example" ,
157
+ "sub_example.example3" ,
158
+ )
159
+ )
160
+
161
+ assert run_command_mock .call_args_list == [
162
+ * _cr_calls (config , "example1" , skip_exec = True ),
163
+ * _cr_calls (config , "example2" , skip_exec = True ),
164
+ * _cr_calls (config , "sub_example" , skip_exec = True ),
165
+ * _cr_calls (config , "sub_example.example3" , skip_exec = True ),
166
+ ]
167
+
168
+
75
169
def test_gather_results_not_started () -> None :
76
170
with mock .patch (
77
171
"python_tool_competition_2024.calculation.mutation_calculator.cosmic_ray_calculator.run_command"
@@ -107,16 +201,28 @@ def test_gather_results_not_completed() -> None:
107
201
)
108
202
109
203
110
- def _cr_calls (config : Config , target : str ) -> tuple [mock ._Call , ...]:
204
+ def _cr_calls (
205
+ config : Config , target : str , * , skip_exec : bool = False
206
+ ) -> tuple [mock ._Call , ...]:
111
207
cr_dir = config .results_dir / "cosmic_ray"
112
208
config_file = cr_dir / f"{ target } .toml"
113
209
db_file = cr_dir / f"{ target } .sqlite"
114
- return (
210
+ calls : tuple [ mock . _Call , ...] = (
115
211
mock .call (config , "cosmic-ray" , "init" , str (config_file ), str (db_file )),
116
- mock .call (config , "cosmic-ray" , "baseline" , str (config_file )),
117
- mock .call (config , "cosmic-ray" , "exec" , str (config_file ), str (db_file )),
118
- mock .call (config , "cr-report" , str (db_file ), capture = True ),
212
+ mock .call (
213
+ config ,
214
+ "cosmic-ray" ,
215
+ "baseline" ,
216
+ str (config_file ),
217
+ show_output_on_error = False ,
218
+ ),
119
219
)
220
+ if not skip_exec :
221
+ calls = (
222
+ * calls ,
223
+ mock .call (config , "cosmic-ray" , "exec" , str (config_file ), str (db_file )),
224
+ )
225
+ return (* calls , mock .call (config , "cr-report" , str (db_file ), capture = True ))
120
226
121
227
122
228
def _cr_config (target : Path , test_file : Path | None ) -> str :
@@ -136,11 +242,14 @@ def _cr_config(target: Path, test_file: Path | None) -> str:
136
242
137
243
138
244
class _OutputCounter :
139
- def __init__ (self ) -> None :
245
+ def __init__ (self , * , fail_baseline : bool = False ) -> None :
140
246
self ._total_count = 9
141
247
self ._successful_count = - 1
248
+ self ._fail_baseline = fail_baseline
142
249
143
250
def __call__ (self , _config : Config , * args : str , ** _kwargs : object ) -> str :
251
+ if self ._fail_baseline and args [0 :2 ] == ("cosmic-ray" , "baseline" ):
252
+ raise CommandFailedError (args )
144
253
if args [0 ] != "cr-report" :
145
254
return ""
146
255
self ._total_count += 1
0 commit comments