-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmetamorphic_tests.py
99 lines (89 loc) · 3.55 KB
/
metamorphic_tests.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import brotli
import glob
import pickle
from os.path import join
import cpmpy as cp
from cpmpy.expressions.python_builtins import any
from mutators import *
def lists_to_conjunction(cons):
# recursive...
return [any(lists_to_conjunction(c)) if is_any_list(c) else c for c in cons]
def metamorphic_test(dirname, solver, iters,fmodels,enb):
#list of mutators and the amount of constraints they accept.
mm_mutators = [xor_morph, and_morph, or_morph, implies_morph, not_morph,
negated_normal_morph,
linearize_constraint_morph,
flatten_morph,
only_numexpr_equality_morph,
normalized_numexpr_morph,
reify_rewrite_morph,
only_bv_implies_morph,
only_var_lhs_morph,
only_const_rhs_morph,
only_positive_bv_morph,
flat2cnf_morph,
toplevel_list_morph,
decompose_globals_morph,
add_solution,
semanticFusion]
# choose a random model
f = random.choice(fmodels)
originalmodel = f
with open(f, 'rb') as fpcl:
cons = pickle.loads(brotli.decompress(fpcl.read())).constraints
assert (len(cons)>0), f"{f} has no constraints"
# replace lists by conjunctions
cons = lists_to_conjunction(cons)
assert (len(cons)>0), f"{f} has no constraints after l2conj"
assert (cp.Model(cons).solve()), f"{f} is not sat"
mutators = []
for i in range(iters):
# choose a metamorphic mutation
m = random.choice(mm_mutators)
# an error can occur in the transformations, so even before the solve call.
# log function and arguments in that case
mutators += [m]
try:
cons += m(cons) # apply a metamorphic mutation
except MetamorphicError as exc:
enb += 1
function, argument, e = exc.args
filename = "internalfunctioncrash"+str(enb)+".pickle"
with open(filename, "wb") as ff:
pickle.dump([function, argument, originalmodel, e], file=ff) # log function and arguments that caused exception
print('IE', end='', flush=True)
return False # no need to solve model we didn't modify..
# enough mutations, time for solving
try:
model = cp.Model(cons)
sat = model.solve(solver=solver, time_limit=20)
if model.status().runtime > 15:
# timeout, skip
print('s', end='', flush=True)
return True
elif sat:
# has to be SAT...
print('.', end='', flush=True)
return True
else:
print('X', end='', flush=True)
#print('morphs: ', mutators)
except Exception as e:
print('E', end='', flush=True)
# if you got here, the model failed...
enb += 1
with open("lasterrormodel" + str(enb)+".pickle", "wb") as f:
pickle.dump([model, originalmodel, mutators], file=f)
return False
if __name__ == '__main__':
dirname = "models"
solver = "ortools"
iters = 5 # number of metamorphic mutations per model
sat = True
enb = 0
random.seed(0)
while enb < 10:
fmodels = glob.glob(join(dirname, "*.bt"))
sat = metamorphic_test(dirname, solver, iters, fmodels, enb)
if not sat:
enb += 1