1use crate::reduce::{Reducer, ReducibilityHint, TransparencyMode};
6use crate::Node;
7use crate::{Environment, Expr};
8use std::collections::HashMap;
9use std::rc::Rc;
10
11use super::types::{
12 BatchDefEqChecker, ConfigNode, DecisionNode, DefEqChecker, DefEqConfig, DefEqStats, Either2,
13 FlatSubstitution, FocusStack, LabelSet, NameIndex, NonEmptyVec, PathBuf, RewriteRule,
14 RewriteRuleSet, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc, StatSummary, Stopwatch,
15 StringPool, StringTrie, TokenBucket, TransformStat, TransitiveClosure, VersionedRecord,
16 WindowIterator, WriteOnce,
17};
18
19pub fn is_def_eq_simple(t: &Expr, s: &Expr) -> bool {
21 let env = Environment::new();
22 let mut checker = DefEqChecker::new(&env);
23 checker.is_def_eq(t, s)
24}
25#[cfg(test)]
26mod tests {
27 use super::*;
28 use crate::{BinderInfo, Declaration, Level, Literal, Name, ReducibilityHint};
29 #[test]
30 fn test_reflexivity() {
31 let expr = Expr::Lit(Literal::nat(42));
32 assert!(is_def_eq_simple(&expr, &expr));
33 }
34 #[test]
35 fn test_beta_reduction() {
36 let lam = Expr::Lam(
37 BinderInfo::Default,
38 Name::str("x"),
39 Node::new(Expr::Sort(Level::zero())),
40 Node::new(Expr::BVar(0)),
41 );
42 let arg = Expr::Lit(Literal::nat(42));
43 let app = Expr::App(Node::new(lam), Node::new(arg.clone()));
44 assert!(is_def_eq_simple(&app, &arg));
45 }
46 #[test]
47 fn test_delta_reduction() {
48 let mut env = Environment::new();
49 let forty_two = Expr::Lit(Literal::nat(42));
50 env.add(Declaration::Definition {
51 name: Name::str("answer"),
52 univ_params: vec![],
53 ty: Expr::Const(Name::str("Nat"), vec![]),
54 val: forty_two.clone(),
55 hint: ReducibilityHint::Regular(1),
56 })
57 .expect("value should be present");
58 let mut checker = DefEqChecker::new(&env);
59 let answer_const = Expr::Const(Name::str("answer"), vec![]);
60 assert!(checker.is_def_eq(&answer_const, &forty_two));
61 }
62 #[test]
63 fn test_level_equivalence() {
64 let s1 = Expr::Sort(Level::max(
65 Level::param(Name::str("u")),
66 Level::param(Name::str("v")),
67 ));
68 let s2 = Expr::Sort(Level::max(
69 Level::param(Name::str("v")),
70 Level::param(Name::str("u")),
71 ));
72 assert!(is_def_eq_simple(&s1, &s2));
73 }
74 #[test]
75 fn test_not_equal() {
76 let n1 = Expr::Lit(Literal::nat(1));
77 let n2 = Expr::Lit(Literal::nat(2));
78 assert!(!is_def_eq_simple(&n1, &n2));
79 }
80 #[test]
81 fn test_lazy_delta() {
82 let mut env = Environment::new();
83 let val = Expr::Lit(Literal::nat(42));
84 env.add(Declaration::Definition {
85 name: Name::str("a"),
86 univ_params: vec![],
87 ty: Expr::Const(Name::str("Nat"), vec![]),
88 val: val.clone(),
89 hint: ReducibilityHint::Regular(1),
90 })
91 .expect("value should be present");
92 env.add(Declaration::Definition {
93 name: Name::str("b"),
94 univ_params: vec![],
95 ty: Expr::Const(Name::str("Nat"), vec![]),
96 val,
97 hint: ReducibilityHint::Regular(2),
98 })
99 .expect("value should be present");
100 let mut checker = DefEqChecker::new(&env);
101 let a = Expr::Const(Name::str("a"), vec![]);
102 let b = Expr::Const(Name::str("b"), vec![]);
103 assert!(checker.is_def_eq(&a, &b));
104 }
105 #[test]
106 fn test_app_equality() {
107 let f = Expr::Const(Name::str("f"), vec![]);
108 let a = Expr::Lit(Literal::nat(1));
109 let app1 = Expr::App(Node::new(f.clone()), Node::new(a.clone()));
110 let app2 = Expr::App(Node::new(f), Node::new(a));
111 assert!(is_def_eq_simple(&app1, &app2));
112 }
113 #[test]
114 fn test_pi_equality() {
115 let pi1 = Expr::Pi(
116 BinderInfo::Default,
117 Name::str("x"),
118 Node::new(Expr::Sort(Level::zero())),
119 Node::new(Expr::Sort(Level::zero())),
120 );
121 let pi2 = Expr::Pi(
122 BinderInfo::Default,
123 Name::str("y"),
124 Node::new(Expr::Sort(Level::zero())),
125 Node::new(Expr::Sort(Level::zero())),
126 );
127 assert!(is_def_eq_simple(&pi1, &pi2));
128 }
129}
130#[allow(dead_code)]
132pub fn syntactic_eq(t: &Expr, s: &Expr) -> bool {
133 match (t, s) {
134 (Expr::BVar(i), Expr::BVar(j)) => i == j,
135 (Expr::FVar(a), Expr::FVar(b)) => a == b,
136 (Expr::Sort(l1), Expr::Sort(l2)) => crate::level::is_equivalent(l1, l2),
137 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
138 n1 == n2
139 && ls1.len() == ls2.len()
140 && ls1
141 .iter()
142 .zip(ls2.iter())
143 .all(|(l1, l2)| crate::level::is_equivalent(l1, l2))
144 }
145 (Expr::App(f1, a1), Expr::App(f2, a2)) => syntactic_eq(f1, f2) && syntactic_eq(a1, a2),
146 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
147 syntactic_eq(ty1, ty2) && syntactic_eq(b1, b2)
148 }
149 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
150 syntactic_eq(ty1, ty2) && syntactic_eq(b1, b2)
151 }
152 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
153 syntactic_eq(ty1, ty2) && syntactic_eq(v1, v2) && syntactic_eq(b1, b2)
154 }
155 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
156 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
157 n1 == n2 && i1 == i2 && syntactic_eq(e1, e2)
158 }
159 _ => false,
160 }
161}
162#[allow(dead_code)]
164pub fn is_def_eq_with_mode(t: &Expr, s: &Expr, env: &Environment, mode: TransparencyMode) -> bool {
165 let mut checker = DefEqChecker::new(env);
166 checker.set_transparency(mode);
167 checker.is_def_eq(t, s)
168}
169#[allow(dead_code)]
171pub fn is_def_eq_args(args1: &[Expr], args2: &[Expr], checker: &mut DefEqChecker<'_>) -> bool {
172 if args1.len() != args2.len() {
173 return false;
174 }
175 args1
176 .iter()
177 .zip(args2.iter())
178 .all(|(a, b)| checker.is_def_eq(a, b))
179}
180#[cfg(test)]
181mod extended_def_eq_tests {
182 use super::*;
183 use crate::{BinderInfo, Level, Literal, Name};
184 #[test]
185 fn test_syntactic_eq_lit() {
186 let a = Expr::Lit(Literal::nat(5));
187 let b = Expr::Lit(Literal::nat(5));
188 let c = Expr::Lit(Literal::nat(6));
189 assert!(syntactic_eq(&a, &b));
190 assert!(!syntactic_eq(&a, &c));
191 }
192 #[test]
193 fn test_syntactic_eq_bvar() {
194 assert!(syntactic_eq(&Expr::BVar(0), &Expr::BVar(0)));
195 assert!(!syntactic_eq(&Expr::BVar(0), &Expr::BVar(1)));
196 }
197 #[test]
198 fn test_syntactic_eq_const() {
199 let a = Expr::Const(Name::str("Nat"), vec![]);
200 let b = Expr::Const(Name::str("Nat"), vec![]);
201 let c = Expr::Const(Name::str("Bool"), vec![]);
202 assert!(syntactic_eq(&a, &b));
203 assert!(!syntactic_eq(&a, &c));
204 }
205 #[test]
206 fn test_batch_checker_basic() {
207 let env = Environment::new();
208 let mut batch = BatchDefEqChecker::new(&env);
209 let a = Expr::Lit(Literal::nat(1));
210 let b = Expr::Lit(Literal::nat(1));
211 let c = Expr::Lit(Literal::nat(2));
212 assert!(batch.check(&a, &b));
213 assert!(!batch.check(&a, &c));
214 }
215 #[test]
216 fn test_batch_check_all() {
217 let env = Environment::new();
218 let mut batch = BatchDefEqChecker::new(&env);
219 let pairs = vec![
220 (Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(1))),
221 (Expr::Lit(Literal::nat(2)), Expr::Lit(Literal::nat(2))),
222 ];
223 assert!(batch.check_all(&pairs));
224 }
225 #[test]
226 fn test_batch_check_all_fail() {
227 let env = Environment::new();
228 let mut batch = BatchDefEqChecker::new(&env);
229 let pairs = vec![
230 (Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(1))),
231 (Expr::Lit(Literal::nat(2)), Expr::Lit(Literal::nat(3))),
232 ];
233 assert!(!batch.check_all(&pairs));
234 }
235 #[test]
236 fn test_batch_count_equal() {
237 let env = Environment::new();
238 let mut batch = BatchDefEqChecker::new(&env);
239 let pairs = vec![
240 (Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(1))),
241 (Expr::Lit(Literal::nat(2)), Expr::Lit(Literal::nat(3))),
242 (Expr::Lit(Literal::nat(4)), Expr::Lit(Literal::nat(4))),
243 ];
244 assert_eq!(batch.count_equal(&pairs), 2);
245 }
246 #[test]
247 fn test_def_eq_config_default() {
248 let cfg = DefEqConfig::default();
249 assert!(cfg.proof_irrelevance);
250 assert!(cfg.eta);
251 assert!(cfg.lazy_delta);
252 }
253 #[test]
254 fn test_def_eq_config_opaque() {
255 let cfg = DefEqConfig::opaque();
256 assert!(!cfg.lazy_delta);
257 }
258 #[test]
259 fn test_def_eq_stats_hit_rate() {
260 let stats = DefEqStats {
261 cache_hits: 8,
262 cache_misses: 2,
263 ..Default::default()
264 };
265 assert!((stats.cache_hit_rate() - 0.8).abs() < 1e-10);
266 assert_eq!(stats.total_cache_accesses(), 10);
267 }
268 #[test]
269 fn test_def_eq_stats_no_accesses() {
270 let stats = DefEqStats::default();
271 assert_eq!(stats.cache_hit_rate(), 1.0);
272 assert_eq!(stats.total_reductions(), 0);
273 }
274 #[test]
275 fn test_is_def_eq_args_equal() {
276 let env = Environment::new();
277 let mut checker = DefEqChecker::new(&env);
278 let args1 = vec![Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(2))];
279 let args2 = vec![Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(2))];
280 assert!(is_def_eq_args(&args1, &args2, &mut checker));
281 }
282 #[test]
283 fn test_is_def_eq_args_different_lengths() {
284 let env = Environment::new();
285 let mut checker = DefEqChecker::new(&env);
286 let args1 = vec![Expr::Lit(Literal::nat(1))];
287 let args2 = vec![Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(2))];
288 assert!(!is_def_eq_args(&args1, &args2, &mut checker));
289 }
290 #[test]
291 fn test_syntactic_eq_app() {
292 let f = Expr::Const(Name::str("f"), vec![]);
293 let x = Expr::Lit(Literal::nat(1));
294 let app1 = Expr::App(Node::new(f.clone()), Node::new(x.clone()));
295 let app2 = Expr::App(Node::new(f), Node::new(x));
296 assert!(syntactic_eq(&app1, &app2));
297 }
298 #[test]
299 fn test_syntactic_eq_pi() {
300 let ty = Expr::Sort(Level::zero());
301 let pi1 = Expr::Pi(
302 BinderInfo::Default,
303 Name::str("x"),
304 Node::new(ty.clone()),
305 Node::new(ty.clone()),
306 );
307 let pi2 = Expr::Pi(
308 BinderInfo::Default,
309 Name::str("y"),
310 Node::new(ty.clone()),
311 Node::new(ty),
312 );
313 assert!(syntactic_eq(&pi1, &pi2));
314 }
315 #[test]
316 fn test_batch_check_any() {
317 let env = Environment::new();
318 let mut batch = BatchDefEqChecker::new(&env);
319 let pairs = vec![
320 (Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(2))),
321 (Expr::Lit(Literal::nat(3)), Expr::Lit(Literal::nat(3))),
322 ];
323 assert!(batch.check_any(&pairs));
324 }
325 fn make_proof_irrel_env() -> Environment {
330 use crate::{BinderInfo, Declaration, ReducibilityHint};
331 let mut env = Environment::new();
332 let prop = Expr::Sort(Level::zero());
333 env.add(Declaration::Axiom {
334 name: Name::str("TrueProp"),
335 univ_params: vec![],
336 ty: prop.clone(),
337 })
338 .expect("value should be present");
339 env.add(Declaration::Axiom {
340 name: Name::str("proof1"),
341 univ_params: vec![],
342 ty: Expr::Const(Name::str("TrueProp"), vec![]),
343 })
344 .expect("value should be present");
345 env.add(Declaration::Axiom {
346 name: Name::str("proof2"),
347 univ_params: vec![],
348 ty: Expr::Const(Name::str("TrueProp"), vec![]),
349 })
350 .expect("value should be present");
351 env.add(Declaration::Axiom {
352 name: Name::str("FalseProp"),
353 univ_params: vec![],
354 ty: prop.clone(),
355 })
356 .expect("value should be present");
357 env.add(Declaration::Axiom {
358 name: Name::str("bad_proof"),
359 univ_params: vec![],
360 ty: Expr::Const(Name::str("FalseProp"), vec![]),
361 })
362 .expect("value should be present");
363 env.add(Declaration::Axiom {
364 name: Name::str("SetProp"),
365 univ_params: vec![],
366 ty: Expr::Sort(Level::succ(Level::zero())),
367 })
368 .expect("value should be present");
369 env.add(Declaration::Axiom {
370 name: Name::str("set_elem1"),
371 univ_params: vec![],
372 ty: Expr::Const(Name::str("SetProp"), vec![]),
373 })
374 .expect("value should be present");
375 env.add(Declaration::Axiom {
376 name: Name::str("set_elem2"),
377 univ_params: vec![],
378 ty: Expr::Const(Name::str("SetProp"), vec![]),
379 })
380 .expect("value should be present");
381 let _ = BinderInfo::Default;
382 let _ = ReducibilityHint::Regular(1);
383 env
384 }
385 #[test]
386 fn test_proof_irrelevance_same_prop() {
387 let env = make_proof_irrel_env();
388 let mut checker = DefEqChecker::new(&env);
389 let p1 = Expr::Const(Name::str("proof1"), vec![]);
390 let p2 = Expr::Const(Name::str("proof2"), vec![]);
391 assert!(
392 checker.is_def_eq(&p1, &p2),
393 "Two proofs of TrueProp must be definitionally equal by proof irrelevance"
394 );
395 }
396 #[test]
397 fn test_proof_irrelevance_different_props() {
398 let env = make_proof_irrel_env();
399 let mut checker = DefEqChecker::new(&env);
400 let p1 = Expr::Const(Name::str("proof1"), vec![]);
401 let bad = Expr::Const(Name::str("bad_proof"), vec![]);
402 assert!(
403 !checker.is_def_eq(&p1, &bad),
404 "Proofs of different Props must NOT be identified by proof irrelevance"
405 );
406 }
407 #[test]
408 fn test_proof_irrelevance_disabled() {
409 let env = make_proof_irrel_env();
410 let mut checker = DefEqChecker::new(&env);
411 checker.set_proof_irrelevance(false);
412 let p1 = Expr::Const(Name::str("proof1"), vec![]);
413 let p2 = Expr::Const(Name::str("proof2"), vec![]);
414 assert!(
415 !checker.is_def_eq(&p1, &p2),
416 "With proof irrelevance disabled, distinct axioms must not be def-eq"
417 );
418 }
419 #[test]
420 fn test_proof_irrelevance_does_not_apply_to_types() {
421 let env = make_proof_irrel_env();
422 let mut checker = DefEqChecker::new(&env);
423 let e1 = Expr::Const(Name::str("set_elem1"), vec![]);
424 let e2 = Expr::Const(Name::str("set_elem2"), vec![]);
425 assert!(
426 !checker.is_def_eq(&e1, &e2),
427 "Terms of Sort 1 (Type) must NOT be identified by proof irrelevance"
428 );
429 }
430 #[test]
431 fn test_proof_irrelevance_self() {
432 let env = make_proof_irrel_env();
433 let mut checker = DefEqChecker::new(&env);
434 let p1 = Expr::Const(Name::str("proof1"), vec![]);
435 assert!(checker.is_def_eq(&p1, &p1));
436 }
437}
438#[allow(dead_code)]
440pub const MODULE_VERSION: &str = "1.0.0";
441#[allow(dead_code)]
445pub trait ModuleMarker: Sized + Clone + std::fmt::Debug {}
446#[allow(dead_code)]
448pub type ModuleResult<T> = Result<T, String>;
449#[allow(dead_code)]
451pub fn module_err(msg: impl Into<String>) -> String {
452 format!("[{module}] {msg}", module = "def_eq", msg = msg.into())
453}
454#[allow(dead_code)]
458pub fn levenshtein_distance(a: &str, b: &str) -> usize {
459 let la = a.len();
460 let lb = b.len();
461 if la == 0 {
462 return lb;
463 }
464 if lb == 0 {
465 return la;
466 }
467 let mut row: Vec<usize> = (0..=lb).collect();
468 for (i, ca) in a.chars().enumerate() {
469 let mut prev = i;
470 row[0] = i + 1;
471 for (j, cb) in b.chars().enumerate() {
472 let old = row[j + 1];
473 row[j + 1] = if ca == cb {
474 prev
475 } else {
476 1 + old.min(row[j]).min(prev)
477 };
478 prev = old;
479 }
480 }
481 row[lb]
482}
483#[allow(dead_code)]
487pub fn closest_match<'a>(query: &str, candidates: &[&'a str]) -> Option<&'a str> {
488 candidates
489 .iter()
490 .min_by_key(|&&c| levenshtein_distance(query, c))
491 .copied()
492}
493#[allow(dead_code)]
495pub fn format_name_list(names: &[&str]) -> String {
496 match names.len() {
497 0 => "(none)".to_string(),
498 1 => names[0].to_string(),
499 2 => format!("{} and {}", names[0], names[1]),
500 _ => {
501 let mut s = names[..names.len() - 1].join(", ");
502 s.push_str(", and ");
503 s.push_str(names[names.len() - 1]);
504 s
505 }
506 }
507}
508pub(super) fn collect_strings(node: &StringTrie, results: &mut Vec<String>) {
510 if let Some(v) = &node.value {
511 results.push(v.clone());
512 }
513 for child in node.children.values() {
514 collect_strings(child, results);
515 }
516}
517#[cfg(test)]
518mod utility_tests {
519 use super::*;
520 #[test]
521 fn test_levenshtein_same_string() {
522 assert_eq!(levenshtein_distance("hello", "hello"), 0);
523 }
524 #[test]
525 fn test_levenshtein_empty() {
526 assert_eq!(levenshtein_distance("", "abc"), 3);
527 assert_eq!(levenshtein_distance("abc", ""), 3);
528 }
529 #[test]
530 fn test_levenshtein_one_edit() {
531 assert_eq!(levenshtein_distance("cat", "bat"), 1);
532 assert_eq!(levenshtein_distance("cat", "cats"), 1);
533 assert_eq!(levenshtein_distance("cats", "cat"), 1);
534 }
535 #[test]
536 fn test_closest_match_found() {
537 let candidates = &["intro", "intros", "exact", "apply"];
538 let result = closest_match("intoo", candidates);
539 assert!(result.is_some());
540 assert_eq!(result.expect("result should be valid"), "intro");
541 }
542 #[test]
543 fn test_closest_match_empty() {
544 let result = closest_match("x", &[]);
545 assert!(result.is_none());
546 }
547 #[test]
548 fn test_format_name_list_empty() {
549 assert_eq!(format_name_list(&[]), "(none)");
550 }
551 #[test]
552 fn test_format_name_list_one() {
553 assert_eq!(format_name_list(&["foo"]), "foo");
554 }
555 #[test]
556 fn test_format_name_list_two() {
557 assert_eq!(format_name_list(&["a", "b"]), "a and b");
558 }
559 #[test]
560 fn test_format_name_list_many() {
561 let result = format_name_list(&["a", "b", "c"]);
562 assert!(result.contains("a"));
563 assert!(result.contains("b"));
564 assert!(result.contains("c"));
565 assert!(result.contains("and"));
566 }
567 #[test]
568 fn test_string_trie_insert_contains() {
569 let mut trie = StringTrie::new();
570 trie.insert("hello");
571 trie.insert("help");
572 trie.insert("world");
573 assert!(trie.contains("hello"));
574 assert!(trie.contains("help"));
575 assert!(trie.contains("world"));
576 assert!(!trie.contains("hell"));
577 assert_eq!(trie.len(), 3);
578 }
579 #[test]
580 fn test_string_trie_starts_with() {
581 let mut trie = StringTrie::new();
582 trie.insert("hello");
583 trie.insert("help");
584 trie.insert("world");
585 let results = trie.starts_with("hel");
586 assert_eq!(results.len(), 2);
587 }
588 #[test]
589 fn test_string_trie_empty_prefix() {
590 let mut trie = StringTrie::new();
591 trie.insert("a");
592 trie.insert("b");
593 let results = trie.starts_with("");
594 assert_eq!(results.len(), 2);
595 }
596 #[test]
597 fn test_name_index_basic() {
598 let mut idx = NameIndex::new();
599 let id1 = idx.insert("Nat");
600 let id2 = idx.insert("Bool");
601 let id3 = idx.insert("Nat");
602 assert_eq!(id1, id3);
603 assert_ne!(id1, id2);
604 assert_eq!(idx.len(), 2);
605 }
606 #[test]
607 fn test_name_index_get() {
608 let mut idx = NameIndex::new();
609 let id = idx.insert("test");
610 assert_eq!(idx.get_id("test"), Some(id));
611 assert_eq!(idx.get_name(id), Some("test"));
612 assert_eq!(idx.get_id("missing"), None);
613 }
614 #[test]
615 fn test_name_index_empty() {
616 let idx = NameIndex::new();
617 assert!(idx.is_empty());
618 assert_eq!(idx.len(), 0);
619 }
620}
621#[cfg(test)]
622mod tests_padding_infra {
623 use super::*;
624 #[test]
625 fn test_stat_summary() {
626 let mut ss = StatSummary::new();
627 ss.record(10.0);
628 ss.record(20.0);
629 ss.record(30.0);
630 assert_eq!(ss.count(), 3);
631 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
632 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
633 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
634 }
635 #[test]
636 fn test_transform_stat() {
637 let mut ts = TransformStat::new();
638 ts.record_before(100.0);
639 ts.record_after(80.0);
640 let ratio = ts.mean_ratio().expect("ratio should be present");
641 assert!((ratio - 0.8).abs() < 1e-9);
642 }
643 #[test]
644 fn test_small_map() {
645 let mut m: SmallMap<u32, &str> = SmallMap::new();
646 m.insert(3, "three");
647 m.insert(1, "one");
648 m.insert(2, "two");
649 assert_eq!(m.get(&2), Some(&"two"));
650 assert_eq!(m.len(), 3);
651 let keys = m.keys();
652 assert_eq!(*keys[0], 1);
653 assert_eq!(*keys[2], 3);
654 }
655 #[test]
656 fn test_label_set() {
657 let mut ls = LabelSet::new();
658 ls.add("foo");
659 ls.add("bar");
660 ls.add("foo");
661 assert_eq!(ls.count(), 2);
662 assert!(ls.has("bar"));
663 assert!(!ls.has("baz"));
664 }
665 #[test]
666 fn test_config_node() {
667 let mut root = ConfigNode::section("root");
668 let child = ConfigNode::leaf("key", "value");
669 root.add_child(child);
670 assert_eq!(root.num_children(), 1);
671 }
672 #[test]
673 fn test_versioned_record() {
674 let mut vr = VersionedRecord::new(0u32);
675 vr.update(1);
676 vr.update(2);
677 assert_eq!(*vr.current(), 2);
678 assert_eq!(vr.version(), 2);
679 assert!(vr.has_history());
680 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
681 }
682 #[test]
683 fn test_simple_dag() {
684 let mut dag = SimpleDag::new(4);
685 dag.add_edge(0, 1);
686 dag.add_edge(1, 2);
687 dag.add_edge(2, 3);
688 assert!(dag.can_reach(0, 3));
689 assert!(!dag.can_reach(3, 0));
690 let order = dag.topological_sort().expect("order should be present");
691 assert_eq!(order, vec![0, 1, 2, 3]);
692 }
693 #[test]
694 fn test_focus_stack() {
695 let mut fs: FocusStack<&str> = FocusStack::new();
696 fs.focus("a");
697 fs.focus("b");
698 assert_eq!(fs.current(), Some(&"b"));
699 assert_eq!(fs.depth(), 2);
700 fs.blur();
701 assert_eq!(fs.current(), Some(&"a"));
702 }
703}
704#[cfg(test)]
705mod tests_extra_iterators {
706 use super::*;
707 #[test]
708 fn test_window_iterator() {
709 let data = vec![1u32, 2, 3, 4, 5];
710 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
711 assert_eq!(windows.len(), 3);
712 assert_eq!(windows[0], &[1, 2, 3]);
713 assert_eq!(windows[2], &[3, 4, 5]);
714 }
715 #[test]
716 fn test_non_empty_vec() {
717 let mut nev = NonEmptyVec::singleton(10u32);
718 nev.push(20);
719 nev.push(30);
720 assert_eq!(nev.len(), 3);
721 assert_eq!(*nev.first(), 10);
722 assert_eq!(*nev.last(), 30);
723 }
724}
725#[cfg(test)]
726mod tests_padding2 {
727 use super::*;
728 #[test]
729 fn test_sliding_sum() {
730 let mut ss = SlidingSum::new(3);
731 ss.push(1.0);
732 ss.push(2.0);
733 ss.push(3.0);
734 assert!((ss.sum() - 6.0).abs() < 1e-9);
735 ss.push(4.0);
736 assert!((ss.sum() - 9.0).abs() < 1e-9);
737 assert_eq!(ss.count(), 3);
738 }
739 #[test]
740 fn test_path_buf() {
741 let mut pb = PathBuf::new();
742 pb.push("src");
743 pb.push("main");
744 assert_eq!(pb.as_str(), "src/main");
745 assert_eq!(pb.depth(), 2);
746 pb.pop();
747 assert_eq!(pb.as_str(), "src");
748 }
749 #[test]
750 fn test_string_pool() {
751 let mut pool = StringPool::new();
752 let s = pool.take();
753 assert!(s.is_empty());
754 pool.give("hello".to_string());
755 let s2 = pool.take();
756 assert!(s2.is_empty());
757 assert_eq!(pool.free_count(), 0);
758 }
759 #[test]
760 fn test_transitive_closure() {
761 let mut tc = TransitiveClosure::new(4);
762 tc.add_edge(0, 1);
763 tc.add_edge(1, 2);
764 tc.add_edge(2, 3);
765 assert!(tc.can_reach(0, 3));
766 assert!(!tc.can_reach(3, 0));
767 let r = tc.reachable_from(0);
768 assert_eq!(r.len(), 4);
769 }
770 #[test]
771 fn test_token_bucket() {
772 let mut tb = TokenBucket::new(100, 0);
773 assert_eq!(tb.available(), 100);
774 assert!(tb.try_consume(50));
775 assert_eq!(tb.available(), 50);
776 assert!(!tb.try_consume(60));
777 assert_eq!(tb.capacity(), 100);
778 }
779 #[test]
780 fn test_rewrite_rule_set() {
781 let mut rrs = RewriteRuleSet::new();
782 rrs.add(RewriteRule::unconditional(
783 "beta",
784 "App(Lam(x, b), v)",
785 "b[x:=v]",
786 ));
787 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
788 assert_eq!(rrs.len(), 2);
789 assert_eq!(rrs.unconditional_rules().len(), 1);
790 assert_eq!(rrs.conditional_rules().len(), 1);
791 assert!(rrs.get("beta").is_some());
792 let disp = rrs
793 .get("beta")
794 .expect("element at \'beta\' should exist")
795 .display();
796 assert!(disp.contains("→"));
797 }
798}
799#[cfg(test)]
800mod tests_padding3 {
801 use super::*;
802 #[test]
803 fn test_decision_node() {
804 let tree = DecisionNode::Branch {
805 key: "x".into(),
806 val: "1".into(),
807 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
808 no_branch: Box::new(DecisionNode::Leaf("no".into())),
809 };
810 let mut ctx = std::collections::HashMap::new();
811 ctx.insert("x".into(), "1".into());
812 assert_eq!(tree.evaluate(&ctx), "yes");
813 ctx.insert("x".into(), "2".into());
814 assert_eq!(tree.evaluate(&ctx), "no");
815 assert_eq!(tree.depth(), 1);
816 }
817 #[test]
818 fn test_flat_substitution() {
819 let mut sub = FlatSubstitution::new();
820 sub.add("foo", "bar");
821 sub.add("baz", "qux");
822 assert_eq!(sub.apply("foo and baz"), "bar and qux");
823 assert_eq!(sub.len(), 2);
824 }
825 #[test]
826 fn test_stopwatch() {
827 let mut sw = Stopwatch::start();
828 sw.split();
829 sw.split();
830 assert_eq!(sw.num_splits(), 2);
831 assert!(sw.elapsed_ms() >= 0.0);
832 for &s in sw.splits() {
833 assert!(s >= 0.0);
834 }
835 }
836 #[test]
837 fn test_either2() {
838 let e: Either2<i32, &str> = Either2::First(42);
839 assert!(e.is_first());
840 let mapped = e.map_first(|x| x * 2);
841 assert_eq!(mapped.first(), Some(84));
842 let e2: Either2<i32, &str> = Either2::Second("hello");
843 assert!(e2.is_second());
844 assert_eq!(e2.second(), Some("hello"));
845 }
846 #[test]
847 fn test_write_once() {
848 let wo: WriteOnce<u32> = WriteOnce::new();
849 assert!(!wo.is_written());
850 assert!(wo.write(42));
851 assert!(!wo.write(99));
852 assert_eq!(wo.read(), Some(42));
853 }
854 #[test]
855 fn test_sparse_vec() {
856 let mut sv: SparseVec<i32> = SparseVec::new(100);
857 sv.set(5, 10);
858 sv.set(50, 20);
859 assert_eq!(*sv.get(5), 10);
860 assert_eq!(*sv.get(50), 20);
861 assert_eq!(*sv.get(0), 0);
862 assert_eq!(sv.nnz(), 2);
863 sv.set(5, 0);
864 assert_eq!(sv.nnz(), 1);
865 }
866 #[test]
867 fn test_stack_calc() {
868 let mut calc = StackCalc::new();
869 calc.push(3);
870 calc.push(4);
871 assert_eq!(calc.add(), Some(7));
872 assert_eq!(calc.peek(), Some(7));
873 calc.push(2);
874 assert_eq!(calc.mul(), Some(14));
875 assert_eq!(calc.peek(), Some(14));
876 }
877}