mirror of
https://github.com/esphome/esphome.git
synced 2025-11-17 15:26:01 +00:00
Add action continuation tests (#11674)
This commit is contained in:
@@ -87,3 +87,99 @@ api:
|
|||||||
- float_arr.size()
|
- float_arr.size()
|
||||||
- string_arr[0].c_str()
|
- string_arr[0].c_str()
|
||||||
- string_arr.size()
|
- string_arr.size()
|
||||||
|
# Test ContinuationAction (IfAction with then/else branches)
|
||||||
|
- action: test_if_action
|
||||||
|
variables:
|
||||||
|
condition: bool
|
||||||
|
value: int
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return condition;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Condition true, value: %d"
|
||||||
|
args: ['value']
|
||||||
|
else:
|
||||||
|
- logger.log:
|
||||||
|
format: "Condition false, value: %d"
|
||||||
|
args: ['value']
|
||||||
|
- logger.log: "After if/else"
|
||||||
|
# Test nested IfAction (multiple ContinuationAction instances)
|
||||||
|
- action: test_nested_if
|
||||||
|
variables:
|
||||||
|
outer: bool
|
||||||
|
inner: bool
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return outer;'
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return inner;'
|
||||||
|
then:
|
||||||
|
- logger.log: "Both true"
|
||||||
|
else:
|
||||||
|
- logger.log: "Outer true, inner false"
|
||||||
|
else:
|
||||||
|
- logger.log: "Outer false"
|
||||||
|
- logger.log: "After nested if"
|
||||||
|
# Test WhileLoopContinuation (WhileAction)
|
||||||
|
- action: test_while_action
|
||||||
|
variables:
|
||||||
|
max_count: int
|
||||||
|
then:
|
||||||
|
- lambda: 'id(api_continuation_test_counter) = 0;'
|
||||||
|
- while:
|
||||||
|
condition:
|
||||||
|
lambda: 'return id(api_continuation_test_counter) < max_count;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "While loop iteration: %d"
|
||||||
|
args: ['id(api_continuation_test_counter)']
|
||||||
|
- lambda: 'id(api_continuation_test_counter)++;'
|
||||||
|
- logger.log: "After while loop"
|
||||||
|
# Test RepeatLoopContinuation (RepeatAction)
|
||||||
|
- action: test_repeat_action
|
||||||
|
variables:
|
||||||
|
count: int
|
||||||
|
then:
|
||||||
|
- repeat:
|
||||||
|
count: !lambda 'return count;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Repeat iteration: %d"
|
||||||
|
args: ['iteration']
|
||||||
|
- logger.log: "After repeat"
|
||||||
|
# Test combined continuations (if + while + repeat)
|
||||||
|
- action: test_combined_continuations
|
||||||
|
variables:
|
||||||
|
do_loop: bool
|
||||||
|
loop_count: int
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return do_loop;'
|
||||||
|
then:
|
||||||
|
- repeat:
|
||||||
|
count: !lambda 'return loop_count;'
|
||||||
|
then:
|
||||||
|
- lambda: 'id(api_continuation_test_counter) = iteration;'
|
||||||
|
- while:
|
||||||
|
condition:
|
||||||
|
lambda: 'return id(api_continuation_test_counter) > 0;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Combined: repeat=%d, while=%d"
|
||||||
|
args: ['iteration', 'id(api_continuation_test_counter)']
|
||||||
|
- lambda: 'id(api_continuation_test_counter)--;'
|
||||||
|
else:
|
||||||
|
- logger.log: "Skipped loops"
|
||||||
|
- logger.log: "After combined test"
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- id: api_continuation_test_counter
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|||||||
174
tests/integration/fixtures/continuation_actions.yaml
Normal file
174
tests/integration/fixtures/continuation_actions.yaml
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
esphome:
|
||||||
|
name: test-continuation-actions
|
||||||
|
|
||||||
|
host:
|
||||||
|
|
||||||
|
api:
|
||||||
|
actions:
|
||||||
|
# Test 1: IfAction with ContinuationAction (then/else branches)
|
||||||
|
- action: test_if_action
|
||||||
|
variables:
|
||||||
|
condition: bool
|
||||||
|
value: int
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Test if: condition=%s, value=%d"
|
||||||
|
args: ['YESNO(condition)', 'value']
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return condition;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "if-then executed: value=%d"
|
||||||
|
args: ['value']
|
||||||
|
else:
|
||||||
|
- logger.log:
|
||||||
|
format: "if-else executed: value=%d"
|
||||||
|
args: ['value']
|
||||||
|
- logger.log: "if completed"
|
||||||
|
|
||||||
|
# Test 2: Nested IfAction (multiple ContinuationAction instances)
|
||||||
|
- action: test_nested_if
|
||||||
|
variables:
|
||||||
|
outer: bool
|
||||||
|
inner: bool
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Test nested if: outer=%s, inner=%s"
|
||||||
|
args: ['YESNO(outer)', 'YESNO(inner)']
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return outer;'
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return inner;'
|
||||||
|
then:
|
||||||
|
- logger.log: "nested-both-true"
|
||||||
|
else:
|
||||||
|
- logger.log: "nested-outer-true-inner-false"
|
||||||
|
else:
|
||||||
|
- logger.log: "nested-outer-false"
|
||||||
|
- logger.log: "nested if completed"
|
||||||
|
|
||||||
|
# Test 3: WhileAction with WhileLoopContinuation
|
||||||
|
- action: test_while_action
|
||||||
|
variables:
|
||||||
|
max_count: int
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Test while: max_count=%d"
|
||||||
|
args: ['max_count']
|
||||||
|
- globals.set:
|
||||||
|
id: continuation_test_counter
|
||||||
|
value: !lambda 'return 0;'
|
||||||
|
- while:
|
||||||
|
condition:
|
||||||
|
lambda: 'return id(continuation_test_counter) < max_count;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "while-iteration-%d"
|
||||||
|
args: ['id(continuation_test_counter)']
|
||||||
|
- globals.set:
|
||||||
|
id: continuation_test_counter
|
||||||
|
value: !lambda 'return id(continuation_test_counter) + 1;'
|
||||||
|
- logger.log: "while completed"
|
||||||
|
|
||||||
|
# Test 4: RepeatAction with RepeatLoopContinuation
|
||||||
|
- action: test_repeat_action
|
||||||
|
variables:
|
||||||
|
count: int
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Test repeat: count=%d"
|
||||||
|
args: ['count']
|
||||||
|
- repeat:
|
||||||
|
count: !lambda 'return count;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "repeat-iteration-%d"
|
||||||
|
args: ['iteration']
|
||||||
|
- logger.log: "repeat completed"
|
||||||
|
|
||||||
|
# Test 5: Combined continuations (if + while + repeat)
|
||||||
|
- action: test_combined
|
||||||
|
variables:
|
||||||
|
do_loop: bool
|
||||||
|
loop_count: int
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Test combined: do_loop=%s, loop_count=%d"
|
||||||
|
args: ['YESNO(do_loop)', 'loop_count']
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return do_loop;'
|
||||||
|
then:
|
||||||
|
- repeat:
|
||||||
|
count: !lambda 'return loop_count;'
|
||||||
|
then:
|
||||||
|
- globals.set:
|
||||||
|
id: continuation_test_counter
|
||||||
|
value: !lambda 'return iteration;'
|
||||||
|
- while:
|
||||||
|
condition:
|
||||||
|
lambda: 'return id(continuation_test_counter) > 0;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "combined-repeat%d-while%d"
|
||||||
|
args: ['iteration', 'id(continuation_test_counter)']
|
||||||
|
- globals.set:
|
||||||
|
id: continuation_test_counter
|
||||||
|
value: !lambda 'return id(continuation_test_counter) - 1;'
|
||||||
|
else:
|
||||||
|
- logger.log: "combined-skipped"
|
||||||
|
- logger.log: "combined completed"
|
||||||
|
|
||||||
|
# Test 6: Rapid triggers to verify memory efficiency
|
||||||
|
- action: test_rapid_if
|
||||||
|
then:
|
||||||
|
- logger.log: "=== Rapid if test start ==="
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: rapid_sensor
|
||||||
|
state: 1
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: rapid_sensor
|
||||||
|
state: 2
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: rapid_sensor
|
||||||
|
state: 3
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: rapid_sensor
|
||||||
|
state: 4
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: rapid_sensor
|
||||||
|
state: 5
|
||||||
|
- logger.log: "=== Rapid if test published 5 values ==="
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- id: continuation_test_counter
|
||||||
|
type: int
|
||||||
|
restore_value: false
|
||||||
|
initial_value: '0'
|
||||||
|
|
||||||
|
# Sensor to test rapid automation triggers with if/else (ContinuationAction)
|
||||||
|
sensor:
|
||||||
|
- platform: template
|
||||||
|
id: rapid_sensor
|
||||||
|
on_value:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return x > 2;'
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "rapid-if-then: value=%d"
|
||||||
|
args: ['(int)x']
|
||||||
|
else:
|
||||||
|
- logger.log:
|
||||||
|
format: "rapid-if-else: value=%d"
|
||||||
|
args: ['(int)x']
|
||||||
|
- logger.log:
|
||||||
|
format: "rapid-if-completed: value=%d"
|
||||||
|
args: ['(int)x']
|
||||||
235
tests/integration/test_continuation_actions.py
Normal file
235
tests/integration/test_continuation_actions.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
"""Test continuation actions (ContinuationAction, WhileLoopContinuation, RepeatLoopContinuation)."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_continuation_actions(
|
||||||
|
yaml_config: str,
|
||||||
|
run_compiled: RunCompiledFunction,
|
||||||
|
api_client_connected: APIClientConnectedFactory,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Test that continuation actions work correctly for if/while/repeat.
|
||||||
|
|
||||||
|
These continuation classes replace LambdaAction with simple parent pointers,
|
||||||
|
saving 32-36 bytes per instance and eliminating std::function overhead.
|
||||||
|
"""
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
# Track test completions
|
||||||
|
test_results = {
|
||||||
|
"if_then": False,
|
||||||
|
"if_else": False,
|
||||||
|
"if_complete": False,
|
||||||
|
"nested_both_true": False,
|
||||||
|
"nested_outer_true_inner_false": False,
|
||||||
|
"nested_outer_false": False,
|
||||||
|
"nested_complete": False,
|
||||||
|
"while_iterations": 0,
|
||||||
|
"while_complete": False,
|
||||||
|
"repeat_iterations": 0,
|
||||||
|
"repeat_complete": False,
|
||||||
|
"combined_iterations": 0,
|
||||||
|
"combined_complete": False,
|
||||||
|
"rapid_then": 0,
|
||||||
|
"rapid_else": 0,
|
||||||
|
"rapid_complete": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Patterns for log messages
|
||||||
|
if_then_pattern = re.compile(r"if-then executed: value=(\d+)")
|
||||||
|
if_else_pattern = re.compile(r"if-else executed: value=(\d+)")
|
||||||
|
if_complete_pattern = re.compile(r"if completed")
|
||||||
|
nested_both_true_pattern = re.compile(r"nested-both-true")
|
||||||
|
nested_outer_true_inner_false_pattern = re.compile(r"nested-outer-true-inner-false")
|
||||||
|
nested_outer_false_pattern = re.compile(r"nested-outer-false")
|
||||||
|
nested_complete_pattern = re.compile(r"nested if completed")
|
||||||
|
while_iteration_pattern = re.compile(r"while-iteration-(\d+)")
|
||||||
|
while_complete_pattern = re.compile(r"while completed")
|
||||||
|
repeat_iteration_pattern = re.compile(r"repeat-iteration-(\d+)")
|
||||||
|
repeat_complete_pattern = re.compile(r"repeat completed")
|
||||||
|
combined_pattern = re.compile(r"combined-repeat(\d+)-while(\d+)")
|
||||||
|
combined_complete_pattern = re.compile(r"combined completed")
|
||||||
|
rapid_then_pattern = re.compile(r"rapid-if-then: value=(\d+)")
|
||||||
|
rapid_else_pattern = re.compile(r"rapid-if-else: value=(\d+)")
|
||||||
|
rapid_complete_pattern = re.compile(r"rapid-if-completed: value=(\d+)")
|
||||||
|
|
||||||
|
# Test completion futures
|
||||||
|
test1_complete = loop.create_future() # if action
|
||||||
|
test2_complete = loop.create_future() # nested if
|
||||||
|
test3_complete = loop.create_future() # while
|
||||||
|
test4_complete = loop.create_future() # repeat
|
||||||
|
test5_complete = loop.create_future() # combined
|
||||||
|
test6_complete = loop.create_future() # rapid
|
||||||
|
|
||||||
|
def check_output(line: str) -> None:
|
||||||
|
"""Check log output for test messages."""
|
||||||
|
# Test 1: IfAction
|
||||||
|
if if_then_pattern.search(line):
|
||||||
|
test_results["if_then"] = True
|
||||||
|
if if_else_pattern.search(line):
|
||||||
|
test_results["if_else"] = True
|
||||||
|
if if_complete_pattern.search(line):
|
||||||
|
test_results["if_complete"] = True
|
||||||
|
if not test1_complete.done():
|
||||||
|
test1_complete.set_result(True)
|
||||||
|
|
||||||
|
# Test 2: Nested IfAction
|
||||||
|
if nested_both_true_pattern.search(line):
|
||||||
|
test_results["nested_both_true"] = True
|
||||||
|
if nested_outer_true_inner_false_pattern.search(line):
|
||||||
|
test_results["nested_outer_true_inner_false"] = True
|
||||||
|
if nested_outer_false_pattern.search(line):
|
||||||
|
test_results["nested_outer_false"] = True
|
||||||
|
if nested_complete_pattern.search(line):
|
||||||
|
test_results["nested_complete"] = True
|
||||||
|
if not test2_complete.done():
|
||||||
|
test2_complete.set_result(True)
|
||||||
|
|
||||||
|
# Test 3: WhileAction
|
||||||
|
if match := while_iteration_pattern.search(line):
|
||||||
|
test_results["while_iterations"] = max(
|
||||||
|
test_results["while_iterations"], int(match.group(1)) + 1
|
||||||
|
)
|
||||||
|
if while_complete_pattern.search(line):
|
||||||
|
test_results["while_complete"] = True
|
||||||
|
if not test3_complete.done():
|
||||||
|
test3_complete.set_result(True)
|
||||||
|
|
||||||
|
# Test 4: RepeatAction
|
||||||
|
if match := repeat_iteration_pattern.search(line):
|
||||||
|
test_results["repeat_iterations"] = max(
|
||||||
|
test_results["repeat_iterations"], int(match.group(1)) + 1
|
||||||
|
)
|
||||||
|
if repeat_complete_pattern.search(line):
|
||||||
|
test_results["repeat_complete"] = True
|
||||||
|
if not test4_complete.done():
|
||||||
|
test4_complete.set_result(True)
|
||||||
|
|
||||||
|
# Test 5: Combined
|
||||||
|
if combined_pattern.search(line):
|
||||||
|
test_results["combined_iterations"] += 1
|
||||||
|
if combined_complete_pattern.search(line):
|
||||||
|
test_results["combined_complete"] = True
|
||||||
|
if not test5_complete.done():
|
||||||
|
test5_complete.set_result(True)
|
||||||
|
|
||||||
|
# Test 6: Rapid triggers
|
||||||
|
if rapid_then_pattern.search(line):
|
||||||
|
test_results["rapid_then"] += 1
|
||||||
|
if rapid_else_pattern.search(line):
|
||||||
|
test_results["rapid_else"] += 1
|
||||||
|
if rapid_complete_pattern.search(line):
|
||||||
|
test_results["rapid_complete"] += 1
|
||||||
|
if test_results["rapid_complete"] == 5 and not test6_complete.done():
|
||||||
|
test6_complete.set_result(True)
|
||||||
|
|
||||||
|
async with (
|
||||||
|
run_compiled(yaml_config, line_callback=check_output),
|
||||||
|
api_client_connected() as client,
|
||||||
|
):
|
||||||
|
# Get services
|
||||||
|
_, services = await client.list_entities_services()
|
||||||
|
|
||||||
|
# Test 1: IfAction with then branch
|
||||||
|
test_service = next((s for s in services if s.name == "test_if_action"), None)
|
||||||
|
assert test_service is not None, "test_if_action service not found"
|
||||||
|
client.execute_service(test_service, {"condition": True, "value": 42})
|
||||||
|
await asyncio.wait_for(test1_complete, timeout=2.0)
|
||||||
|
assert test_results["if_then"], "IfAction then branch not executed"
|
||||||
|
assert test_results["if_complete"], "IfAction did not complete"
|
||||||
|
|
||||||
|
# Test 1b: IfAction with else branch
|
||||||
|
test1_complete = loop.create_future()
|
||||||
|
test_results["if_complete"] = False
|
||||||
|
client.execute_service(test_service, {"condition": False, "value": 99})
|
||||||
|
await asyncio.wait_for(test1_complete, timeout=2.0)
|
||||||
|
assert test_results["if_else"], "IfAction else branch not executed"
|
||||||
|
assert test_results["if_complete"], "IfAction did not complete"
|
||||||
|
|
||||||
|
# Test 2: Nested IfAction - test all branches
|
||||||
|
test_service = next((s for s in services if s.name == "test_nested_if"), None)
|
||||||
|
assert test_service is not None, "test_nested_if service not found"
|
||||||
|
|
||||||
|
# Both true
|
||||||
|
client.execute_service(test_service, {"outer": True, "inner": True})
|
||||||
|
await asyncio.wait_for(test2_complete, timeout=2.0)
|
||||||
|
assert test_results["nested_both_true"], "Nested both true not executed"
|
||||||
|
|
||||||
|
# Outer true, inner false
|
||||||
|
test2_complete = loop.create_future()
|
||||||
|
test_results["nested_complete"] = False
|
||||||
|
client.execute_service(test_service, {"outer": True, "inner": False})
|
||||||
|
await asyncio.wait_for(test2_complete, timeout=2.0)
|
||||||
|
assert test_results["nested_outer_true_inner_false"], (
|
||||||
|
"Nested outer true inner false not executed"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Outer false
|
||||||
|
test2_complete = loop.create_future()
|
||||||
|
test_results["nested_complete"] = False
|
||||||
|
client.execute_service(test_service, {"outer": False, "inner": True})
|
||||||
|
await asyncio.wait_for(test2_complete, timeout=2.0)
|
||||||
|
assert test_results["nested_outer_false"], "Nested outer false not executed"
|
||||||
|
|
||||||
|
# Test 3: WhileAction
|
||||||
|
test_service = next(
|
||||||
|
(s for s in services if s.name == "test_while_action"), None
|
||||||
|
)
|
||||||
|
assert test_service is not None, "test_while_action service not found"
|
||||||
|
client.execute_service(test_service, {"max_count": 3})
|
||||||
|
await asyncio.wait_for(test3_complete, timeout=2.0)
|
||||||
|
assert test_results["while_iterations"] == 3, (
|
||||||
|
f"WhileAction expected 3 iterations, got {test_results['while_iterations']}"
|
||||||
|
)
|
||||||
|
assert test_results["while_complete"], "WhileAction did not complete"
|
||||||
|
|
||||||
|
# Test 4: RepeatAction
|
||||||
|
test_service = next(
|
||||||
|
(s for s in services if s.name == "test_repeat_action"), None
|
||||||
|
)
|
||||||
|
assert test_service is not None, "test_repeat_action service not found"
|
||||||
|
client.execute_service(test_service, {"count": 5})
|
||||||
|
await asyncio.wait_for(test4_complete, timeout=2.0)
|
||||||
|
assert test_results["repeat_iterations"] == 5, (
|
||||||
|
f"RepeatAction expected 5 iterations, got {test_results['repeat_iterations']}"
|
||||||
|
)
|
||||||
|
assert test_results["repeat_complete"], "RepeatAction did not complete"
|
||||||
|
|
||||||
|
# Test 5: Combined (if + repeat + while)
|
||||||
|
test_service = next((s for s in services if s.name == "test_combined"), None)
|
||||||
|
assert test_service is not None, "test_combined service not found"
|
||||||
|
client.execute_service(test_service, {"do_loop": True, "loop_count": 2})
|
||||||
|
await asyncio.wait_for(test5_complete, timeout=2.0)
|
||||||
|
# Should execute: repeat 2 times, each iteration does while from iteration down to 0
|
||||||
|
# iteration 0: while 0 times = 0
|
||||||
|
# iteration 1: while 1 time = 1
|
||||||
|
# Total: 1 combined log
|
||||||
|
assert test_results["combined_iterations"] >= 1, (
|
||||||
|
f"Combined expected >=1 iterations, got {test_results['combined_iterations']}"
|
||||||
|
)
|
||||||
|
assert test_results["combined_complete"], "Combined did not complete"
|
||||||
|
|
||||||
|
# Test 6: Rapid triggers (tests memory efficiency of ContinuationAction)
|
||||||
|
test_service = next((s for s in services if s.name == "test_rapid_if"), None)
|
||||||
|
assert test_service is not None, "test_rapid_if service not found"
|
||||||
|
client.execute_service(test_service, {})
|
||||||
|
await asyncio.wait_for(test6_complete, timeout=2.0)
|
||||||
|
# Values 1, 2 should hit else (<=2), values 3, 4, 5 should hit then (>2)
|
||||||
|
assert test_results["rapid_else"] == 2, (
|
||||||
|
f"Rapid test expected 2 else, got {test_results['rapid_else']}"
|
||||||
|
)
|
||||||
|
assert test_results["rapid_then"] == 3, (
|
||||||
|
f"Rapid test expected 3 then, got {test_results['rapid_then']}"
|
||||||
|
)
|
||||||
|
assert test_results["rapid_complete"] == 5, (
|
||||||
|
f"Rapid test expected 5 completions, got {test_results['rapid_complete']}"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user