Skip to content

Commit d1178c8

Browse files
will-keenimgtec-admin
authored andcommitted
Merge pull request #7 from imaginationtech/rand_len_tests
Add much more thorough testing for random length lists
2 parents a2e24de + 3a62b23 commit d1178c8

File tree

1 file changed

+269
-2
lines changed

1 file changed

+269
-2
lines changed

tests/features/rand_list.py

Lines changed: 269 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
Test random lists.
66
'''
77

8-
from random import Random
8+
from enum import auto, IntEnum
9+
from typing import Any, Dict, List
910

1011
from constrainedrandom import RandObj
1112
from constrainedrandom.utils import unique
@@ -339,6 +340,26 @@ def not_7(x):
339340
r.add_rand_var('listvar', bits=5, constraints=[not_7], rand_length='length')
340341
return r
341342

343+
def get_tmp_constraints(self):
344+
tmp_constrs = []
345+
def not_6(x):
346+
return x != 6
347+
tmp_constrs.append((not_6, ('listvar',)))
348+
tmp_constrs.append((not_6, ('length',)))
349+
def mul_3(x):
350+
return x % 3 == 0
351+
tmp_constrs.append((mul_3, ('length',)))
352+
return tmp_constrs
353+
354+
def tmp_check(self, results):
355+
self.check(results)
356+
for result in results:
357+
length = result['length']
358+
listvar = result['listvar']
359+
self.assertNotEqual(length, 6, "Temp constraint not respected")
360+
self.assertNotEqual(listvar, 6, "Temp constraint not respected")
361+
self.assertEqual(length % 3, 0, "Temp constraint not respected")
362+
342363
def check(self, results):
343364
nonzero_seen = False
344365
for result in results:
@@ -355,13 +376,22 @@ def check(self, results):
355376
self.assertTrue(nonzero_seen, "All values were zero")
356377

357378

379+
class RandSizeListValue(RandSizeList):
380+
'''
381+
Test a random sized list with temporary values.
382+
'''
383+
384+
def get_tmp_values(self):
385+
return {'length': 12}
386+
387+
358388
class RandSizeListConstrained(RandSizeList):
359389
'''
360390
Test a randomized list, with a random size.
361391
Add constriants between the length and another variable.
362392
'''
363393

364-
ITERATIONS = 1000
394+
ITERATIONS = 500
365395

366396
def get_randobj(self, *args):
367397
r = super().get_randobj(*args)
@@ -385,6 +415,12 @@ def check(self, results):
385415
self.assertEqual(length % 2, 1, "Length was even, should be odd")
386416

387417

418+
class RandSizeListConstrainedValue(RandSizeListValue, RandSizeListConstrained):
419+
'''
420+
Test a random sized list, with constraints, and with temporary values.
421+
'''
422+
423+
388424
class RandSizeListConstrainedMore(RandSizeListConstrained):
389425
'''
390426
Test a randomized list, with a random size.
@@ -407,3 +443,234 @@ def check(self, results):
407443
length = result['length']
408444
listvar = result['listvar']
409445
self.assertNotIn(length, listvar, "Length should not appear in list")
446+
447+
448+
class RandSizeListConstrainedMoreValue(RandSizeListValue, RandSizeListConstrained):
449+
'''
450+
Test a randomized list, with a random size.
451+
Add constriants between the length and other variables,
452+
and the length and the list.
453+
Test with temporary values.
454+
'''
455+
456+
457+
class RandSizeListConstrainedSparse(RandSizeListConstrained):
458+
'''
459+
Test a constrained randomized list with a random length,
460+
exercising the sparse solver.
461+
'''
462+
463+
def get_randobj(self, *args):
464+
r = super().get_randobj(*args)
465+
r.set_solver_mode(naive=False, sparse=True, thorough=False)
466+
return r
467+
468+
469+
class RandSizeListConstrainedSparseValue(RandSizeListValue, RandSizeListConstrainedSparse):
470+
'''
471+
Test a constrained randomized list with a random length,
472+
exercising the sparse solver, with temporary values.
473+
'''
474+
475+
476+
class RandSizeListConstrainedMoreSparse(RandSizeListConstrainedMore):
477+
'''
478+
Test a further constrained randomized list with a random length,
479+
exercising the sparse solver.
480+
'''
481+
482+
def get_randobj(self, *args):
483+
r = super().get_randobj(*args)
484+
r.set_solver_mode(naive=False, sparse=True, thorough=False)
485+
return r
486+
487+
488+
class RandSizeListConstrainedMoreSparseValue(RandSizeListValue, RandSizeListConstrainedMoreSparse):
489+
'''
490+
Test a further constrained randomized list with a random length,
491+
exercising the sparse solver, with temporary values.
492+
'''
493+
494+
495+
class RandSizeListConstrainedThorough(RandSizeListConstrained):
496+
'''
497+
Test a constrained randomized list with a random length,
498+
exercising the thorough solver.
499+
'''
500+
501+
ITERATIONS = 5
502+
503+
def get_randobj(self, *args):
504+
r = super().get_randobj(*args)
505+
r.set_solver_mode(naive=False, sparse=False, thorough=True)
506+
return r
507+
508+
509+
class RandSizeListConstrainedThoroughValue(RandSizeListValue, RandSizeListConstrainedThorough):
510+
'''
511+
Test a constrained randomized list with a random length,
512+
exercising the thorough solver, with temporary values.
513+
'''
514+
515+
516+
class RandSizeListConstrainedMoreThorough(RandSizeListConstrainedMore):
517+
'''
518+
Test a constrained randomized list with a random length,
519+
exercising the thorough solver.
520+
'''
521+
522+
ITERATIONS = 2
523+
524+
def get_randobj(self, *args):
525+
r = super().get_randobj(*args)
526+
r.set_solver_mode(naive=False, sparse=False, thorough=True)
527+
return r
528+
529+
530+
class RandSizeListConstrainedMoreThoroughValue(RandSizeListValue, RandSizeListConstrainedMoreThorough):
531+
'''
532+
Test a constrained randomized list with a random length,
533+
exercising the thorough solver.
534+
'''
535+
536+
537+
class RandSizeListHard(testutils.RandObjTestBase):
538+
'''
539+
Test a much more difficult problem with randomized-length lists.
540+
'''
541+
542+
ITERATIONS = 100
543+
544+
class RegEnum(IntEnum):
545+
546+
REG0 = 0
547+
REG1 = auto()
548+
REG2 = auto()
549+
REG3 = auto()
550+
REG4 = auto()
551+
REG5 = auto()
552+
REG6 = auto()
553+
REG7 = auto()
554+
555+
def get_randobj(self, *args):
556+
r = RandObj(*args)
557+
r.add_rand_var('shared_length', domain=range(8))
558+
def not_reg0(x):
559+
return x != self.RegEnum.REG0
560+
r.add_rand_var(
561+
'list1',
562+
domain=self.RegEnum,
563+
rand_length='shared_length',
564+
constraints=[not_reg0],
565+
list_constraints=[unique],
566+
)
567+
r.add_rand_var('list2', domain=range(32), rand_length='shared_length')
568+
def lists_dont_intersect(list1, list2):
569+
for x in list1:
570+
if x in list2:
571+
return False
572+
return True
573+
r.add_constraint(lists_dont_intersect, ('list1', 'list2'))
574+
return r
575+
576+
def get_tmp_constraints(self):
577+
return super().get_tmp_constraints()
578+
579+
def check(self, results):
580+
for idx, result in enumerate(results):
581+
list1 = result['list1']
582+
list2 = result['list2']
583+
shared_length = result['shared_length']
584+
self.assertIn(shared_length, range(8))
585+
self.assertEqual(len(list1), shared_length, f"{idx} List length was wrong")
586+
self.assertEqual(len(list2), shared_length, "List length was wrong")
587+
for idx, item in enumerate(list1):
588+
self.assertIn(item, self.RegEnum)
589+
other_elems = list1[0:idx] + list1[idx+1:]
590+
self.assertNotIn(item, other_elems, "List had repeated elements")
591+
for item in list2:
592+
self.assertNotIn(item, list1, "Lists were not disjoint")
593+
594+
595+
class RandSizeListVeryHard(RandSizeListHard):
596+
'''
597+
Test an extremely difficult problem with randomized-length lists.
598+
'''
599+
600+
ITERATIONS = 2
601+
602+
def get_randobj(self, *args):
603+
r = super().get_randobj(*args)
604+
def double_length(length, length2):
605+
return length2 == length * 2
606+
r.add_rand_var('other_length', domain=range(16))
607+
r.add_constraint(double_length, ('shared_length', 'other_length'))
608+
r.add_rand_var('list3', domain=range(32), rand_length='other_length', order=2)
609+
def composed_from_others(list1, list2, list3):
610+
for x in list3:
611+
if x not in list1 and x not in list2:
612+
return False
613+
return True
614+
r.add_constraint(composed_from_others, ('list1', 'list2', 'list3'))
615+
return r
616+
617+
def check(self, results):
618+
super().check(results)
619+
for result in results:
620+
list1 = result['list1']
621+
list2 = result['list2']
622+
list3 = result['list3']
623+
shared_length = result['shared_length']
624+
other_length = result['other_length']
625+
self.assertEqual(len(list3), shared_length*2, "List length was wrong")
626+
self.assertEqual(other_length, shared_length*2, "List length was wrong")
627+
for item in list3:
628+
self.assertIn(item, list1 + list2, "Item was not in other lists")
629+
630+
631+
class RandSizeListShort(testutils.RandObjTestBase):
632+
'''
633+
Test random lists and lengths with small domains, to
634+
use CSP.
635+
'''
636+
637+
def get_randobj(self, *args):
638+
r = RandObj(*args)
639+
r.add_rand_var('length1', domain=range(1, 4))
640+
r.add_rand_var('list1', domain=range(1, 4), rand_length='length1')
641+
def in_list(x, y):
642+
return x in y
643+
r.add_rand_var('length2', domain=range(1, 4))
644+
r.add_constraint(in_list, ('length2', 'list1'))
645+
r.add_rand_var('list2', domain=range(1, 4), rand_length='length2')
646+
return r
647+
648+
def check(self, results):
649+
for result in results:
650+
length1 = result['length1']
651+
list1 = result['list1']
652+
length2 = result['length2']
653+
list2 = result['list2']
654+
self.assertEqual(len(list1), length1, "List length was wrong")
655+
self.assertIn(length2, list1, "Length 2 must be in list 1")
656+
self.assertEqual(len(list2), length2, "List length was wrong")
657+
658+
659+
class RandSizeListShortSparse(RandSizeListShort):
660+
661+
ITERATIONS = 200
662+
663+
def get_randobj(self, *args):
664+
r = super().get_randobj(*args)
665+
r.set_solver_mode(naive=False, sparse=True, thorough=False)
666+
return r
667+
668+
669+
class RandSizeListShortThorough(RandSizeListShort):
670+
671+
ITERATIONS = 50
672+
673+
def get_randobj(self, *args):
674+
r = super().get_randobj(*args)
675+
r.set_solver_mode(naive=False, sparse=False, thorough=True)
676+
return r

0 commit comments

Comments
 (0)