gwr_track/
test_helpers.rs1use std::cell::RefCell;
13use std::fs;
14use std::io::BufWriter;
15use std::path::Path;
16use std::rc::Rc;
17
18use regex::Regex;
19
20use crate::entity::Capacity;
21use crate::tracker::aka::AlternativeNames;
22use crate::tracker::{CapnProtoTracker, EntityManager};
23use crate::{Id, Track, Tracker, Writer};
24
25pub struct TestTracker {
27 events: RefCell<Vec<String>>,
28
29 unique_id: RefCell<u64>,
30 level: log::Level,
31}
32
33impl TestTracker {
34 #[must_use]
38 pub fn new(initial_id: u64, level: log::Level) -> Self {
39 Self {
40 events: RefCell::new(Vec::new()),
41 unique_id: RefCell::new(initial_id),
42 level,
43 }
44 }
45
46 fn add_event(&self, event: String) {
47 println!("{event}");
48 let mut events = self.events.borrow_mut();
49 events.push(event);
50 }
51
52 #[must_use]
54 pub fn events(&self) -> Vec<String> {
55 self.events.borrow().clone()
56 }
57}
58
59impl Track for TestTracker {
60 fn unique_id(&self) -> Id {
61 let mut guard = self.unique_id.borrow_mut();
62 let id = *guard;
63 *guard += 1;
64 Id(id)
65 }
66
67 fn enabled_level(&self, _id: Id) -> log::Level {
68 self.level
69 }
70
71 fn monitoring_window_size_for(&self, _id: Id) -> Option<u64> {
72 None
73 }
74
75 fn add_entity(
76 &self,
77 _id: Id,
78 _entity_name: &str,
79 _alternative_names: AlternativeNames,
80 ) -> log::Level {
81 self.level
82 }
83
84 fn enter(&self, id: Id, item: Id) {
85 self.add_event(format!("{id}: {item} entered"));
86 }
87
88 fn exit(&self, id: Id, item: Id) {
89 self.add_event(format!("{id}: {item} exited"));
90 }
91
92 fn value(&self, id: Id, value: f64) {
93 self.add_event(format!("{id}: {value}"));
94 }
95
96 fn begin_activity(&self, activity: Id, lane: Id, name: &str) {
97 self.add_event(format!("{activity}: activity begin {name} on lane {lane}"));
98 }
99
100 fn end_activity(&self, activity: Id) {
101 self.add_event(format!("{activity}: activity end"));
102 }
103
104 fn add_to_group(&self, activity: Id, group_id: Id) {
105 self.add_event(format!("{activity}: added to group {group_id}"));
106 }
107
108 fn remove_from_group(&self, activity: Id, group_id: Id) {
109 self.add_event(format!("{activity}: removed from group {group_id}"));
110 }
111
112 fn create_entity(&self, created_by: Id, id: Id, name: &str) {
113 self.add_event(format!("{created_by}: created entity {id}, {name}"));
114 }
115
116 fn create_monitor(&self, created_by: Id, id: Id, name: &str) {
117 self.add_event(format!("{created_by}: created monitor {id}, {name}"));
118 }
119
120 fn create_lane(&self, created_by: Id, id: Id, name: &str) {
121 self.add_event(format!("{created_by}: created lane {id}, {name}"));
122 }
123
124 fn create_group(&self, created_by: Id, id: Id, name: &str) {
125 self.add_event(format!("{created_by}: created group {id}, {name}"));
126 }
127
128 fn create_object(
129 &self,
130 created_by: Id,
131 id: Id,
132 size: usize,
133 units: &str,
134 req_type: u8,
135 details: &str,
136 ) {
137 self.add_event(format!(
138 "{created_by}: created object {id}, {req_type}, {size}, {units}, {details}"
139 ));
140 }
141
142 fn capacity(&self, id: Id, capacity: Capacity) {
143 self.add_event(format!(
144 "{id}: capacity {} {}",
145 capacity.value, capacity.units
146 ));
147 }
148
149 fn destroy(&self, destroyed_by: Id, id: Id) {
150 self.add_event(format!("{destroyed_by}: destroyed {id}"));
151 }
152
153 fn connect(&self, connect_from: Id, connect_to: Id) {
154 self.add_event(format!("{connect_from}: connect to {connect_to}"));
155 }
156
157 fn log(&self, id: Id, level: log::Level, msg: std::fmt::Arguments) {
158 self.add_event(format!("{id}:{level}: {msg}"));
159 }
160
161 fn time(&self, set_by: Id, time_ns: f64) {
162 self.add_event(format!("{set_by}: set time {time_ns:.1}ns"));
163 }
164
165 fn shutdown(&self) {
166 }
168}
169
170#[macro_export]
199macro_rules! test_init {
200 ($start_id:expr) => {{
201 let test_tracker = std::rc::Rc::new($crate::test_helpers::TestTracker::new(
202 $start_id,
203 $crate::log::Level::Trace,
204 ));
205 let tracker: $crate::Tracker = test_tracker.clone();
206 (test_tracker, tracker)
207 }};
208}
209
210pub fn check_and_clear(tracker: &TestTracker, expected: &[&str]) {
244 let mut log_contents_ref = tracker.events.borrow_mut();
245
246 println!("Checking {:?} matches {:?}", expected, *log_contents_ref);
247
248 let num_strings = expected.len();
250 assert_eq!(num_strings, log_contents_ref.len());
251
252 for i in 0..num_strings {
253 let log_expect = expected[i];
254 let re = Regex::new(log_expect).unwrap();
255 let actual = &(*log_contents_ref[i]);
256 println!("Checking {i}: {log_expect:?} matches {actual:?}");
257 assert!(re.is_match(actual));
258 }
259
260 log_contents_ref.clear();
261}
262
263#[must_use]
265pub fn create_tracker(full_filepath: &str) -> Tracker {
266 const FOLDER: &str = "traces";
268
269 fs::create_dir_all(FOLDER).unwrap();
271
272 let filename_only = Path::new(full_filepath)
273 .file_stem()
274 .and_then(|s| s.to_str())
275 .unwrap();
276
277 let bin_writer: Writer = Box::new(BufWriter::new(
278 fs::File::create(format!("{FOLDER}/{filename_only}.bin")).unwrap(),
279 ));
280
281 let default_log_level = log::Level::Trace;
282 let entity_manger = EntityManager::new(default_log_level);
283 let tracker: Tracker = Rc::new(CapnProtoTracker::new(entity_manger, bin_writer));
284 tracker
285}