@@ -27,9 +27,14 @@ class RandObjTestBase(unittest.TestCase):
27
27
Extend this class to create testcases.
28
28
'''
29
29
30
+ # Number of iterations to do per call to `randomize_and_check_result`.
30
31
ITERATIONS = 1000
32
+ # Global multiplier for test length, set via command line.
31
33
TEST_LENGTH_MULTIPLIER = 1
32
- EXPECT_FAILURE = False
34
+ # Expected exception when calling `get_randobj`.
35
+ EXPECTED_ERROR_INIT = None
36
+ # Expected exception when calling `randomize_and_check_result`.
37
+ EXPECTED_ERROR_RAND = None
33
38
34
39
def setUp (self ) -> None :
35
40
self .iterations = self .ITERATIONS * self .TEST_LENGTH_MULTIPLIER
@@ -111,8 +116,8 @@ def randomize_and_check_result(
111
116
Code to randomize a randobj and check its results against expected
112
117
results.
113
118
'''
114
- if self .EXPECT_FAILURE :
115
- self .assertRaises (RandomizationError , randobj .randomize )
119
+ if self .EXPECTED_ERROR_RAND is not None :
120
+ self .assertRaises (self . EXPECTED_ERROR_RAND , randobj .randomize )
116
121
else :
117
122
results = self .randomize_and_time (randobj , self .iterations )
118
123
assertListOfDictsEqual (self , expected_results , results , "Non-determinism detected, results were not equal" )
@@ -164,132 +169,145 @@ def test_randobj(self) -> None:
164
169
165
170
# Test with seed 0
166
171
r = random .Random (0 )
167
- randobj = self .get_randobj (r )
168
- # Take a copy of the randobj for use later
169
- randobj_copy = deepcopy (randobj )
170
- if self .EXPECT_FAILURE :
171
- self .assertRaises (RandomizationError , randobj .randomize )
172
+ if self .EXPECTED_ERROR_INIT is not None :
173
+ self .assertRaises (self .EXPECTED_ERROR_INIT , self .get_randobj , r )
172
174
else :
173
- results = self .randomize_and_time (randobj , self .iterations )
174
- self .check (results )
175
- if do_tmp_checks :
176
- # Check when applying temporary constraints
177
- tmp_results = self .randomize_and_time (randobj , self .iterations , tmp_constraints , tmp_values )
178
- self .tmp_check (tmp_results )
179
- # Check temporary constraints don't break base randomization
180
- post_tmp_results = self .randomize_and_time (randobj , self .iterations )
181
- self .check (post_tmp_results )
182
- # Add temporary constraints permanently, see what happens
183
- if tmp_constraints is not None :
184
- for constr , vars in tmp_constraints :
185
- randobj .add_constraint (constr , vars )
186
- add_results = self .randomize_and_time (randobj , self .iterations , tmp_values = tmp_values )
187
- self .tmp_check (add_results )
175
+ randobj = self .get_randobj (r )
176
+ # Take a copy of the randobj for use later
177
+ randobj_copy = deepcopy (randobj )
178
+ if self .EXPECTED_ERROR_RAND is not None :
179
+ self .assertRaises (self .EXPECTED_ERROR_RAND , randobj .randomize )
180
+ else :
181
+ results = self .randomize_and_time (randobj , self .iterations )
182
+ self .check (results )
183
+ if do_tmp_checks :
184
+ # Check when applying temporary constraints
185
+ tmp_results = self .randomize_and_time (randobj , self .iterations , tmp_constraints , tmp_values )
186
+ self .tmp_check (tmp_results )
187
+ # Check temporary constraints don't break base randomization
188
+ post_tmp_results = self .randomize_and_time (randobj , self .iterations )
189
+ self .check (post_tmp_results )
190
+ # Add temporary constraints permanently, see what happens
191
+ if tmp_constraints is not None :
192
+ for constr , vars in tmp_constraints :
193
+ randobj .add_constraint (constr , vars )
194
+ add_results = self .randomize_and_time (randobj , self .iterations , tmp_values = tmp_values )
195
+ self .tmp_check (add_results )
188
196
189
197
# Test again with seed 0, ensuring results are the same.
190
198
r0 = random .Random (0 )
191
- randobj0 = self .get_randobj (r0 )
192
- self .randomize_and_check_result (
193
- randobj0 ,
194
- results ,
195
- do_tmp_checks ,
196
- tmp_constraints ,
197
- tmp_values ,
198
- tmp_results ,
199
- post_tmp_results ,
200
- add_results ,
201
- add_tmp_constraints = True ,
202
- )
199
+ if self .EXPECTED_ERROR_INIT is not None :
200
+ self .assertRaises (self .EXPECTED_ERROR_INIT , self .get_randobj , r0 )
201
+ else :
202
+ randobj0 = self .get_randobj (r0 )
203
+ self .randomize_and_check_result (
204
+ randobj0 ,
205
+ results ,
206
+ do_tmp_checks ,
207
+ tmp_constraints ,
208
+ tmp_values ,
209
+ tmp_results ,
210
+ post_tmp_results ,
211
+ add_results ,
212
+ add_tmp_constraints = True ,
213
+ )
203
214
204
215
# Also test the copy we took earlier.
205
- self .randomize_and_check_result (
206
- randobj_copy ,
207
- results ,
208
- do_tmp_checks ,
209
- tmp_constraints ,
210
- tmp_values ,
211
- tmp_results ,
212
- post_tmp_results ,
213
- add_results ,
214
- add_tmp_constraints = True ,
215
- )
216
+ if self .EXPECTED_ERROR_INIT is None :
217
+ self .randomize_and_check_result (
218
+ randobj_copy ,
219
+ results ,
220
+ do_tmp_checks ,
221
+ tmp_constraints ,
222
+ tmp_values ,
223
+ tmp_results ,
224
+ post_tmp_results ,
225
+ add_results ,
226
+ add_tmp_constraints = True ,
227
+ )
216
228
217
229
# Test with seed 1, ensuring results are different
218
230
r1 = random .Random (1 )
219
- randobj1 = self .get_randobj (r1 )
220
- if self .EXPECT_FAILURE :
221
- self .assertRaises (RandomizationError , randobj1 .randomize )
231
+ if self .EXPECTED_ERROR_INIT is not None :
232
+ self .assertRaises (self .EXPECTED_ERROR_INIT , self .get_randobj , r1 )
222
233
else :
223
- results1 = self .randomize_and_time (randobj1 , self .iterations )
224
- self .check (results1 )
225
- self .assertNotEqual (results , results1 , "Results were the same for two different seeds, check testcase." )
226
- if do_tmp_checks :
227
- # Check results are also different when applying temporary constraints
228
- tmp_results1 = self .randomize_and_time (randobj1 , self .iterations , tmp_constraints , tmp_values )
229
- self .tmp_check (tmp_results1 )
230
- self .assertNotEqual (tmp_results , tmp_results1 ,
231
- "Results were the same for two different seeds, check testcase." )
234
+ randobj1 = self .get_randobj (r1 )
235
+ if self .EXPECTED_ERROR_RAND is not None :
236
+ self .assertRaises (self .EXPECTED_ERROR_RAND , randobj1 .randomize )
237
+ else :
238
+ results1 = self .randomize_and_time (randobj1 , self .iterations )
239
+ self .check (results1 )
240
+ self .assertNotEqual (results , results1 , "Results were the same for two different seeds, check testcase." )
241
+ if do_tmp_checks :
242
+ # Check results are also different when applying temporary constraints
243
+ tmp_results1 = self .randomize_and_time (randobj1 , self .iterations , tmp_constraints , tmp_values )
244
+ self .tmp_check (tmp_results1 )
245
+ self .assertNotEqual (tmp_results , tmp_results1 ,
246
+ "Results were the same for two different seeds, check testcase." )
232
247
233
248
# Test using global seeding, ensuring results are the same
234
249
# Don't add temp constraints this time, so that we can test this object again.
235
250
random .seed (0 )
236
- randobj0_global = self .get_randobj ()
237
- self .randomize_and_check_result (
238
- randobj0_global ,
239
- results ,
240
- do_tmp_checks ,
241
- tmp_constraints ,
242
- tmp_values ,
243
- tmp_results ,
244
- post_tmp_results ,
245
- add_results ,
246
- add_tmp_constraints = False ,
247
- )
251
+ if self .EXPECTED_ERROR_INIT is not None :
252
+ self .assertRaises (self .EXPECTED_ERROR_INIT , self .get_randobj )
253
+ else :
254
+ randobj0_global = self .get_randobj ()
255
+ self .randomize_and_check_result (
256
+ randobj0_global ,
257
+ results ,
258
+ do_tmp_checks ,
259
+ tmp_constraints ,
260
+ tmp_values ,
261
+ tmp_results ,
262
+ post_tmp_results ,
263
+ add_results ,
264
+ add_tmp_constraints = False ,
265
+ )
248
266
249
- # Re-test the the globally-seeded object
250
- # Must re-seed the global random module to ensure repeatability.
251
- random .seed (0 )
252
- self .randomize_and_check_result (
253
- randobj0_global ,
254
- results ,
255
- do_tmp_checks ,
256
- tmp_constraints ,
257
- tmp_values ,
258
- tmp_results ,
259
- post_tmp_results ,
260
- add_results ,
261
- add_tmp_constraints = True ,
262
- )
267
+ # Re-test the the globally-seeded object
268
+ # Must re-seed the global random module to ensure repeatability.
269
+ random .seed (0 )
270
+ self .randomize_and_check_result (
271
+ randobj0_global ,
272
+ results ,
273
+ do_tmp_checks ,
274
+ tmp_constraints ,
275
+ tmp_values ,
276
+ tmp_results ,
277
+ post_tmp_results ,
278
+ add_results ,
279
+ add_tmp_constraints = True ,
280
+ )
263
281
264
- # TODO: Fix interaction between global random module and deepcopy.
265
- # Details:
266
- # There is an issue around copying an object that relies on the
267
- # global random object - the state of any copied object is tied to
268
- # its original.
269
- # Having spent a lot of time debugging this issue, it is still very
270
- # difficult to understand.
271
- # Each individual copied RandObj instance points to a new random.Random
272
- # instance, which shares state with the global module. It appears then
273
- # in some instances that the object uses the global value in the random
274
- # module, and in others it uses the copied one, meaning the state
275
- # diverges.
276
- # Right now, all I can conclude is it would take a lot of work to
277
- # fully debug it, and it can be worked around by passing objects a
278
- # seeded random.Random if the user desires reproducible objects.
282
+ # TODO: Fix interaction between global random module and deepcopy.
283
+ # Details:
284
+ # There is an issue around copying an object that relies on the
285
+ # global random object - the state of any copied object is tied to
286
+ # its original.
287
+ # Having spent a lot of time debugging this issue, it is still very
288
+ # difficult to understand.
289
+ # Each individual copied RandObj instance points to a new random.Random
290
+ # instance, which shares state with the global module. It appears then
291
+ # in some instances that the object uses the global value in the random
292
+ # module, and in others it uses the copied one, meaning the state
293
+ # diverges.
294
+ # Right now, all I can conclude is it would take a lot of work to
295
+ # fully debug it, and it can be worked around by passing objects a
296
+ # seeded random.Random if the user desires reproducible objects.
279
297
280
- # TODO: Make testing of copy more thorough when above issue fixed.
281
- # Take a copy, to show that we can. Its behaviour can't be guaranteed
282
- # to be deterministic w.r.t. randobj0_global due to issues around
283
- # deepcopy interacting with the global random module.
284
- # So, just test it can randomize.
285
- randobj0_global_copy = deepcopy (randobj0_global )
286
- if self .EXPECT_FAILURE :
287
- self .assertRaises (RandomizationError , randobj0_global_copy .randomize )
288
- else :
289
- # Don't check results. Checks may fail due to the interaction
290
- # between deepcopy and global random. E.g. if we check that temp
291
- # constraints are not followed when not supplied, they may
292
- # be due to the interaction between random and deepcopy.
293
- # This just ensures it doesn't crash.
294
- self .randomize_and_time (randobj0_global_copy , self .iterations )
295
- self .randomize_and_time (randobj0_global_copy , self .iterations , tmp_constraints , tmp_values )
298
+ # TODO: Make testing of copy more thorough when above issue fixed.
299
+ # Take a copy, to show that we can. Its behaviour can't be guaranteed
300
+ # to be deterministic w.r.t. randobj0_global due to issues around
301
+ # deepcopy interacting with the global random module.
302
+ # So, just test it can randomize.
303
+ randobj0_global_copy = deepcopy (randobj0_global )
304
+ if self .EXPECTED_ERROR_RAND is not None :
305
+ self .assertRaises (self . EXPECTED_ERROR_RAND , randobj0_global_copy .randomize )
306
+ else :
307
+ # Don't check results. Checks may fail due to the interaction
308
+ # between deepcopy and global random. E.g. if we check that temp
309
+ # constraints are not followed when not supplied, they may
310
+ # be due to the interaction between random and deepcopy.
311
+ # This just ensures it doesn't crash.
312
+ self .randomize_and_time (randobj0_global_copy , self .iterations )
313
+ self .randomize_and_time (randobj0_global_copy , self .iterations , tmp_constraints , tmp_values )
0 commit comments