Skip to content

Commit d28694f

Browse files
committed
more tests for refinement and rewinds
1 parent 5ca5492 commit d28694f

8 files changed

Lines changed: 160 additions & 9 deletions

atest/resources/birthday_cards_flat.resource

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ ${person A} passes the birthday card ${back/on} to ${person B}
6060
Log Thank you ${person A}, I'll be sure to put my name on here.
6161
Set suite variable ${has_card} ${person B}
6262

63-
${person} refuses to write their name on the birthday card
63+
${person} writes their name in invisible ink on the birthday card
6464
[Documentation] *model info*
6565
... :IN: birthday_card
6666
... :OUT: birthday_card

atest/robotMBT tests/05__repeating_scenarios/02__repetition_with_identity_bogey.robot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ Someone writes their name on the card
1919
when Someone writes their name on the birthday card
2020
then the birthday card has 'Someone' written on it
2121

22-
Refusing to share the birthday card
22+
Signing the card in invisible ink
2323
Given there is a birthday card
2424
and the birthday card has 'Someone' written on it
25-
when Johan refuses to write their name on the birthday card
25+
when Johan writes their name in invisible ink on the birthday card
2626
then the birthday card has 'Someone' written on it
2727
but the birthday card does not have 'Johan' written on it
2828

atest/robotMBT tests/05__repeating_scenarios/09__impossible_trace.robot

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ Buying a card
1111
When someone buys a birthday card
1212
then there is a blank birthday card available
1313

14-
Refusing to sign the birthday card
14+
Signing the card in invisible ink
1515
Given there is a birthday card
16-
when everybody refuses to write their name on the birthday card
16+
when everybody writes their name in invisible ink on the birthday card
1717
then the birthday card has 0 names written on it
1818

1919
At least 42 people can write their name on the card
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
*** Settings ***
2+
Documentation This suite confirms that a scenario that can be inserted at the place
3+
... of refinement based on its entry conditions, but afterwards does not
4+
... satisfy the high-level scenario's exit conditions, is rejected.
5+
Suite Setup Expect failing suite processing
6+
Resource ../../resources/birthday_cards_flat.resource
7+
Library robotmbt
8+
9+
10+
*** Test Cases ***
11+
Buying a card
12+
When someone buys a birthday card
13+
then there is a blank birthday card available
14+
15+
high-level scenario
16+
Given there is a birthday card
17+
when Two people write their name on the birthday card
18+
then the birthday card has 2 names written on it
19+
20+
low-level scenario
21+
Given there is a birthday card
22+
when Someone writes their name on the birthday card
23+
then the birthday card has 'Someone' written on it
24+
25+
26+
*** Keywords ***
27+
Two people write their name on the birthday card
28+
[Documentation]
29+
... *model info*
30+
... :IN: scenario.count = len(birthday_card.names)
31+
... :OUT: len(birthday_card.names) == scenario.count+2
32+
Skip when unreachable
33+
Length should be ${names} ${2}
34+
35+
Expect failing suite processing
36+
Run keyword and expect error Unable to compose* Treat this test suite Model-based
37+
Set suite variable ${expected_error_detected} ${True}
38+
39+
Skip when unreachable
40+
[Documentation]
41+
... If the scenario is inserted after proper detection of the expected error,
42+
... then this keyword causes the remainder of the scenario to be skipped and
43+
... the test passes. When inserted without detected error, the scenario will
44+
... fail.
45+
IF ${expected_error_detected}
46+
Pass execution Accepting intentionally unreachable scenario
47+
END
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
*** Settings ***
2+
Documentation This suite covers a special case where an incomplete rollback inside a
3+
... scenario which is split up for refinement, could cause two scenarios
4+
... to be inserted for a single refinement. To get into that situation the
5+
... high-level scenario has two steps that require refinement. The first
6+
... one only checks that a certain name is inserted, it does not check the
7+
... number of names. The second one checks that the total number of names
8+
... is three. This should be an unreachable situation, because refinements
9+
... are always a single scenario and each of the scenarios only inserts a
10+
... single name. If the rollback of the middle part (2.2 in the trace) was
11+
... incomplete, i.e. its rollback did not include the refinement scenario
12+
... as well, then inserting the second low-level scenario would satisfy
13+
... the first exit conditions and inserting another low-level scenario for
14+
... the second refinement would satisfy exit conditions for both steps and
15+
... incorrectly complete the suite.
16+
Suite Setup Expect failing suite processing
17+
Resource ../../resources/birthday_cards_flat.resource
18+
Library robotmbt
19+
20+
21+
*** Test Cases ***
22+
Buying a card
23+
When someone buys a birthday card
24+
then there is a blank birthday card available
25+
26+
high-level scenario
27+
Given there is a birthday card
28+
when The first person writes their name on the birthday card
29+
and Two more people write their name on the birthday card
30+
then the birthday card has 3 names written on it
31+
32+
low-level scenario A
33+
Given there is a birthday card
34+
and we are in refinement
35+
when Someone writes their name on the birthday card
36+
then the birthday card has 'Someone' written on it
37+
38+
low-level scenario B
39+
Given there is a birthday card
40+
and we are in refinement
41+
when Someone writes their name on the birthday card
42+
then the birthday card has 'Someone' written on it
43+
44+
low-level scenario C
45+
Given there is a birthday card
46+
and we are in refinement
47+
when Someone writes their name on the birthday card
48+
then the birthday card has 'Someone' written on it
49+
50+
51+
*** Keywords ***
52+
The first person writes their name on the birthday card
53+
[Documentation] *model info*
54+
... :IN: scenario.count = len(birthday_card.names)
55+
... :OUT: Someone in birthday_card.names
56+
Skip when unreachable
57+
Should Contain ${names} Someone
58+
59+
Two more people write their name on the birthday card
60+
[Documentation] *model info*
61+
... :IN: scenario.count
62+
... :OUT: len(birthday_card.names) == scenario.count+3
63+
Skip when unreachable
64+
Length should be ${names} ${2}
65+
66+
we are in refinement
67+
[Documentation] Helper to prevent lower-level scenarios from being valid
68+
... at the top-level. (Better for performance)
69+
... *model info*
70+
... :IN: scenario.count
71+
... :OUT: None
72+
No Operation
73+
74+
Expect failing suite processing
75+
Run keyword and expect error Unable to compose* Treat this test suite Model-based
76+
Set suite variable ${expected_error_detected} ${True}
77+
78+
Skip when unreachable
79+
[Documentation]
80+
... If the scenario is inserted after proper detection of the expected error,
81+
... then this keyword causes the remainder of the scenario to be skipped and
82+
... the test passes. When inserted without detected error, the scenario will
83+
... fail.
84+
IF ${expected_error_detected}
85+
Pass execution Accepting intentionally unreachable scenario
86+
END

