Skip to main content

oxilean_kernel/trace/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use 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
15/// Build a debug event for definitional equality checking.
16pub fn def_eq_event(msg: impl Into<String>) -> TraceEvent {
17    TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::DefEq)
18}
19/// Build a trace event for reduction.
20pub fn reduce_event(msg: impl Into<String>) -> TraceEvent {
21    TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Reduce)
22}
23/// Build an info event for tactic execution.
24pub 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}
133/// Build an info event for the simp category.
134pub fn simp_event(msg: impl Into<String>) -> TraceEvent {
135    TraceEvent::new(TraceLevel::Info, msg.into()).with_category(TraceCategory::Simp)
136}
137/// Build a debug event for the unification category.
138pub fn unify_event(msg: impl Into<String>) -> TraceEvent {
139    TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::Unify)
140}
141/// Build a trace event for elaboration.
142pub fn elab_event(msg: impl Into<String>) -> TraceEvent {
143    TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Elab)
144}
145/// Build an info event for typeclass resolution.
146pub fn typeclass_event(msg: impl Into<String>) -> TraceEvent {
147    TraceEvent::new(TraceLevel::Info, msg.into()).with_category(TraceCategory::Typeclass)
148}
149/// Build a warning event with no category.
150pub fn warn_event(msg: impl Into<String>) -> TraceEvent {
151    TraceEvent::new(TraceLevel::Warn, msg.into())
152}
153/// Build an error event with no category.
154pub 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}
263/// Replay events from one tracer into a sink.
264pub fn replay_into_sink(tracer: &Tracer, sink: &mut StringSink) {
265    for event in tracer.events() {
266        sink.record(event);
267    }
268}
269/// Filter events by a predicate and return formatted strings.
270pub 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}
278/// Count events matching a predicate.
279pub fn count_matching<F: Fn(&TraceEvent) -> bool>(tracer: &Tracer, pred: F) -> usize {
280    tracer.events().iter().filter(|e| pred(e)).count()
281}
282/// Check whether the tracer has logged any event with a message containing `substr`.
283pub fn has_message_containing(tracer: &Tracer, substr: &str) -> bool {
284    tracer.events().iter().any(|e| e.message.contains(substr))
285}
286/// Build a trace event for kernel type inference.
287pub fn infer_event(msg: impl Into<String>) -> TraceEvent {
288    TraceEvent::new(TraceLevel::Debug, msg.into()).with_category(TraceCategory::Infer)
289}
290/// Build a trace event for definitional equality with location.
291pub 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}
296/// Merge events from `src` into `dst` tracer (if below `dst`'s level).
297pub fn merge_tracers(src: &Tracer, dst: &mut Tracer) {
298    for event in src.events() {
299        dst.log(event.clone());
300    }
301}
302/// Summarize a tracer's reduction steps.
303pub 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}
398/// Filter events from a tracer using a filter.
399pub 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}
406/// Count events in a tracer matching a filter.
407pub fn count_filtered(tracer: &Tracer, filter: &TraceFilter) -> usize {
408    filtered_events(tracer, filter).len()
409}
410/// Extract all unique categories present in a tracer's events.
411pub 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}