diff --git a/test/test_core/test_breakpoint.py b/test/test_core/test_breakpoint.py index f361e62f7a1b80df928852616e83db9ba1bdca9d..27986d7ff411f8cd8351b7c0a16238e9c90fe5bb 100644 --- a/test/test_core/test_breakpoint.py +++ b/test/test_core/test_breakpoint.py @@ -6,6 +6,7 @@ from simudator.core.modules.memory import Memory from simudator.core.processor import Processor from simudator.core.signal import Signal + class DummyModule(Module): def __init__(self, name: str = "") -> None: super().__init__(name) @@ -16,19 +17,32 @@ class DummyModule(Module): state["value"] = self.value return state + def test_state_breakpoint(): + """ + Test the functionality of StateBreakpoint. + """ m = DummyModule() bp = StateBreakpoint(m, "value", 10) - assert bp.is_break() == False + # Module state is not set to break value => should not break + assert not bp.is_break() + # Module state is set to break value => should break m.value = 10 - assert bp.is_break() == True + assert bp.is_break() + # Module state is no longer set to break value => should no longer break + # Also checks that a value of a different type than that of the break value + # does not cause issues m.value = "-" - assert bp.is_break() == False + assert not bp.is_break() + def test_memory_breakpoint(): + """ + Test the functionality of MemoryBreakpoint. + """ cpu = Processor() in_s = Signal(cpu) out_s = Signal(cpu) @@ -39,36 +53,131 @@ def test_memory_breakpoint(): # Default memory value is not -2 => should not break bp = MemoryBreakpoint(mem, 3, -2) - assert bp.is_break() == False + assert not bp.is_break() - # Write the relevant memory address to some other value + # Write the relevant memory address to some other value # => should not break in_s.update_value("a") adr_s.update_value(3) ctrl_s.update_value(True) - cpu.do_tick() # Address the memory - cpu.do_tick() # Write to the memory - assert bp.is_break() == False + cpu.do_tick() # Address the memory + cpu.do_tick() # Write to the memory + assert not bp.is_break() - # Write the breakpoint value to the relevant address => should break + # Write the breakpoint value to the relevant address => should break in_s.update_value(-2) cpu.do_tick() - assert bp.is_break() == True + assert bp.is_break() # Writing to some other address should not affect in_s.update_value(-2) adr_s.update_value(7) - cpu.do_tick() # Address the memory - cpu.do_tick() # Write to the memory - assert bp.is_break() == True + cpu.do_tick() # Address the memory + cpu.do_tick() # Write to the memory + assert bp.is_break() # Writing some other value to the relevant address => should no longer break adr_s.update_value(3) in_s.update_value(4.6) - cpu.do_tick() # Address the memory - cpu.do_tick() # Write to the memory - assert bp.is_break() == False + cpu.do_tick() # Address the memory + cpu.do_tick() # Write to the memory + assert not bp.is_break() + + +def test_lambda_breakpoint_no_args(): + """ + Test the functionality of LambdaBreakpoint when supplied with a function + that takes no arguments. + """ + # Test functions with no arguments + # Function returns False => should not break + bp = LambdaBreakpoint(lambda: False) + assert not bp.is_break() + + # Function returns True => should break + bp = LambdaBreakpoint(lambda: True) + assert bp.is_break() + + +def test_lambda_breakpoint_args(): + """ + Test the functionality of LambdaBreakpoint when supplied with a function + that takes arguments. + """ + # Test functions with arguments + # Arguments of same type + def func_1(num, thres): + return num > thres + + kwargs = {"num": 5, "thres": 10} + bp = LambdaBreakpoint(func_1, **kwargs) + assert bp.is_break() == func_1(**kwargs) + + kwargs = {"num": 5, "thres": -2} + bp = LambdaBreakpoint(func_1, **kwargs) + assert bp.is_break() == func_1(**kwargs) + + # Arguments of different types + def str_float_comp(string, num): + return float(string) == num + kwargs = {"string": "2.5", "num": 2.5} + bp = LambdaBreakpoint(str_float_comp, **kwargs) + assert bp.is_break() == str_float_comp(**kwargs) + +def test_lambda_breakpoint_ref_args(): + """ + Test the functionality of LambdaBreakpoint when supplied with a function + that takes references as arguments. + """ + # Explicit comparison of references + l1 = [] + l2 = [] + def func_list_ref_comp(l): + return l is l2 + + kwargs = {"l": l1} + bp = LambdaBreakpoint(func_list_ref_comp, **kwargs) + assert bp.is_break() == func_list_ref_comp(l1) + + kwargs = {"l": l2} + bp = LambdaBreakpoint(func_list_ref_comp, **kwargs) + assert bp.is_break() == func_list_ref_comp(l2) + + # Test that changes to a reference are reflected in the breakpoint + l = [1, 2, "a"] + def func_list_comp(l): + return l == [1, 2, "a", "b"] + + kwargs = {"l": l} + bp = LambdaBreakpoint(func_list_comp, **kwargs) + + # The supplied list is not equal to the internal list of the + # supplied function => shoud not break + assert bp.is_break() == func_list_comp(l) + + # The list is modified to be equal to the internal list of the function + # => should break + l.append("b") + assert bp.is_break() == func_list_comp(l) + + + # Test with reference to a more advanced data structure, e.g. a class + class Dummy: + def __init__(self): + self.value = None + + def func_dummy_val(dummy, value): + return dummy.value == value + + dummy = Dummy() + value = True + kwargs = {"dummy": dummy, "value": value} + bp = LambdaBreakpoint(func_dummy_val, **kwargs) + assert bp.is_break() == func_dummy_val(dummy, value) -def test_lambda_breakpoint(): - pass + # The supplied argument should be a reference, so changes to `dummy` + # should affect the break point + dummy.value = value + assert bp.is_break() == func_dummy_val(dummy, value) + assert bp.is_break() == (not func_dummy_val(dummy, not value))