Testing
Models can be tested using the build_model_harness! macro. This wraps a model
with a simple test harness that drives and expects objects that implement the
AccessMemory trait. The model harness uses the same harness DSL and generated
API as build_component_harness!, but uses MemoryTxn to check objects coming
out of the model.
MemoryTxn lets tests match only the memory access fields that matter for a
scenario. For example, this test harness checks that a Memory model produces a
read response for the expected destination address, while ignoring fields that
are not specified:
#![allow(unused)] fn main() { mod memory_harness { use std::rc::Rc; use gwr_engine::test_helpers::start_test; use gwr_models::build_model_harness; use gwr_models::memory::memory_access::MemoryAccess; use gwr_models::memory::{Memory, MemoryConfig}; use gwr_models::test_helpers::{MemoryTxn, create_default_memory_map, create_read}; const DST_ADDR: u64 = 0x80000; const SRC_ADDR: u64 = 0x90000; const ACCESS_SIZE_BYTES: usize = 64; const OVERHEAD_SIZE_BYTES: usize = 8; build_model_harness! { harness MemoryHarness<T> { component: memory: Rc<Memory<T>>, rx ports: { Rx<T> => rx, }, tx ports: { Tx<T> => tx, }, } } #[test] fn model_harness_matches_selected_memory_fields() { let mut engine = start_test(file!()); let clock = engine.default_clock(); let config = MemoryConfig::new(DST_ADDR, 0x40000, 32, 1); let memory = Memory::<MemoryAccess>::new_and_register( &engine, &clock, engine.top(), "memory", config, ) .unwrap(); let memory_map = Rc::new(create_default_memory_map()); let request = create_read( engine.top(), &memory_map, ACCESS_SIZE_BYTES, DST_ADDR, SRC_ADDR, OVERHEAD_SIZE_BYTES, ); let mut harness = MemoryHarness::new(engine, memory); harness.run_steps([ send_rx!(request), expect_tx!(MemoryTxn::read_rsp(DST_ADDR)), ]); } } }
Use the component harness documentation for the shared syntax and execution model.