class ComplexGraph(unittest.TestCase): def setUp(self): """Constructs the following graph: +---------------------------+ | SAVE | | +-----+ ^ | +--->Add +----+ | |to 10| +----+ | | +--------> | | +-----+ |ADD +---+ 2 --->| | +----+ """ self.saver = StateSaver(int) with DeltaGraph() as graph: add_ph = placeholder_node_factory() b = return_2() self.int_node = add_until_10.call(num=add_ph) add_node = add_non_const(b, self.int_node.x) add_ph.specify_by_node(add_node) self.saver.save_and_exit(self.int_node.y) self.graph = graph self.runtime = DeltaPySimulator(self.graph) def test_run(self): """This graph should run, adding 2 to the number on every cycle.""" self.runtime.run() self.assertEqual(self.saver.saved, [11]) def test_graph_properties(self): self.graph.check()
def test_method(self): foo = Foo() with DeltaGraph() as test_graph: foo.add_set_x(a=4, b=5) rt = DeltaPySimulator(test_graph) rt.run() self.assertEqual(foo.x, 9)
class UpdateClockTest(unittest.TestCase): """Test logical clock in MessageLog. TODO this test case should be moved from here. """ def setUp(self): with DeltaGraph() as self.test_graph: const_consumer(obj=forward.call(num=return_1())) def test_clock_updates(self): """Messages should be displayed at end of run in logical clock order. """ self.rt = DeltaPySimulator(self.test_graph, msg_lvl=logging.DEBUG) self.rt.run() message_times = [ msg.clk for node, _, msg in self.rt.msg_log.messages if node.startswith("const_consumer") ] self.assertGreater(len(message_times), 0) for time_1, time_2 in zip(message_times, message_times[1:]): self.assertLess(time_1, time_2) def test_no_message_logging(self): """Messages should not be logged at all. """ self.rt = DeltaPySimulator(self.test_graph) self.rt.run() message_times = [ msg.clk for node, _, msg in self.rt.msg_log.messages if node.startswith("const_consumer") ] self.assertEqual(message_times, []) for time_1, time_2 in zip(message_times, message_times[1:]): self.assertLess(time_1, time_2)
def test_placeholder_method(self): foo = Foo() with DeltaGraph() as test_graph: n = placeholder_node_factory(a=4, b=5) n.specify_by_method(Foo.add_set_x, foo, node_key="node") rt = DeltaPySimulator(test_graph) rt.run() self.assertEqual(foo.x, 9)
def test_func(self): @DeltaBlock(node_key="node") def add_assert(a: int, b: int, node: PythonNode = None) -> Void: self.assertEqual(node.receive('a') + node.receive('b'), 9) raise DeltaRuntimeExit with DeltaGraph() as test_graph: add_assert(a=4, b=5) rt = DeltaPySimulator(test_graph) rt.run()
def test_migen_node_reset_shaper_constant(self, mock_stdout): """One PyMigenBody that takes as input a reset signal and extends the length of the reset to N clock cycles reset. """ graph, _ = generate_graph_constant_input() rt = DeltaPySimulator(graph) rt.run() self.assertEqual( mock_stdout.getvalue(), 'CHECK_SHAPE: reset has lasted at least 5 clk cycles\n')
def test_real_run(self): """Test that the graph runs and terminates.""" interactive_node = self.graph.find_node_by_name("blah") runtime = DeltaPySimulator(self.graph) # run for a short time - just enough for the processing to end runtime.run(0.1) # check that the interactive node has terminated self.assertFalse(runtime.threads[interactive_node.name].is_alive()) runtime.stop()
def test_placeholder_func(self): @DeltaBlock(node_key="node") def add_assert(a: int, b: int, node: PythonNode = None) -> Void: self.assertEqual(node.receive('a') + node.receive('b'), 9) raise DeltaRuntimeExit with DeltaGraph() as test_graph: n = placeholder_node_factory(a=4, b=5) n.specify_by_func(add_assert, node_key="node") rt = DeltaPySimulator(test_graph) rt.run()
def test_migen_node_reset_shaper_pulse(self, mock_stdout): """One PyMigenBody that takes as input a reset signal and extends the length of the reset to N clock cycles reset. We generate a pulse of length 1 clock cycle (i.e. 0010) and check for (00000...111110) """ graph, _ = generate_graph_interactive_input(verbose=False) rt = DeltaPySimulator(graph) rt.run() self.assertEqual( mock_stdout.getvalue(), 'CHECK_SHAPE: reset has lasted exactly 5 clk cycles\n')
def test_splitting_of_one_forked_non_const(self): """One of forked outputs of a non-constant node is splitted.""" s1 = StateSaver(int) s2 = StateSaver(int) with DeltaGraph() as graph: val = return_12_non_const() val_x = val.x s1.save(val_x) s2.save_and_exit(val_x) rt = DeltaPySimulator(graph) rt.run() self.assertEqual(s2.saved, [1])
def test_one_migen_node_with_2_outs(self): """One PyMigenBody with 2 out ports produces what we expect.""" s = StateSaver(int, verbose=True) with DeltaGraph() as graph: counter = TestMigen(tb_num_iter=2000, name='counter', lvl=logging.INFO).call(in1=40, in2=2) s.save_and_exit(adder(counter.out1, multiplier(counter.out2))) rt = DeltaPySimulator(graph) rt.run() self.assertEqual(s.saved, [5042])
def test_one_migen_node_with_separate_ctrl_on_output_valid(self): """One PyMigenBody with 2 optional output ports produces the correct valid values (for the different ports). The migen node should be generating a sequence of outputs (1, None), (None, 2), (3, None) etc... """ with DeltaGraph() as graph: alt = AlternatingOutputsMigen(tb_num_iter=100, name='alternatingOutput', lvl=logging.INFO).call(start=1) my_adder = add_non_const(alt.out_a, alt.out_b) # Checking that we have received a 1 and a 2 checker = InputCheckerWithExit(lambda x: (x == 3)) checker.check(my_adder) rt = DeltaPySimulator(graph) rt.run() self.assertEqual(checker.cond_met, True)
def test_migen_trigger_succeeds(self): """Assert that when the `test_bench_ye_trigger` node sends data, the ouput of the migen node is 15 since the data signal is available on the particular clock cycle that loads in the data. """ with DeltaGraph() as graph: test_bench_output = test_bench_yes_trigger.call() c1 = TestMigenNode(tb_num_iter=10).call( inp=test_bench_output.inp, trigger=test_bench_output.trigger) self.saver.save_and_exit(c1.out) rt = DeltaPySimulator(graph) rt.run() self.assertEqual(self.saver.saved[0], 15)
def test_migen_trigger_fails(self): """Assert that when the `test_bench_no_trigger` node sends data, the ouput of the migen node is 0 due to the data not loading into output signal properly. """ with DeltaGraph() as graph: test_bench_output = test_bench_no_trigger.call() c1 = TestMigenNode(tb_num_iter=10).call( inp=test_bench_output.inp, trigger=test_bench_output.trigger) self.saver.save_and_exit(c1.out) rt = DeltaPySimulator(graph) rt.run() self.assertEqual(self.saver.saved[0], 0)
def test_can_save_to_tempfile(self): """Test StateSaver can save to a file.""" st = [(k, k**2) for k in range(5)] # Note the conversion to a list as the json format doesn't care # for tuples. st_expected = "\n".join(repr(list(x)) for x in st) items = [ ((int, int), (42, 100), "[42, 100]"), ((int, int), st, st_expected), (str, "Hello", '"Hello"'), (bool, True, "true"), (float, 3.91, "3.91"), (Tuple([int, int]), (1, 2), "[1, 2]"), (Union([int, float]), 90, "90"), (Union([int, float]), 90.0, "90.0"), (complex, 1j, '{"real": 0.0, "imaginary": 1.0}'), (SimpleRecord, SimpleRecord(x=1, y=True), '{"x": 1, "y": true}'), ( ComplexRecord, ComplexRecord(x=1 + 2j), '{"x": {"real": 1.0, "imaginary": 2.0}}' ), ( NestedRecord, NestedRecord(x=3, y=SimpleRecord(x=1, y=True)), '{"x": 3, "y": {"x": 1, "y": true}}' ), ( ArrayRecord, ArrayRecord(x=[ComplexRecord(x=-1+4j)]), '{"x": [{"x": {"real": -1.0, "imaginary": 4.0}}]}' ) ] for i, item in enumerate(items): t, data, expected = item with self.subTest(i=i): with tempfile.NamedTemporaryFile(mode="w+") as f: s = StateSaver(t, verbose=True, filename=f.name) @DeltaBlock(allow_const=False) def save_things_node() -> object: # If it's a list, save them independently, otherwise # it's just one thing. if type(data) == list: for d in data: s.save(d) else: s.save(data) raise DeltaRuntimeExit with DeltaGraph() as graph: save_things_node() rt = DeltaPySimulator(graph) rt.run() f.seek(0) contents = f.read() self.assertEqual(contents, f"{expected}\n")