@@ -20,7 +20,10 @@ def __init__(self, alphabet: list, sul: SUL, k: int = 2, method='random',
2020 max_path_len : int = 50 ,
2121 max_number_of_steps : int = 0 ,
2222 optimize : str = 'steps' ,
23- random_walk_len = 10 ):
23+ random_walk_len = 10 ,
24+ num_test_lower_bound = None ,
25+ num_test_upper_bound = None ,
26+ ):
2427 """
2528 Args:
2629
@@ -33,6 +36,8 @@ def __init__(self, alphabet: list, sul: SUL, k: int = 2, method='random',
3336 max_number_of_steps: maximum number of steps that will be executed on the SUL (0 = no limit)
3437 optimize: minimize either the number of 'steps' or 'queries' that are executed
3538 random_walk_len: the number of steps that are added by 'prefix' generated paths
39+ num_test_lower_bound= either None or number a minimum number of test-cases to be performed in each testing round
40+ num_test_upper_bound= either None or number a maximum number of test-cases to be performed in each testing round
3641
3742 """
3843 super ().__init__ (alphabet , sul )
@@ -48,26 +53,62 @@ def __init__(self, alphabet: list, sul: SUL, k: int = 2, method='random',
4853 self .optimize = optimize
4954 self .random_walk_len = random_walk_len
5055
56+ # to account for cases where number of test-cases generated by the oracle is either too big or too small
57+ # num_test_lower_bound does not affect k-way transition coverage, but limiting the upper bound might as not all
58+ # tests will be executed
59+ self .num_test_lower_bound = num_test_lower_bound
60+ self .num_test_upper_bound = num_test_upper_bound
61+
5162 self .cached_paths = list ()
5263
5364 def find_cex (self , hypothesis : Automaton ):
5465 if self .method == 'random' :
5566 paths = self .generate_random_paths (hypothesis ) + self .cached_paths
5667 self .cached_paths = self .greedy_set_cover (hypothesis , paths )
5768
58- print ('Num TC' , len (self .cached_paths ))
59- for path in self .cached_paths :
69+ # to account for lower bound
70+ additional_test_cases = []
71+ num_executed_tcs = 0
72+ if self .num_test_lower_bound is not None :
73+ while len (self .cached_paths ) + len (additional_test_cases ) < self .num_test_lower_bound :
74+ random_length = randint (self .k , self .max_path_len )
75+ steps = tuple (choices (self .alphabet , k = random_length ))
76+ additional_test_cases .append (self .create_path (hypothesis , steps ))
77+
78+ for path in list (self .cached_paths + additional_test_cases ):
79+ if self .num_test_upper_bound is not None and num_executed_tcs >= self .num_test_upper_bound :
80+ break
81+
6082 counter_example = self .check_path (hypothesis , path .steps )
83+ num_executed_tcs += 1
6184
6285 if counter_example is not None :
6386 return counter_example
6487
6588 elif self .method == 'prefix' :
89+ generated_paths = []
90+ # generate tcs with prefix coverage
6691 for steps in self .generate_prefix_steps (hypothesis ):
67- counter_example = self .check_path (hypothesis , steps )
92+ generated_paths .append (self .create_path (hypothesis , steps ))
93+
94+ if self .num_test_lower_bound is not None and len (generated_paths ) >= self .num_test_lower_bound :
95+ break
6896
97+ # add random paths if needed
98+ while self .num_test_lower_bound is not None and len (generated_paths ) < self .num_test_lower_bound :
99+ random_length = randint (self .k , self .max_path_len )
100+ steps = tuple (choices (self .alphabet , k = random_length ))
101+ generated_paths .append (self .create_path (hypothesis , steps ))
102+
103+ # limit upper bound
104+ if self .num_test_upper_bound is not None :
105+ generated_paths = generated_paths [:self .num_test_upper_bound ]
106+
107+ for path in generated_paths :
108+ counter_example = self .check_path (hypothesis , path .steps )
69109 if counter_example is not None :
70110 return counter_example
111+
71112 return None
72113
73114 def greedy_set_cover (self , hypothesis : Automaton , paths : list ):
@@ -90,7 +131,6 @@ def greedy_set_cover(self, hypothesis: Automaton, paths: list):
90131 paths = [self .create_path (hypothesis , steps ) for steps in self .generate_prefix_steps (hypothesis )]
91132
92133 if self .max_number_of_steps != 0 and step_count > self .max_number_of_steps :
93- print ("stop" )
94134 break
95135
96136 return result
0 commit comments