randomtesting.py 4.18 KB
Newer Older
Michele's avatar
Michele committed
1
2
from .basetesting import AbstractTester
import random
3
import logging
Michele's avatar
Michele committed
4
5
6
7

# Random tester.
class RandomTester(AbstractTester):

8
    def __init__(self, teacher, limit=1000, expectedLength=20, logger=None):
Michele's avatar
Michele committed
9
10
        # The tester will run test using the teacher
        self._teacher = teacher
11
12
        self._expectedLength = expectedLength
        self._limit = limit
Michele's avatar
Michele committed
13

14
15
        self._logger = logger or logging.getLogger(__name__)

Michele's avatar
Michele committed
16
    # Search a counterexample to teacher ioco model using at most limit actions
17
    # provide an expectedLength
18
19
20
    def findCounterexample(self, model):
        self._teacher.reset()
        model.reset()
21
22
        ce = ()
        i = 0
23
24
        # in case of multiple inputs in a row, I need to keep track of them
        consecutiveInputs = ()
25
        while i <= self._limit:
26
27
28
            #choice to reset or not:
            #(roll dice with expectedLength faces, if 0
            # I reset, otherwise I continue with one more input or output)
29
            reset = random.sample(range(self._expectedLength),1)[0]
30
31
32
33
34
35
36
37
38
            if reset != 0:
                # do not Reset
                typeAction = random.sample(set(['input', 'output']),1)[0]
                if typeAction == 'input':
                    # provide an input
                    # do not assume input enabledness
                    input = random.sample(model.inputs(),1)[0]
                    ce = ce + (input,)
                    model.move(input) # should be deterministic
39
40
41
42

                    # add input to consecutiveInputs
                    consecutiveInputs = consecutiveInputs + (input,)
                    # and continue with next step
43
44
45
                    # providing input costs an action
                    i += 1
                else:
46
47
48
                    # process consecutiveInputs and get an output
                    output = self._processInputs(consecutiveInputs)
                    consecutiveInputs = ()
49
50
                    if output not in model.outputs():
                        self._logger.info("Found a counterexample after "
51
52
                                          + str(i) + " input actions.")

53
54
                        self._teacher.reset()
                        model.reset()
55
56
57
                        # return counterexample trace and output obtained by
                        # testing
                        return ce, output
58
59
                    else:
                        model.move(output)
60
                        ce = ce + (output,)
61
62
                    # waiting for outputs does not cost actions
            else:
63
64
65
66
67
68
                # check if some inputs needed to be processed
                output = self._processInputs(consecutiveInputs)
                consecutiveInputs = ()
                if output not in model.outputs():
                    self._logger.info("Found a counterexample after "
                                      + str(i) + " input actions.")
69

70
71
72
73
74
75
                    self._teacher.reset()
                    model.reset()
                    # return counterexample trace and output obtained by
                    # testing
                    return ce, output
                # reset
76
77
78
79
80
81
82
                self._teacher.reset()
                model.reset()
                ce = ()
                # resetting costs a action
                i += 1


83
        # reached limit, check if some inputs needed still to be processed.
84
85
        if consecutiveInputs != ():
            # TODO: check if something is needed here
86
            output = self._processInputs(consecutiveInputs)
87

88
89
90
91
92
93
94
            # anyway reset the teacher
            self._teacher.reset()

            if output not in model.outputs():
                self._logger.info("Found a counterexample after "
                                  + str(i) + " input actions.")
                return ce, output
95

96
        return None, None
97
98
99
100
101
102
103
104
105
106
107

    def _processInputs(self, consecutiveInputs):
        if consecutiveInputs != ():
            output = self._teacher.oneOutput(consecutiveInputs)
            if output == None:
                # SUT did not accept an input. Reset everything and
                # continue
                # TODO: handle noninputenabledness of SUT here!
                return None
            return output
        return self._teacher.output()