robotmbt/suiteprocessors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def _handle_refinement_exit(self, inserted_refinement, tracestate):
218218
if not exit_conditions_processed:
219219
self._rewind(tracestate) # Reject insterted scenario. Even though it fits, it is not a refinement.
220220
logger.debug(f"Reconsidering scenario {inserted_refinement.src_id}, {inserted_refinement.name}, "
221-
f"did not meet refinement conditions: {exit_conditions}")
221+
f"did not meet refinement exit condition: {exit_conditions}")
222222
return
223223

224224
tail_inserted, remainder, new_model, extra_data = self._process_scenario(refinement_tail, tracestate.model)

robotmbt/tracestate.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ def push_partial_scenario(self, index, scenario, model, remainder=None):
139139
else:
140140
id = f"{index}.1"
141141
self._tried[-1].append(index)
142-
self._tried.append([])
143142
self._open_refinements.append(index)
143+
self._tried.append([])
144144
self._snapshots.append(TraceSnapShot(id, scenario, model, remainder, self.coverage_drought))
145145

146146
def can_rewind(self):
@@ -157,11 +157,10 @@ def rewind(self):
157157
self.rewind()
158158
return self.rewind()
159159

160+
self._tried.pop()
160161
if '.' not in id:
161-
self._tried.pop()
162162
self.c_pool[index] -= 1
163163
if id.endswith('.1'):
164-
self._tried.pop()
165164
self._open_refinements.pop()
166165
return self._snapshots[-1] if self._snapshots else None
167166

utest/test_tracestate.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,25 @@ def test_rewind_all_parts_of_completed_scenario_at_once(self):
401401
self.assertIs(ts.next_candidate(), None)
402402
self.assertIs(tail, None)
403403

404+
def test_tried_entries_after_rewind(self):
405+
ts = TraceState([1, 2, 10, 11, 12, 20, 21])
406+
ts.push_partial_scenario(1, 'part1', {})
407+
ts.reject_scenario(10)
408+
ts.reject_scenario(11)
409+
ts.confirm_full_scenario(2, 'two', {})
410+
ts.push_partial_scenario(1, 'part2', {})
411+
ts.reject_scenario(20)
412+
ts.reject_scenario(21)
413+
self.assertEqual(ts.tried, (20, 21))
414+
ts.rewind()
415+
self.assertEqual(ts.tried, ())
416+
ts.rewind()
417+
self.assertEqual(ts.tried, (10, 11, 2))
418+
ts.reject_scenario(12)
419+
self.assertEqual(ts.tried, (10, 11, 2, 12))
420+
ts.rewind()
421+
self.assertEqual(ts.tried, (1,))
422+
404423
def test_highest_part_after_first_part(self):
405424
ts = TraceState([1])
406425
ts.push_partial_scenario(1, 'part1', {})

0 commit comments

Comments
 (0)