forked from jon-jacky/PyModel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTestSuite.py
118 lines (100 loc) · 3.98 KB
/
TestSuite.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Interface to a test suite module (one or more runs) used by ProductModelProgram
"""
from operator import concat
from .model import Model
from functools import reduce
class TestSuite(Model):
def __init__(self, module, exclude, include):
Model.__init__(self, module, exclude, include)
def post_init(self):
"""
Now that all modules have been imported and executed their __init__
do a postprocessing pass
to process metadata that might be affected by configuration modules
"""
# Do all of this work here rather than in __init__
# so it can include the effects of any pymodel config modules
# recognize PEP-8 style names (all lowercase) if present
if hasattr(self.module, 'testsuite'):
self.module.testSuite = self.module.testsuite
if hasattr(self.module, 'test_suite'):
self.module.testSuite = self.module.test_suite
if hasattr(self.module, 'actions'):
self.actions = list(self.module.actions) # copy, actions from cmd line
else:
self.actions = list(self.actions_in_suite()) # default, copy
Model.post_init(self) # uses self.actions
# Revise the test suite to account for excluded, included actions
self.test_suite = list()
for run in self.module.testSuite:
new_run = list() # list not tuple, must mutable
for action in run:
if action[0] in self.actions:
new_run.append(action)
else:
break # truncate the run before the excluded action
self.test_suite.append(new_run)
# prepare for first run
self.irun = 0 # index of current test run in test suite
self.pc = 0 # program counter
def actions_in_suite(self):
# there might be two or three items in action_tuple
return tuple(set(reduce(concat,[[action_tuple[0] for action_tuple in run]
for run in self.module.testSuite])))
def Accepting(self):
# In a test suite, the only accepting states are at ends of runs
# NB Here Accepting() is called *after* DoAction() that advances self.pc
length = len(self.test_suite[self.irun]) # number of tuples in run
return (self.pc == length)
def make_properties(self, accepting):
return { 'accepting': accepting, 'statefilter': True,
'stateinvariant': True }
def Properties(self):
return self.make_properties(self.Accepting())
def Reset(self): # needed by stepper
self.pc = 0
if self.irun < len(self.test_suite) - 1:
self.irun += 1
else:
raise StopIteration # no more runs in test suite
def ActionEnabled(self, a, args):
"""
action a with args is enabled in the current state
"""
step = self.test_suite[self.irun][self.pc]
action, arguments = step[0:2] # works whether or not step has result
return (a == action and args == arguments)
def EnabledTransitions(self, cleanup=False):
"""
Return list of all tuples for enabled actions. Here, there is just one.
(action, args, next state, next state is accepting state)
Next state is a list of two elements:the run number and step within the run
In a test suite, there is always just *one* next action, or *none*
Ignore cleanup, test suite should always end in accepting state.
"""
run = self.test_suite[self.irun]
length = len(run)
if self.pc < length:
step = run[self.pc]
action, args = step[0:2]
result = step[2] if len(step) > 2 else None # result is optional
next = self.pc + 1
accepting = (next == length)
return([(action, args, result, (self.irun,next),
self.make_properties(accepting))])
else:
return list() # test run finished, nothing enabled,
def DoAction(self, a, args):
step = self.test_suite[self.irun][self.pc]
result = step[2] if len(step) > 2 else None # result is optional
self.pc += 1
return result
def Current(self):
return (self.irun, self.pc)
def Restore(self, state):
"""
Restore state
"""
self.irun, self.pc = state
# GetNext not needed