1use crate::Expr;
6
7use super::types::{
8 ConfigNode, DecisionNode, Either2, FlatSubstitution, FocusStack, LabelSet, NonEmptyVec,
9 PathBuf, ReductionRule, RewriteRule, RewriteRuleSet, RingTracer, SimpleDag, SlidingSum,
10 SmallMap, SparseVec, StackCalc, StatSummary, Stopwatch, StringPool, StringSink, TokenBucket,
11 TraceCategory, TraceEvent, TraceFilter, TraceLevel, Tracer, TransformStat, TransitiveClosure,
12 VersionedRecord, WindowIterator, WriteOnce,
13};
14
15pub fn def_eq_event(msg: impl Into<String>) -> TraceEvent {
17 TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::DefEq)
18}
19pub fn reduce_event(msg: impl Into<String>) -> TraceEvent {
21 TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Reduce)
22}
23pub fn tactic_event(msg: impl Into<String>) -> TraceEvent {
25 TraceEvent::new(TraceLevel::Info, msg.into()).with_category(TraceCategory::Tactic)
26}
27#[cfg(test)]
28mod tests {
29 use super::*;
30 use crate::Literal;
31 #[test]
32 fn test_tracer_create() {
33 let tracer = Tracer::new(TraceLevel::Info);
34 assert_eq!(tracer.level(), TraceLevel::Info);
35 assert_eq!(tracer.events().len(), 0);
36 }
37 #[test]
38 fn test_log_event() {
39 let mut tracer = Tracer::new(TraceLevel::Debug);
40 tracer.log(TraceEvent::new(
41 TraceLevel::Info,
42 "Test message".to_string(),
43 ));
44 assert_eq!(tracer.event_count(), 1);
45 }
46 #[test]
47 fn test_log_filtered() {
48 let mut tracer = Tracer::new(TraceLevel::Warn);
49 tracer.log(TraceEvent::new(
50 TraceLevel::Debug,
51 "Test message".to_string(),
52 ));
53 assert_eq!(tracer.event_count(), 0);
54 }
55 #[test]
56 fn test_clear() {
57 let mut tracer = Tracer::new(TraceLevel::Debug);
58 tracer.info("hello");
59 assert_eq!(tracer.event_count(), 1);
60 tracer.clear();
61 assert_eq!(tracer.event_count(), 0);
62 }
63 #[test]
64 fn test_with_expr() {
65 let event = TraceEvent::new(TraceLevel::Info, "Test".to_string())
66 .with_expr(Expr::Lit(Literal::Nat(42)));
67 assert!(event.expr.is_some());
68 }
69 #[test]
70 fn test_level_ordering() {
71 assert!(TraceLevel::Off < TraceLevel::Error);
72 assert!(TraceLevel::Error < TraceLevel::Warn);
73 assert!(TraceLevel::Warn < TraceLevel::Info);
74 assert!(TraceLevel::Info < TraceLevel::Debug);
75 assert!(TraceLevel::Debug < TraceLevel::Trace);
76 }
77 #[test]
78 fn test_level_from_str() {
79 assert_eq!(TraceLevel::from_str("info"), Some(TraceLevel::Info));
80 assert_eq!(TraceLevel::from_str("DEBUG"), Some(TraceLevel::Debug));
81 assert_eq!(TraceLevel::from_str("bogus"), None);
82 }
83 #[test]
84 fn test_suppress_category() {
85 let mut tracer = Tracer::new(TraceLevel::Trace);
86 tracer.suppress(TraceCategory::Simp);
87 let event = TraceEvent::new(TraceLevel::Trace, "simp step".to_string())
88 .with_category(TraceCategory::Simp);
89 tracer.log(event);
90 assert_eq!(tracer.event_count(), 0);
91 }
92 #[test]
93 fn test_record_reduction() {
94 let mut tracer = Tracer::new(TraceLevel::Trace);
95 let before = Expr::Lit(Literal::Nat(1));
96 let after = Expr::Lit(Literal::Nat(2));
97 tracer.record_reduction(ReductionRule::Beta, before, after);
98 assert_eq!(tracer.reduction_steps().len(), 1);
99 assert_eq!(tracer.reduction_steps()[0].rule, ReductionRule::Beta);
100 }
101 #[test]
102 fn test_depth_indentation() {
103 let mut tracer = Tracer::new(TraceLevel::Info);
104 tracer.push();
105 tracer.push();
106 assert_eq!(tracer.current_depth(), 2);
107 tracer.info("indented");
108 let formatted = tracer.events()[0].format();
109 assert!(
110 formatted.starts_with(" "),
111 "Expected 4-space indent, got: {formatted:?}"
112 );
113 }
114 #[test]
115 fn test_render() {
116 let mut tracer = Tracer::new(TraceLevel::Info);
117 tracer.info("line 1");
118 tracer.info("line 2");
119 let rendered = tracer.render();
120 assert!(rendered.contains("line 1"));
121 assert!(rendered.contains("line 2"));
122 }
123 #[test]
124 fn test_convenience_builders() {
125 let e1 = def_eq_event("checking");
126 assert_eq!(e1.category, Some(TraceCategory::DefEq));
127 let e2 = reduce_event("reducing");
128 assert_eq!(e2.category, Some(TraceCategory::Reduce));
129 let e3 = tactic_event("applying");
130 assert_eq!(e3.category, Some(TraceCategory::Tactic));
131 }
132}
133pub fn simp_event(msg: impl Into<String>) -> TraceEvent {
135 TraceEvent::new(TraceLevel::Info, msg.into()).with_category(TraceCategory::Simp)
136}
137pub fn unify_event(msg: impl Into<String>) -> TraceEvent {
139 TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::Unify)
140}
141pub fn elab_event(msg: impl Into<String>) -> TraceEvent {
143 TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Elab)
144}
145pub fn typeclass_event(msg: impl Into<String>) -> TraceEvent {
147 TraceEvent::new(TraceLevel::Info, msg.into()).with_category(TraceCategory::Typeclass)
148}
149pub fn warn_event(msg: impl Into<String>) -> TraceEvent {
151 TraceEvent::new(TraceLevel::Warn, msg.into())
152}
153pub fn error_event(msg: impl Into<String>) -> TraceEvent {
155 TraceEvent::new(TraceLevel::Error, msg.into())
156}
157#[cfg(test)]
158mod trace_extended_tests {
159 use super::*;
160 #[test]
161 fn test_ring_tracer_basic() {
162 let mut rt = RingTracer::new(3, TraceLevel::Info);
163 rt.log_msg(TraceLevel::Info, "a");
164 rt.log_msg(TraceLevel::Info, "b");
165 rt.log_msg(TraceLevel::Info, "c");
166 assert_eq!(rt.stored_count(), 3);
167 assert_eq!(rt.total_count(), 3);
168 }
169 #[test]
170 fn test_ring_tracer_overflow() {
171 let mut rt = RingTracer::new(2, TraceLevel::Info);
172 rt.log_msg(TraceLevel::Info, "a");
173 rt.log_msg(TraceLevel::Info, "b");
174 rt.log_msg(TraceLevel::Info, "c");
175 assert_eq!(rt.stored_count(), 2);
176 assert_eq!(rt.total_count(), 3);
177 }
178 #[test]
179 fn test_ring_tracer_clear() {
180 let mut rt = RingTracer::new(5, TraceLevel::Info);
181 rt.log_msg(TraceLevel::Info, "x");
182 rt.clear();
183 assert_eq!(rt.stored_count(), 0);
184 assert_eq!(rt.total_count(), 0);
185 }
186 #[test]
187 fn test_ring_tracer_level_filter() {
188 let mut rt = RingTracer::new(10, TraceLevel::Warn);
189 rt.log_msg(TraceLevel::Debug, "debug msg");
190 assert_eq!(rt.stored_count(), 0);
191 rt.log_msg(TraceLevel::Warn, "warn msg");
192 assert_eq!(rt.stored_count(), 1);
193 }
194 #[test]
195 fn test_tracer_stats() {
196 let mut t = Tracer::new(TraceLevel::Trace);
197 t.error("err");
198 t.warn("wrn");
199 t.info("inf");
200 let stats = t.stats();
201 assert_eq!(stats.errors, 1);
202 assert_eq!(stats.warnings, 1);
203 assert_eq!(stats.infos, 1);
204 assert!(stats.has_errors());
205 assert!(stats.has_warnings());
206 }
207 #[test]
208 fn test_tracer_last_event() {
209 let mut t = Tracer::new(TraceLevel::Info);
210 assert!(t.last_event().is_none());
211 t.info("first");
212 t.info("second");
213 assert_eq!(
214 t.last_event().expect("last_event should succeed").message,
215 "second"
216 );
217 }
218 #[test]
219 fn test_tracer_last_error() {
220 let mut t = Tracer::new(TraceLevel::Trace);
221 t.info("not an error");
222 assert!(t.last_error().is_none());
223 t.error("problem");
224 assert!(t.last_error().is_some());
225 }
226 #[test]
227 fn test_tracer_log_with_category() {
228 let mut t = Tracer::new(TraceLevel::Debug);
229 t.log_with_category(TraceLevel::Debug, TraceCategory::Simp, "simp step");
230 let simp = t.events_in_category(&TraceCategory::Simp);
231 assert_eq!(simp.len(), 1);
232 }
233 #[test]
234 fn test_simp_event() {
235 let e = simp_event("normalizing");
236 assert_eq!(e.category, Some(TraceCategory::Simp));
237 }
238 #[test]
239 fn test_unify_event() {
240 let e = unify_event("checking");
241 assert_eq!(e.category, Some(TraceCategory::Unify));
242 }
243 #[test]
244 fn test_warn_error_events() {
245 let w = warn_event("careful");
246 let e = error_event("oops");
247 assert_eq!(w.level, TraceLevel::Warn);
248 assert_eq!(e.level, TraceLevel::Error);
249 }
250 #[test]
251 fn test_tracer_is_empty() {
252 let t = Tracer::new(TraceLevel::Info);
253 assert!(t.is_empty());
254 }
255 #[test]
256 fn test_category_log() {
257 let mut t = Tracer::new(TraceLevel::Debug);
258 t.log_infer("inferring type");
259 let log = t.category_log(&TraceCategory::Infer);
260 assert!(!log.is_empty());
261 }
262}
263pub fn replay_into_sink(tracer: &Tracer, sink: &mut StringSink) {
265 for event in tracer.events() {
266 sink.record(event);
267 }
268}
269pub fn filter_events<F: Fn(&TraceEvent) -> bool>(tracer: &Tracer, pred: F) -> Vec<String> {
271 tracer
272 .events()
273 .iter()
274 .filter(|e| pred(e))
275 .map(|e| e.format())
276 .collect()
277}
278pub fn count_matching<F: Fn(&TraceEvent) -> bool>(tracer: &Tracer, pred: F) -> usize {
280 tracer.events().iter().filter(|e| pred(e)).count()
281}
282pub fn has_message_containing(tracer: &Tracer, substr: &str) -> bool {
284 tracer.events().iter().any(|e| e.message.contains(substr))
285}
286pub fn infer_event(msg: impl Into<String>) -> TraceEvent {
288 TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::Infer)
289}
290pub fn def_eq_event_at(msg: impl Into<String>, loc: impl Into<String>) -> TraceEvent {
292 TraceEvent::new(TraceLevel::Debug, msg.into())
293 .with_category(TraceCategory::DefEq)
294 .with_location(loc)
295}
296pub fn merge_tracers(src: &Tracer, dst: &mut Tracer) {
298 for event in src.events() {
299 dst.log(event.clone());
300 }
301}
302pub fn summarize_reductions(tracer: &Tracer) -> String {
304 let steps = tracer.reduction_steps();
305 if steps.is_empty() {
306 "No reductions recorded.".to_string()
307 } else {
308 format!(
309 "{} reduction(s): {}",
310 steps.len(),
311 steps
312 .iter()
313 .map(|s| s.rule.to_string())
314 .collect::<Vec<_>>()
315 .join(", ")
316 )
317 }
318}
319#[cfg(test)]
320mod trace_further_tests {
321 use super::*;
322 use crate::Literal;
323 #[test]
324 fn test_string_sink_record() {
325 let mut t = Tracer::new(TraceLevel::Info);
326 t.info("hello");
327 let mut sink = StringSink::new();
328 replay_into_sink(&t, &mut sink);
329 assert_eq!(sink.len(), 1);
330 assert!(sink.render().contains("hello"));
331 }
332 #[test]
333 fn test_filter_events() {
334 let mut t = Tracer::new(TraceLevel::Debug);
335 t.info("info msg");
336 t.debug("debug msg");
337 let infos = filter_events(&t, |e| e.level == TraceLevel::Info);
338 assert_eq!(infos.len(), 1);
339 }
340 #[test]
341 fn test_count_matching() {
342 let mut t = Tracer::new(TraceLevel::Debug);
343 t.error("e1");
344 t.error("e2");
345 t.info("i1");
346 let n = count_matching(&t, |e| e.level == TraceLevel::Error);
347 assert_eq!(n, 2);
348 }
349 #[test]
350 fn test_has_message_containing() {
351 let mut t = Tracer::new(TraceLevel::Info);
352 t.info("type mismatch found");
353 assert!(has_message_containing(&t, "mismatch"));
354 assert!(!has_message_containing(&t, "universe"));
355 }
356 #[test]
357 fn test_merge_tracers() {
358 let mut src = Tracer::new(TraceLevel::Info);
359 src.info("from source");
360 let mut dst = Tracer::new(TraceLevel::Info);
361 merge_tracers(&src, &mut dst);
362 assert_eq!(dst.event_count(), 1);
363 }
364 #[test]
365 fn test_summarize_reductions_empty() {
366 let t = Tracer::new(TraceLevel::Trace);
367 let s = summarize_reductions(&t);
368 assert!(s.contains("No reductions"));
369 }
370 #[test]
371 fn test_summarize_reductions_some() {
372 let mut t = Tracer::new(TraceLevel::Trace);
373 let e = Expr::Lit(Literal::Nat(1));
374 t.record_reduction(ReductionRule::Beta, e.clone(), e.clone());
375 let s = summarize_reductions(&t);
376 assert!(s.contains("beta"));
377 }
378 #[test]
379 fn test_infer_event_category() {
380 let e = infer_event("checking sort");
381 assert_eq!(e.category, Some(TraceCategory::Infer));
382 assert_eq!(e.level, TraceLevel::Debug);
383 }
384 #[test]
385 fn test_def_eq_event_at_location() {
386 let e = def_eq_event_at("comparing", "line 42");
387 assert_eq!(e.category, Some(TraceCategory::DefEq));
388 assert_eq!(e.location, "line 42");
389 }
390 #[test]
391 fn test_string_sink_clear() {
392 let mut sink = StringSink::new();
393 sink.lines.push("a".to_string());
394 sink.clear();
395 assert!(sink.is_empty());
396 }
397}
398pub fn filtered_events<'a>(tracer: &'a Tracer, filter: &'a TraceFilter) -> Vec<&'a TraceEvent> {
400 tracer
401 .events()
402 .iter()
403 .filter(|e| filter.accepts(e))
404 .collect()
405}
406pub fn count_filtered(tracer: &Tracer, filter: &TraceFilter) -> usize {
408 filtered_events(tracer, filter).len()
409}
410pub fn unique_categories(tracer: &Tracer) -> Vec<TraceCategory> {
412 let mut cats: Vec<TraceCategory> = tracer
413 .events()
414 .iter()
415 .filter_map(|e| e.category.clone())
416 .collect();
417 cats.dedup();
418 cats
419}
420#[cfg(test)]
421mod trace_filter_tests {
422 use super::*;
423 #[test]
424 fn test_trace_filter_level_excludes() {
425 let mut t = Tracer::new(TraceLevel::Trace);
426 t.debug("a debug message");
427 t.info("an info message");
428 let filter = TraceFilter::at_level(TraceLevel::Info);
429 let events = filtered_events(&t, &filter);
430 assert!(events.iter().all(|e| e.level >= TraceLevel::Info));
431 }
432 #[test]
433 fn test_trace_filter_category() {
434 let mut t = Tracer::new(TraceLevel::Trace);
435 t.trace_infer("infer something");
436 t.trace_reduce("reduce something");
437 let filter =
438 TraceFilter::at_level(TraceLevel::Trace).with_categories(vec![TraceCategory::Infer]);
439 let events = filtered_events(&t, &filter);
440 assert!(events
441 .iter()
442 .all(|e| e.category == Some(TraceCategory::Infer)));
443 }
444 #[test]
445 fn test_trace_filter_exclude_text() {
446 let mut t = Tracer::new(TraceLevel::Trace);
447 t.info("universe check");
448 t.info("type inference");
449 let filter = TraceFilter::at_level(TraceLevel::Info).excluding("universe");
450 let events = filtered_events(&t, &filter);
451 assert!(events.iter().all(|e| !e.message.contains("universe")));
452 }
453 #[test]
454 fn test_count_filtered() {
455 let mut t = Tracer::new(TraceLevel::Trace);
456 t.info("msg1");
457 t.info("msg2");
458 t.debug("msg3");
459 let filter = TraceFilter::at_level(TraceLevel::Info);
460 assert_eq!(count_filtered(&t, &filter), 2);
461 }
462 #[test]
463 fn test_unique_categories_empty() {
464 let t = Tracer::new(TraceLevel::Off);
465 let cats = unique_categories(&t);
466 assert!(cats.is_empty());
467 }
468 #[test]
469 fn test_unique_categories_non_empty() {
470 let mut t = Tracer::new(TraceLevel::Trace);
471 t.trace_infer("x");
472 t.trace_reduce("y");
473 let cats = unique_categories(&t);
474 assert!(!cats.is_empty());
475 }
476 #[test]
477 fn test_trace_filter_default_accepts_nothing() {
478 let mut t = Tracer::new(TraceLevel::Trace);
479 t.info("hi");
480 let filter = TraceFilter::default();
481 let events = filtered_events(&t, &filter);
482 let _ = events;
483 }
484}
485#[cfg(test)]
486mod tests_padding_infra {
487 use super::*;
488 #[test]
489 fn test_stat_summary() {
490 let mut ss = StatSummary::new();
491 ss.record(10.0);
492 ss.record(20.0);
493 ss.record(30.0);
494 assert_eq!(ss.count(), 3);
495 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
496 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
497 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
498 }
499 #[test]
500 fn test_transform_stat() {
501 let mut ts = TransformStat::new();
502 ts.record_before(100.0);
503 ts.record_after(80.0);
504 let ratio = ts.mean_ratio().expect("ratio should be present");
505 assert!((ratio - 0.8).abs() < 1e-9);
506 }
507 #[test]
508 fn test_small_map() {
509 let mut m: SmallMap<u32, &str> = SmallMap::new();
510 m.insert(3, "three");
511 m.insert(1, "one");
512 m.insert(2, "two");
513 assert_eq!(m.get(&2), Some(&"two"));
514 assert_eq!(m.len(), 3);
515 let keys = m.keys();
516 assert_eq!(*keys[0], 1);
517 assert_eq!(*keys[2], 3);
518 }
519 #[test]
520 fn test_label_set() {
521 let mut ls = LabelSet::new();
522 ls.add("foo");
523 ls.add("bar");
524 ls.add("foo");
525 assert_eq!(ls.count(), 2);
526 assert!(ls.has("bar"));
527 assert!(!ls.has("baz"));
528 }
529 #[test]
530 fn test_config_node() {
531 let mut root = ConfigNode::section("root");
532 let child = ConfigNode::leaf("key", "value");
533 root.add_child(child);
534 assert_eq!(root.num_children(), 1);
535 }
536 #[test]
537 fn test_versioned_record() {
538 let mut vr = VersionedRecord::new(0u32);
539 vr.update(1);
540 vr.update(2);
541 assert_eq!(*vr.current(), 2);
542 assert_eq!(vr.version(), 2);
543 assert!(vr.has_history());
544 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
545 }
546 #[test]
547 fn test_simple_dag() {
548 let mut dag = SimpleDag::new(4);
549 dag.add_edge(0, 1);
550 dag.add_edge(1, 2);
551 dag.add_edge(2, 3);
552 assert!(dag.can_reach(0, 3));
553 assert!(!dag.can_reach(3, 0));
554 let order = dag.topological_sort().expect("order should be present");
555 assert_eq!(order, vec![0, 1, 2, 3]);
556 }
557 #[test]
558 fn test_focus_stack() {
559 let mut fs: FocusStack<&str> = FocusStack::new();
560 fs.focus("a");
561 fs.focus("b");
562 assert_eq!(fs.current(), Some(&"b"));
563 assert_eq!(fs.depth(), 2);
564 fs.blur();
565 assert_eq!(fs.current(), Some(&"a"));
566 }
567}
568#[cfg(test)]
569mod tests_extra_iterators {
570 use super::*;
571 #[test]
572 fn test_window_iterator() {
573 let data = vec![1u32, 2, 3, 4, 5];
574 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
575 assert_eq!(windows.len(), 3);
576 assert_eq!(windows[0], &[1, 2, 3]);
577 assert_eq!(windows[2], &[3, 4, 5]);
578 }
579 #[test]
580 fn test_non_empty_vec() {
581 let mut nev = NonEmptyVec::singleton(10u32);
582 nev.push(20);
583 nev.push(30);
584 assert_eq!(nev.len(), 3);
585 assert_eq!(*nev.first(), 10);
586 assert_eq!(*nev.last(), 30);
587 }
588}
589#[cfg(test)]
590mod tests_padding2 {
591 use super::*;
592 #[test]
593 fn test_sliding_sum() {
594 let mut ss = SlidingSum::new(3);
595 ss.push(1.0);
596 ss.push(2.0);
597 ss.push(3.0);
598 assert!((ss.sum() - 6.0).abs() < 1e-9);
599 ss.push(4.0);
600 assert!((ss.sum() - 9.0).abs() < 1e-9);
601 assert_eq!(ss.count(), 3);
602 }
603 #[test]
604 fn test_path_buf() {
605 let mut pb = PathBuf::new();
606 pb.push("src");
607 pb.push("main");
608 assert_eq!(pb.as_str(), "src/main");
609 assert_eq!(pb.depth(), 2);
610 pb.pop();
611 assert_eq!(pb.as_str(), "src");
612 }
613 #[test]
614 fn test_string_pool() {
615 let mut pool = StringPool::new();
616 let s = pool.take();
617 assert!(s.is_empty());
618 pool.give("hello".to_string());
619 let s2 = pool.take();
620 assert!(s2.is_empty());
621 assert_eq!(pool.free_count(), 0);
622 }
623 #[test]
624 fn test_transitive_closure() {
625 let mut tc = TransitiveClosure::new(4);
626 tc.add_edge(0, 1);
627 tc.add_edge(1, 2);
628 tc.add_edge(2, 3);
629 assert!(tc.can_reach(0, 3));
630 assert!(!tc.can_reach(3, 0));
631 let r = tc.reachable_from(0);
632 assert_eq!(r.len(), 4);
633 }
634 #[test]
635 fn test_token_bucket() {
636 let mut tb = TokenBucket::new(100, 10);
637 assert_eq!(tb.available(), 100);
638 assert!(tb.try_consume(50));
639 assert_eq!(tb.available(), 50);
640 assert!(!tb.try_consume(60));
641 assert_eq!(tb.capacity(), 100);
642 }
643 #[test]
644 fn test_rewrite_rule_set() {
645 let mut rrs = RewriteRuleSet::new();
646 rrs.add(RewriteRule::unconditional(
647 "beta",
648 "App(Lam(x, b), v)",
649 "b[x:=v]",
650 ));
651 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
652 assert_eq!(rrs.len(), 2);
653 assert_eq!(rrs.unconditional_rules().len(), 1);
654 assert_eq!(rrs.conditional_rules().len(), 1);
655 assert!(rrs.get("beta").is_some());
656 let disp = rrs
657 .get("beta")
658 .expect("element at \'beta\' should exist")
659 .display();
660 assert!(disp.contains("→"));
661 }
662}
663#[cfg(test)]
664mod tests_padding3 {
665 use super::*;
666 #[test]
667 fn test_decision_node() {
668 let tree = DecisionNode::Branch {
669 key: "x".into(),
670 val: "1".into(),
671 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
672 no_branch: Box::new(DecisionNode::Leaf("no".into())),
673 };
674 let mut ctx = std::collections::HashMap::new();
675 ctx.insert("x".into(), "1".into());
676 assert_eq!(tree.evaluate(&ctx), "yes");
677 ctx.insert("x".into(), "2".into());
678 assert_eq!(tree.evaluate(&ctx), "no");
679 assert_eq!(tree.depth(), 1);
680 }
681 #[test]
682 fn test_flat_substitution() {
683 let mut sub = FlatSubstitution::new();
684 sub.add("foo", "bar");
685 sub.add("baz", "qux");
686 assert_eq!(sub.apply("foo and baz"), "bar and qux");
687 assert_eq!(sub.len(), 2);
688 }
689 #[test]
690 fn test_stopwatch() {
691 let mut sw = Stopwatch::start();
692 sw.split();
693 sw.split();
694 assert_eq!(sw.num_splits(), 2);
695 assert!(sw.elapsed_ms() >= 0.0);
696 for &s in sw.splits() {
697 assert!(s >= 0.0);
698 }
699 }
700 #[test]
701 fn test_either2() {
702 let e: Either2<i32, &str> = Either2::First(42);
703 assert!(e.is_first());
704 let mapped = e.map_first(|x| x * 2);
705 assert_eq!(mapped.first(), Some(84));
706 let e2: Either2<i32, &str> = Either2::Second("hello");
707 assert!(e2.is_second());
708 assert_eq!(e2.second(), Some("hello"));
709 }
710 #[test]
711 fn test_write_once() {
712 let wo: WriteOnce<u32> = WriteOnce::new();
713 assert!(!wo.is_written());
714 assert!(wo.write(42));
715 assert!(!wo.write(99));
716 assert_eq!(wo.read(), Some(42));
717 }
718 #[test]
719 fn test_sparse_vec() {
720 let mut sv: SparseVec<i32> = SparseVec::new(100);
721 sv.set(5, 10);
722 sv.set(50, 20);
723 assert_eq!(*sv.get(5), 10);
724 assert_eq!(*sv.get(50), 20);
725 assert_eq!(*sv.get(0), 0);
726 assert_eq!(sv.nnz(), 2);
727 sv.set(5, 0);
728 assert_eq!(sv.nnz(), 1);
729 }
730 #[test]
731 fn test_stack_calc() {
732 let mut calc = StackCalc::new();
733 calc.push(3);
734 calc.push(4);
735 calc.add();
736 assert_eq!(calc.peek(), Some(7));
737 calc.push(2);
738 calc.mul();
739 assert_eq!(calc.peek(), Some(14));
740 }
741}