1use super::{Brick, BrickError};
36use std::collections::HashMap;
37use std::time::Duration;
38
39pub trait DeterministicBrick: Brick {
41 type State: Clone + Default;
43 type Input;
45 type Output;
47
48 fn execute_pure(
55 state: Self::State,
56 input: Self::Input,
57 ) -> Result<(Self::State, Self::Output), BrickError>;
58
59 fn initial_state() -> Self::State {
61 Self::State::default()
62 }
63
64 fn state_dependencies(&self) -> &[&str] {
66 &[]
67 }
68}
69
70#[derive(Debug, Clone)]
72pub struct BrickState {
73 pub tensors: HashMap<String, Vec<f32>>,
75 pub shapes: HashMap<String, Vec<usize>>,
77 pub metadata: HashMap<String, StateValue>,
79 pub version: u64,
81}
82
83#[derive(Debug, Clone, PartialEq)]
85pub enum StateValue {
86 Int(i64),
88 Float(f64),
90 String(String),
92 Bool(bool),
94}
95
96impl BrickState {
97 #[must_use]
99 pub fn new() -> Self {
100 Self {
101 tensors: HashMap::new(),
102 shapes: HashMap::new(),
103 metadata: HashMap::new(),
104 version: 0,
105 }
106 }
107
108 #[must_use]
110 pub fn snapshot(&self) -> Self {
111 let mut snap = self.clone();
112 snap.version = self.version + 1;
113 snap
114 }
115
116 pub fn set_tensor(&mut self, name: impl Into<String>, data: Vec<f32>, shape: Vec<usize>) {
118 let name = name.into();
119 self.tensors.insert(name.clone(), data);
120 self.shapes.insert(name, shape);
121 }
122
123 pub fn get_tensor(&self, name: &str) -> Option<(&[f32], &[usize])> {
125 let data = self.tensors.get(name)?;
126 let shape = self.shapes.get(name)?;
127 Some((data, shape))
128 }
129
130 pub fn set_metadata(&mut self, key: impl Into<String>, value: StateValue) {
132 self.metadata.insert(key.into(), value);
133 }
134
135 pub fn get_metadata(&self, key: &str) -> Option<&StateValue> {
137 self.metadata.get(key)
138 }
139}
140
141impl Default for BrickState {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147#[derive(Debug, Clone)]
149pub struct ExecutionTrace {
150 pub operation: String,
152 pub input_summary: String,
154 pub output_summary: String,
156 pub duration: Duration,
158 pub state_version_before: u64,
160 pub state_version_after: u64,
162}
163
164#[derive(Debug)]
166pub struct BrickHistory {
167 snapshots: Vec<BrickState>,
169 traces: Vec<ExecutionTrace>,
171 position: usize,
173 max_size: usize,
175}
176
177impl BrickHistory {
178 #[must_use]
180 pub fn new(max_size: usize) -> Self {
181 Self {
182 snapshots: Vec::with_capacity(max_size),
183 traces: Vec::with_capacity(max_size),
184 position: 0,
185 max_size,
186 }
187 }
188
189 pub fn record(&mut self, state: BrickState, trace: ExecutionTrace) {
191 if self.position < self.snapshots.len() {
193 self.snapshots.truncate(self.position);
194 self.traces.truncate(self.position);
195 }
196
197 if self.snapshots.len() >= self.max_size {
199 self.snapshots.remove(0);
200 self.traces.remove(0);
201 }
202
203 self.snapshots.push(state);
204 self.traces.push(trace);
205 self.position = self.snapshots.len();
206 }
207
208 pub fn step_back(&mut self) -> Option<&BrickState> {
210 if self.position > 0 {
211 self.position -= 1;
212 self.snapshots.get(self.position)
213 } else {
214 None
215 }
216 }
217
218 pub fn step_forward(&mut self) -> Option<&BrickState> {
220 if self.position < self.snapshots.len() {
221 let state = self.snapshots.get(self.position);
222 self.position += 1;
223 state
224 } else {
225 None
226 }
227 }
228
229 pub fn goto(&mut self, position: usize) -> Option<&BrickState> {
231 if position < self.snapshots.len() {
232 self.position = position;
233 self.snapshots.get(position)
234 } else {
235 None
236 }
237 }
238
239 pub fn current(&self) -> Option<&BrickState> {
241 if self.position > 0 && self.position <= self.snapshots.len() {
242 self.snapshots.get(self.position - 1)
243 } else {
244 self.snapshots.first()
245 }
246 }
247
248 #[must_use]
250 pub fn position(&self) -> usize {
251 self.position
252 }
253
254 #[must_use]
256 pub fn len(&self) -> usize {
257 self.snapshots.len()
258 }
259
260 #[must_use]
262 pub fn is_empty(&self) -> bool {
263 self.snapshots.is_empty()
264 }
265
266 pub fn trace_at(&self, position: usize) -> Option<&ExecutionTrace> {
268 self.traces.get(position)
269 }
270
271 pub fn traces(&self) -> &[ExecutionTrace] {
273 &self.traces
274 }
275}
276
277impl Default for BrickHistory {
278 fn default() -> Self {
279 Self::new(1000)
280 }
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
285pub enum GuardSeverity {
286 Warning,
288 Error,
290 Critical,
292}
293
294pub struct InvariantGuard {
296 pub name: &'static str,
298 pub check: fn(&BrickState) -> bool,
300 pub severity: GuardSeverity,
302}
303
304impl std::fmt::Debug for InvariantGuard {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 f.debug_struct("InvariantGuard")
307 .field("name", &self.name)
308 .field("check", &"<fn>")
309 .field("severity", &self.severity)
310 .finish()
311 }
312}
313
314impl InvariantGuard {
315 #[must_use]
317 pub const fn new(
318 name: &'static str,
319 check: fn(&BrickState) -> bool,
320 severity: GuardSeverity,
321 ) -> Self {
322 Self {
323 name,
324 check,
325 severity,
326 }
327 }
328
329 pub fn check(&self, state: &BrickState) -> bool {
331 (self.check)(state)
332 }
333}
334
335#[derive(Debug)]
337pub struct GuardedBrick<B: Brick> {
338 inner: B,
340 guards: Vec<InvariantGuard>,
342}
343
344impl<B: Brick> GuardedBrick<B> {
345 #[must_use]
347 pub fn new(brick: B) -> Self {
348 Self {
349 inner: brick,
350 guards: Vec::new(),
351 }
352 }
353
354 #[must_use]
356 pub fn guard(mut self, guard: InvariantGuard) -> Self {
357 self.guards.push(guard);
358 self
359 }
360
361 pub fn check_guards(&self, state: &BrickState) -> Result<(), GuardViolation> {
363 for guard in &self.guards {
364 if !guard.check(state) {
365 return Err(GuardViolation {
366 guard_name: guard.name,
367 severity: guard.severity,
368 });
369 }
370 }
371 Ok(())
372 }
373
374 pub fn inner(&self) -> &B {
376 &self.inner
377 }
378
379 pub fn guards(&self) -> &[InvariantGuard] {
381 &self.guards
382 }
383}
384
385#[derive(Debug, Clone)]
387pub struct GuardViolation {
388 pub guard_name: &'static str,
390 pub severity: GuardSeverity,
392}
393
394impl std::fmt::Display for GuardViolation {
395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396 write!(
397 f,
398 "Invariant guard '{}' violated (severity: {:?})",
399 self.guard_name, self.severity
400 )
401 }
402}
403
404impl std::error::Error for GuardViolation {}
405
406#[derive(Debug, Clone)]
408pub struct DeterministicRng {
409 state: u64,
410}
411
412impl DeterministicRng {
413 #[must_use]
415 pub const fn new(seed: u64) -> Self {
416 Self { state: seed }
417 }
418
419 pub fn next_u64(&mut self) -> u64 {
421 self.state ^= self.state << 13;
423 self.state ^= self.state >> 7;
424 self.state ^= self.state << 17;
425 self.state
426 }
427
428 pub fn next_f64(&mut self) -> f64 {
430 (self.next_u64() >> 11) as f64 / ((1u64 << 53) as f64)
431 }
432
433 pub fn next_f32(&mut self) -> f32 {
435 self.next_f64() as f32
436 }
437
438 #[must_use]
440 pub const fn state(&self) -> u64 {
441 self.state
442 }
443
444 pub fn restore(&mut self, state: u64) {
446 self.state = state;
447 }
448}
449
450impl Default for DeterministicRng {
451 fn default() -> Self {
452 Self::new(42)
453 }
454}
455
456#[derive(Debug, Clone)]
458pub struct DeterministicClock {
459 current_ns: u64,
461 tick_ns: u64,
463}
464
465impl DeterministicClock {
466 #[must_use]
468 pub const fn new(start_ns: u64, tick_ns: u64) -> Self {
469 Self {
470 current_ns: start_ns,
471 tick_ns,
472 }
473 }
474
475 #[must_use]
477 pub const fn now_ns(&self) -> u64 {
478 self.current_ns
479 }
480
481 #[must_use]
483 pub const fn now(&self) -> Duration {
484 Duration::from_nanos(self.current_ns)
485 }
486
487 pub fn tick(&mut self) {
489 self.current_ns += self.tick_ns;
490 }
491
492 pub fn advance(&mut self, ticks: u64) {
494 self.current_ns += self.tick_ns * ticks;
495 }
496
497 pub fn set(&mut self, time_ns: u64) {
499 self.current_ns = time_ns;
500 }
501}
502
503impl Default for DeterministicClock {
504 fn default() -> Self {
505 Self::new(0, 10_000_000)
507 }
508}
509
510#[cfg(test)]
511#[allow(clippy::unwrap_used, clippy::expect_used)]
512mod tests {
513 use super::*;
514
515 #[test]
516 fn test_brick_state_basic() {
517 let mut state = BrickState::new();
518 state.set_tensor("audio", vec![1.0, 2.0, 3.0], vec![3]);
519 state.set_metadata("frame_count", StateValue::Int(42));
520
521 let (data, shape) = state.get_tensor("audio").unwrap();
522 assert_eq!(data, &[1.0, 2.0, 3.0]);
523 assert_eq!(shape, &[3]);
524
525 assert_eq!(
526 state.get_metadata("frame_count"),
527 Some(&StateValue::Int(42))
528 );
529 }
530
531 #[test]
532 fn test_brick_state_snapshot() {
533 let mut state = BrickState::new();
534 state.set_metadata("count", StateValue::Int(1));
535
536 let snap = state.snapshot();
537 assert_eq!(snap.version, 1);
538 assert_eq!(snap.get_metadata("count"), Some(&StateValue::Int(1)));
539 }
540
541 #[test]
542 fn test_brick_history_forward() {
543 let mut history = BrickHistory::new(10);
544
545 for i in 0..5 {
546 let mut state = BrickState::new();
547 state.version = i;
548 state.set_metadata("step", StateValue::Int(i as i64));
549
550 let trace = ExecutionTrace {
551 operation: format!("step_{}", i),
552 input_summary: String::new(),
553 output_summary: String::new(),
554 duration: Duration::from_millis(1),
555 state_version_before: i,
556 state_version_after: i + 1,
557 };
558
559 history.record(state, trace);
560 }
561
562 assert_eq!(history.len(), 5);
563 assert_eq!(history.position(), 5);
564 }
565
566 #[test]
567 fn test_brick_history_time_travel() {
568 let mut history = BrickHistory::new(10);
569
570 for i in 0..3 {
572 let mut state = BrickState::new();
573 state.set_metadata("value", StateValue::Int(i as i64));
574
575 let trace = ExecutionTrace {
576 operation: format!("op_{}", i),
577 input_summary: String::new(),
578 output_summary: String::new(),
579 duration: Duration::from_millis(1),
580 state_version_before: i as u64,
581 state_version_after: (i + 1) as u64,
582 };
583
584 history.record(state, trace);
585 }
586
587 assert_eq!(history.position(), 3);
589
590 let state = history.step_back().unwrap();
592 assert_eq!(state.get_metadata("value"), Some(&StateValue::Int(2)));
593 assert_eq!(history.position(), 2);
594
595 let state = history.step_back().unwrap();
597 assert_eq!(state.get_metadata("value"), Some(&StateValue::Int(1)));
598 assert_eq!(history.position(), 1);
599
600 let state = history.step_forward().unwrap();
602 assert_eq!(state.get_metadata("value"), Some(&StateValue::Int(1)));
603 assert_eq!(history.position(), 2);
604 }
605
606 #[test]
607 fn test_brick_history_goto() {
608 let mut history = BrickHistory::new(10);
609
610 for i in 0..5 {
611 let mut state = BrickState::new();
612 state.set_metadata("index", StateValue::Int(i as i64));
613
614 let trace = ExecutionTrace {
615 operation: format!("op_{}", i),
616 input_summary: String::new(),
617 output_summary: String::new(),
618 duration: Duration::from_millis(1),
619 state_version_before: i as u64,
620 state_version_after: (i + 1) as u64,
621 };
622
623 history.record(state, trace);
624 }
625
626 let state = history.goto(2).unwrap();
627 assert_eq!(state.get_metadata("index"), Some(&StateValue::Int(2)));
628 assert_eq!(history.position(), 2);
629 }
630
631 #[test]
632 fn test_invariant_guard() {
633 fn check_positive(state: &BrickState) -> bool {
634 match state.get_metadata("count") {
635 Some(StateValue::Int(n)) => *n >= 0,
636 _ => true,
637 }
638 }
639
640 let guard = InvariantGuard::new("positive_count", check_positive, GuardSeverity::Error);
641
642 let mut state = BrickState::new();
643 state.set_metadata("count", StateValue::Int(5));
644 assert!(guard.check(&state));
645
646 state.set_metadata("count", StateValue::Int(-1));
647 assert!(!guard.check(&state));
648 }
649
650 #[test]
651 fn test_deterministic_rng() {
652 let mut rng1 = DeterministicRng::new(12345);
653 let mut rng2 = DeterministicRng::new(12345);
654
655 for _ in 0..100 {
657 assert_eq!(rng1.next_u64(), rng2.next_u64());
658 }
659 }
660
661 #[test]
662 fn test_deterministic_rng_f64_range() {
663 let mut rng = DeterministicRng::new(42);
664
665 for _ in 0..1000 {
666 let val = rng.next_f64();
667 assert!((0.0..1.0).contains(&val));
668 }
669 }
670
671 #[test]
672 fn test_deterministic_clock() {
673 let mut clock = DeterministicClock::new(0, 1_000_000); assert_eq!(clock.now_ns(), 0);
676
677 clock.tick();
678 assert_eq!(clock.now_ns(), 1_000_000);
679
680 clock.advance(10);
681 assert_eq!(clock.now_ns(), 11_000_000);
682 assert_eq!(clock.now(), Duration::from_millis(11));
683 }
684
685 #[test]
686 fn test_deterministic_clock_replay() {
687 let mut clock = DeterministicClock::new(0, 1_000_000);
688
689 clock.advance(100);
690 assert_eq!(clock.now_ns(), 100_000_000);
691
692 clock.set(0);
694 assert_eq!(clock.now_ns(), 0);
695 }
696
697 #[test]
698 fn test_state_value_variants() {
699 let int_val = StateValue::Int(42);
700 let float_val = StateValue::Float(3.14);
701 let string_val = StateValue::String("hello".into());
702 let bool_val = StateValue::Bool(true);
703
704 assert_eq!(int_val, StateValue::Int(42));
705 assert_eq!(float_val, StateValue::Float(3.14));
706 assert_eq!(string_val, StateValue::String("hello".into()));
707 assert_eq!(bool_val, StateValue::Bool(true));
708 }
709
710 #[test]
715 fn test_brick_state_default() {
716 let state = BrickState::default();
717 assert!(state.tensors.is_empty());
718 assert!(state.shapes.is_empty());
719 assert!(state.metadata.is_empty());
720 assert_eq!(state.version, 0);
721 }
722
723 #[test]
724 fn test_brick_state_get_tensor_nonexistent() {
725 let state = BrickState::new();
726 assert!(state.get_tensor("nonexistent").is_none());
727 }
728
729 #[test]
730 fn test_brick_state_get_metadata_nonexistent() {
731 let state = BrickState::new();
732 assert!(state.get_metadata("nonexistent").is_none());
733 }
734
735 #[test]
736 fn test_brick_state_tensor_missing_shape() {
737 let mut state = BrickState::new();
738 state.tensors.insert("data".into(), vec![1.0, 2.0]);
739 assert!(state.get_tensor("data").is_none());
741 }
742
743 #[test]
744 fn test_brick_state_clone() {
745 let mut state = BrickState::new();
746 state.set_tensor("t1", vec![1.0], vec![1]);
747 state.set_metadata("m1", StateValue::Bool(true));
748 state.version = 5;
749
750 let cloned = state.clone();
751 assert_eq!(cloned.version, 5);
752 assert_eq!(cloned.get_tensor("t1").unwrap().0, &[1.0]);
753 assert_eq!(cloned.get_metadata("m1"), Some(&StateValue::Bool(true)));
754 }
755
756 #[test]
757 fn test_state_value_clone() {
758 let val = StateValue::String("test".into());
759 let cloned = val.clone();
760 assert_eq!(val, cloned);
761 }
762
763 #[test]
764 fn test_state_value_partial_eq() {
765 assert_ne!(StateValue::Int(1), StateValue::Int(2));
766 assert_ne!(StateValue::Float(1.0), StateValue::Float(2.0));
767 assert_ne!(StateValue::Bool(true), StateValue::Bool(false));
768 assert_ne!(
769 StateValue::String("a".into()),
770 StateValue::String("b".into())
771 );
772 }
773
774 #[test]
775 fn test_execution_trace_clone() {
776 let trace = ExecutionTrace {
777 operation: "test".into(),
778 input_summary: "in".into(),
779 output_summary: "out".into(),
780 duration: Duration::from_secs(1),
781 state_version_before: 0,
782 state_version_after: 1,
783 };
784 let cloned = trace.clone();
785 assert_eq!(trace.operation, cloned.operation);
786 assert_eq!(trace.duration, cloned.duration);
787 }
788
789 #[test]
790 fn test_brick_history_default() {
791 let history = BrickHistory::default();
792 assert!(history.is_empty());
793 assert_eq!(history.len(), 0);
794 assert_eq!(history.position(), 0);
795 }
796
797 #[test]
798 fn test_brick_history_is_empty() {
799 let mut history = BrickHistory::new(10);
800 assert!(history.is_empty());
801
802 let state = BrickState::new();
803 let trace = ExecutionTrace {
804 operation: "op".into(),
805 input_summary: String::new(),
806 output_summary: String::new(),
807 duration: Duration::ZERO,
808 state_version_before: 0,
809 state_version_after: 1,
810 };
811 history.record(state, trace);
812 assert!(!history.is_empty());
813 }
814
815 #[test]
816 fn test_brick_history_step_back_empty() {
817 let mut history = BrickHistory::new(10);
818 assert!(history.step_back().is_none());
819 }
820
821 #[test]
822 fn test_brick_history_step_back_at_start() {
823 let mut history = BrickHistory::new(10);
824
825 let state = BrickState::new();
826 let trace = ExecutionTrace {
827 operation: "op".into(),
828 input_summary: String::new(),
829 output_summary: String::new(),
830 duration: Duration::ZERO,
831 state_version_before: 0,
832 state_version_after: 1,
833 };
834 history.record(state, trace);
835
836 history.position = 0;
838 assert!(history.step_back().is_none());
839 }
840
841 #[test]
842 fn test_brick_history_step_forward_at_end() {
843 let mut history = BrickHistory::new(10);
844
845 let state = BrickState::new();
846 let trace = ExecutionTrace {
847 operation: "op".into(),
848 input_summary: String::new(),
849 output_summary: String::new(),
850 duration: Duration::ZERO,
851 state_version_before: 0,
852 state_version_after: 1,
853 };
854 history.record(state, trace);
855
856 assert!(history.step_forward().is_none());
858 }
859
860 #[test]
861 fn test_brick_history_goto_invalid() {
862 let mut history = BrickHistory::new(10);
863 assert!(history.goto(100).is_none());
864 }
865
866 #[test]
867 fn test_brick_history_current_empty() {
868 let history = BrickHistory::new(10);
869 assert!(history.current().is_none());
870 }
871
872 #[test]
873 fn test_brick_history_current_at_start() {
874 let mut history = BrickHistory::new(10);
875
876 let mut state = BrickState::new();
877 state.set_metadata("val", StateValue::Int(1));
878 let trace = ExecutionTrace {
879 operation: "op".into(),
880 input_summary: String::new(),
881 output_summary: String::new(),
882 duration: Duration::ZERO,
883 state_version_before: 0,
884 state_version_after: 1,
885 };
886 history.record(state, trace);
887
888 let current = history.current();
890 assert!(current.is_some());
891 assert_eq!(
892 current.unwrap().get_metadata("val"),
893 Some(&StateValue::Int(1))
894 );
895 }
896
897 #[test]
898 fn test_brick_history_current_position_zero() {
899 let mut history = BrickHistory::new(10);
900
901 let state = BrickState::new();
902 let trace = ExecutionTrace {
903 operation: "op".into(),
904 input_summary: String::new(),
905 output_summary: String::new(),
906 duration: Duration::ZERO,
907 state_version_before: 0,
908 state_version_after: 1,
909 };
910 history.record(state, trace);
911
912 history.position = 0;
914 assert!(history.current().is_some());
915 }
916
917 #[test]
918 fn test_brick_history_trace_at() {
919 let mut history = BrickHistory::new(10);
920
921 let state = BrickState::new();
922 let trace = ExecutionTrace {
923 operation: "test_op".into(),
924 input_summary: "input".into(),
925 output_summary: "output".into(),
926 duration: Duration::from_secs(2),
927 state_version_before: 0,
928 state_version_after: 1,
929 };
930 history.record(state, trace);
931
932 let retrieved = history.trace_at(0);
933 assert!(retrieved.is_some());
934 assert_eq!(retrieved.unwrap().operation, "test_op");
935 }
936
937 #[test]
938 fn test_brick_history_trace_at_invalid() {
939 let history = BrickHistory::new(10);
940 assert!(history.trace_at(100).is_none());
941 }
942
943 #[test]
944 fn test_brick_history_traces() {
945 let mut history = BrickHistory::new(10);
946
947 for i in 0..3 {
948 let state = BrickState::new();
949 let trace = ExecutionTrace {
950 operation: format!("op_{}", i),
951 input_summary: String::new(),
952 output_summary: String::new(),
953 duration: Duration::ZERO,
954 state_version_before: i as u64,
955 state_version_after: (i + 1) as u64,
956 };
957 history.record(state, trace);
958 }
959
960 let traces = history.traces();
961 assert_eq!(traces.len(), 3);
962 assert_eq!(traces[0].operation, "op_0");
963 assert_eq!(traces[2].operation, "op_2");
964 }
965
966 #[test]
967 fn test_brick_history_record_truncates_forward() {
968 let mut history = BrickHistory::new(10);
969
970 for i in 0..5 {
972 let mut state = BrickState::new();
973 state.set_metadata("i", StateValue::Int(i));
974 let trace = ExecutionTrace {
975 operation: format!("op_{}", i),
976 input_summary: String::new(),
977 output_summary: String::new(),
978 duration: Duration::ZERO,
979 state_version_before: i as u64,
980 state_version_after: (i + 1) as u64,
981 };
982 history.record(state, trace);
983 }
984
985 history.goto(2);
987
988 let mut new_state = BrickState::new();
990 new_state.set_metadata("new", StateValue::Bool(true));
991 let trace = ExecutionTrace {
992 operation: "new_op".into(),
993 input_summary: String::new(),
994 output_summary: String::new(),
995 duration: Duration::ZERO,
996 state_version_before: 2,
997 state_version_after: 3,
998 };
999 history.record(new_state, trace);
1000
1001 assert_eq!(history.len(), 3);
1003 }
1004
1005 #[test]
1006 fn test_brick_history_capacity_eviction() {
1007 let mut history = BrickHistory::new(3); for i in 0..5 {
1011 let mut state = BrickState::new();
1012 state.set_metadata("i", StateValue::Int(i));
1013 let trace = ExecutionTrace {
1014 operation: format!("op_{}", i),
1015 input_summary: String::new(),
1016 output_summary: String::new(),
1017 duration: Duration::ZERO,
1018 state_version_before: i as u64,
1019 state_version_after: (i + 1) as u64,
1020 };
1021 history.record(state, trace);
1022 }
1023
1024 assert_eq!(history.len(), 3);
1026
1027 let first = history.goto(0).unwrap();
1029 assert_eq!(first.get_metadata("i"), Some(&StateValue::Int(2)));
1030 }
1031
1032 #[test]
1033 fn test_guard_severity_values() {
1034 assert_eq!(GuardSeverity::Warning, GuardSeverity::Warning);
1035 assert_eq!(GuardSeverity::Error, GuardSeverity::Error);
1036 assert_eq!(GuardSeverity::Critical, GuardSeverity::Critical);
1037 assert_ne!(GuardSeverity::Warning, GuardSeverity::Error);
1038 }
1039
1040 #[test]
1041 fn test_invariant_guard_debug() {
1042 fn check(_: &BrickState) -> bool {
1043 true
1044 }
1045 let guard = InvariantGuard::new("test", check, GuardSeverity::Warning);
1046 let debug_str = format!("{:?}", guard);
1047 assert!(debug_str.contains("InvariantGuard"));
1048 assert!(debug_str.contains("test"));
1049 }
1050
1051 #[test]
1052 fn test_guarded_brick() {
1053 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1054
1055 struct TestBrick;
1056 impl Brick for TestBrick {
1057 fn brick_name(&self) -> &'static str {
1058 "TestBrick"
1059 }
1060 fn assertions(&self) -> &[BrickAssertion] {
1061 &[]
1062 }
1063 fn budget(&self) -> BrickBudget {
1064 BrickBudget::uniform(16)
1065 }
1066 fn verify(&self) -> BrickVerification {
1067 BrickVerification {
1068 passed: vec![],
1069 failed: vec![],
1070 verification_time: Duration::ZERO,
1071 }
1072 }
1073 fn to_html(&self) -> String {
1074 String::new()
1075 }
1076 fn to_css(&self) -> String {
1077 String::new()
1078 }
1079 }
1080
1081 fn check_positive(state: &BrickState) -> bool {
1082 match state.get_metadata("count") {
1083 Some(StateValue::Int(n)) => *n >= 0,
1084 _ => true,
1085 }
1086 }
1087
1088 let guard = InvariantGuard::new("positive", check_positive, GuardSeverity::Error);
1089 let guarded = GuardedBrick::new(TestBrick).guard(guard);
1090
1091 assert_eq!(guarded.inner().brick_name(), "TestBrick");
1092 assert_eq!(guarded.guards().len(), 1);
1093 }
1094
1095 #[test]
1096 fn test_guarded_brick_check_guards_pass() {
1097 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1098
1099 struct TestBrick;
1100 impl Brick for TestBrick {
1101 fn brick_name(&self) -> &'static str {
1102 "TestBrick"
1103 }
1104 fn assertions(&self) -> &[BrickAssertion] {
1105 &[]
1106 }
1107 fn budget(&self) -> BrickBudget {
1108 BrickBudget::uniform(16)
1109 }
1110 fn verify(&self) -> BrickVerification {
1111 BrickVerification {
1112 passed: vec![],
1113 failed: vec![],
1114 verification_time: Duration::ZERO,
1115 }
1116 }
1117 fn to_html(&self) -> String {
1118 String::new()
1119 }
1120 fn to_css(&self) -> String {
1121 String::new()
1122 }
1123 }
1124
1125 fn always_pass(_: &BrickState) -> bool {
1126 true
1127 }
1128
1129 let guard = InvariantGuard::new("always_pass", always_pass, GuardSeverity::Error);
1130 let guarded = GuardedBrick::new(TestBrick).guard(guard);
1131
1132 let state = BrickState::new();
1133 assert!(guarded.check_guards(&state).is_ok());
1134 }
1135
1136 #[test]
1137 fn test_guarded_brick_check_guards_fail() {
1138 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1139
1140 struct TestBrick;
1141 impl Brick for TestBrick {
1142 fn brick_name(&self) -> &'static str {
1143 "TestBrick"
1144 }
1145 fn assertions(&self) -> &[BrickAssertion] {
1146 &[]
1147 }
1148 fn budget(&self) -> BrickBudget {
1149 BrickBudget::uniform(16)
1150 }
1151 fn verify(&self) -> BrickVerification {
1152 BrickVerification {
1153 passed: vec![],
1154 failed: vec![],
1155 verification_time: Duration::ZERO,
1156 }
1157 }
1158 fn to_html(&self) -> String {
1159 String::new()
1160 }
1161 fn to_css(&self) -> String {
1162 String::new()
1163 }
1164 }
1165
1166 fn always_fail(_: &BrickState) -> bool {
1167 false
1168 }
1169
1170 let guard = InvariantGuard::new("always_fail", always_fail, GuardSeverity::Critical);
1171 let guarded = GuardedBrick::new(TestBrick).guard(guard);
1172
1173 let state = BrickState::new();
1174 let result = guarded.check_guards(&state);
1175 assert!(result.is_err());
1176
1177 let violation = result.unwrap_err();
1178 assert_eq!(violation.guard_name, "always_fail");
1179 assert_eq!(violation.severity, GuardSeverity::Critical);
1180 }
1181
1182 #[test]
1183 fn test_guard_violation_display() {
1184 let violation = GuardViolation {
1185 guard_name: "test_guard",
1186 severity: GuardSeverity::Error,
1187 };
1188 let display = format!("{}", violation);
1189 assert!(display.contains("test_guard"));
1190 assert!(display.contains("Error"));
1191 }
1192
1193 #[test]
1194 fn test_guard_violation_error_trait() {
1195 let violation = GuardViolation {
1196 guard_name: "test",
1197 severity: GuardSeverity::Warning,
1198 };
1199 let _: &dyn std::error::Error = &violation;
1200 }
1201
1202 #[test]
1203 fn test_deterministic_rng_default() {
1204 let rng = DeterministicRng::default();
1205 assert_eq!(rng.state(), 42);
1206 }
1207
1208 #[test]
1209 fn test_deterministic_rng_f32_range() {
1210 let mut rng = DeterministicRng::new(123);
1211 for _ in 0..100 {
1212 let val = rng.next_f32();
1213 assert!((0.0..1.0).contains(&val));
1214 }
1215 }
1216
1217 #[test]
1218 fn test_deterministic_rng_state() {
1219 let mut rng = DeterministicRng::new(999);
1220 let _ = rng.next_u64();
1221 let state = rng.state();
1222 assert_ne!(state, 999); }
1224
1225 #[test]
1226 fn test_deterministic_rng_restore() {
1227 let mut rng1 = DeterministicRng::new(100);
1228 let mut rng2 = DeterministicRng::new(999);
1229
1230 for _ in 0..10 {
1232 rng1.next_u64();
1233 }
1234
1235 let saved_state = rng1.state();
1237 rng2.restore(saved_state);
1238
1239 for _ in 0..10 {
1241 assert_eq!(rng1.next_u64(), rng2.next_u64());
1242 }
1243 }
1244
1245 #[test]
1246 fn test_deterministic_rng_clone() {
1247 let mut rng1 = DeterministicRng::new(555);
1248 for _ in 0..5 {
1249 rng1.next_u64();
1250 }
1251
1252 let mut rng2 = rng1.clone();
1253
1254 for _ in 0..10 {
1256 assert_eq!(rng1.next_u64(), rng2.next_u64());
1257 }
1258 }
1259
1260 #[test]
1261 fn test_deterministic_clock_default() {
1262 let clock = DeterministicClock::default();
1263 assert_eq!(clock.now_ns(), 0);
1264 }
1266
1267 #[test]
1268 fn test_deterministic_clock_clone() {
1269 let mut clock1 = DeterministicClock::new(100, 50);
1270 clock1.advance(5);
1271
1272 let clock2 = clock1.clone();
1273 assert_eq!(clock1.now_ns(), clock2.now_ns());
1274 }
1275
1276 #[test]
1281 fn test_state_value_debug() {
1282 let int_val = StateValue::Int(42);
1283 let debug_str = format!("{:?}", int_val);
1284 assert!(debug_str.contains("Int"));
1285 assert!(debug_str.contains("42"));
1286
1287 let float_val = StateValue::Float(3.14);
1288 let debug_str = format!("{:?}", float_val);
1289 assert!(debug_str.contains("Float"));
1290
1291 let string_val = StateValue::String("hello".into());
1292 let debug_str = format!("{:?}", string_val);
1293 assert!(debug_str.contains("String"));
1294 assert!(debug_str.contains("hello"));
1295
1296 let bool_val = StateValue::Bool(true);
1297 let debug_str = format!("{:?}", bool_val);
1298 assert!(debug_str.contains("Bool"));
1299 assert!(debug_str.contains("true"));
1300 }
1301
1302 #[test]
1303 fn test_brick_state_debug() {
1304 let mut state = BrickState::new();
1305 state.set_tensor("test", vec![1.0, 2.0], vec![2]);
1306 state.set_metadata("key", StateValue::Int(1));
1307 state.version = 5;
1308
1309 let debug_str = format!("{:?}", state);
1310 assert!(debug_str.contains("BrickState"));
1311 assert!(debug_str.contains("version"));
1312 }
1313
1314 #[test]
1315 fn test_execution_trace_debug() {
1316 let trace = ExecutionTrace {
1317 operation: "compute".into(),
1318 input_summary: "input data".into(),
1319 output_summary: "output data".into(),
1320 duration: Duration::from_millis(100),
1321 state_version_before: 1,
1322 state_version_after: 2,
1323 };
1324
1325 let debug_str = format!("{:?}", trace);
1326 assert!(debug_str.contains("ExecutionTrace"));
1327 assert!(debug_str.contains("compute"));
1328 }
1329
1330 #[test]
1331 fn test_brick_history_debug() {
1332 let history = BrickHistory::new(10);
1333 let debug_str = format!("{:?}", history);
1334 assert!(debug_str.contains("BrickHistory"));
1335 }
1336
1337 #[test]
1338 fn test_guard_violation_clone() {
1339 let violation = GuardViolation {
1340 guard_name: "test_guard",
1341 severity: GuardSeverity::Critical,
1342 };
1343 let cloned = violation.clone();
1344 assert_eq!(violation.guard_name, cloned.guard_name);
1345 assert_eq!(violation.severity, cloned.severity);
1346 }
1347
1348 #[test]
1349 fn test_guard_violation_debug() {
1350 let violation = GuardViolation {
1351 guard_name: "my_guard",
1352 severity: GuardSeverity::Warning,
1353 };
1354 let debug_str = format!("{:?}", violation);
1355 assert!(debug_str.contains("GuardViolation"));
1356 assert!(debug_str.contains("my_guard"));
1357 assert!(debug_str.contains("Warning"));
1358 }
1359
1360 #[test]
1361 fn test_guarded_brick_debug() {
1362 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1363
1364 #[derive(Debug)]
1365 struct TestBrick;
1366 impl Brick for TestBrick {
1367 fn brick_name(&self) -> &'static str {
1368 "TestBrick"
1369 }
1370 fn assertions(&self) -> &[BrickAssertion] {
1371 &[]
1372 }
1373 fn budget(&self) -> BrickBudget {
1374 BrickBudget::uniform(16)
1375 }
1376 fn verify(&self) -> BrickVerification {
1377 BrickVerification {
1378 passed: vec![],
1379 failed: vec![],
1380 verification_time: Duration::ZERO,
1381 }
1382 }
1383 fn to_html(&self) -> String {
1384 String::new()
1385 }
1386 fn to_css(&self) -> String {
1387 String::new()
1388 }
1389 }
1390
1391 fn check(_: &BrickState) -> bool {
1392 true
1393 }
1394
1395 let guard = InvariantGuard::new("guard1", check, GuardSeverity::Warning);
1396 let guarded = GuardedBrick::new(TestBrick).guard(guard);
1397
1398 let debug_str = format!("{:?}", guarded);
1399 assert!(debug_str.contains("GuardedBrick"));
1400 }
1401
1402 #[test]
1403 fn test_guarded_brick_multiple_guards() {
1404 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1405
1406 struct TestBrick;
1407 impl Brick for TestBrick {
1408 fn brick_name(&self) -> &'static str {
1409 "TestBrick"
1410 }
1411 fn assertions(&self) -> &[BrickAssertion] {
1412 &[]
1413 }
1414 fn budget(&self) -> BrickBudget {
1415 BrickBudget::uniform(16)
1416 }
1417 fn verify(&self) -> BrickVerification {
1418 BrickVerification {
1419 passed: vec![],
1420 failed: vec![],
1421 verification_time: Duration::ZERO,
1422 }
1423 }
1424 fn to_html(&self) -> String {
1425 String::new()
1426 }
1427 fn to_css(&self) -> String {
1428 String::new()
1429 }
1430 }
1431
1432 fn always_pass(_: &BrickState) -> bool {
1433 true
1434 }
1435 fn check_count(state: &BrickState) -> bool {
1436 match state.get_metadata("count") {
1437 Some(StateValue::Int(n)) => *n >= 0,
1438 _ => true,
1439 }
1440 }
1441
1442 let guard1 = InvariantGuard::new("guard1", always_pass, GuardSeverity::Warning);
1443 let guard2 = InvariantGuard::new("guard2", check_count, GuardSeverity::Error);
1444
1445 let guarded = GuardedBrick::new(TestBrick).guard(guard1).guard(guard2);
1446
1447 assert_eq!(guarded.guards().len(), 2);
1448
1449 let mut state = BrickState::new();
1451 state.set_metadata("count", StateValue::Int(5));
1452 assert!(guarded.check_guards(&state).is_ok());
1453
1454 state.set_metadata("count", StateValue::Int(-1));
1456 let result = guarded.check_guards(&state);
1457 assert!(result.is_err());
1458 let violation = result.unwrap_err();
1459 assert_eq!(violation.guard_name, "guard2");
1460 }
1461
1462 #[test]
1463 fn test_guarded_brick_first_guard_fails() {
1464 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1465
1466 struct TestBrick;
1467 impl Brick for TestBrick {
1468 fn brick_name(&self) -> &'static str {
1469 "TestBrick"
1470 }
1471 fn assertions(&self) -> &[BrickAssertion] {
1472 &[]
1473 }
1474 fn budget(&self) -> BrickBudget {
1475 BrickBudget::uniform(16)
1476 }
1477 fn verify(&self) -> BrickVerification {
1478 BrickVerification {
1479 passed: vec![],
1480 failed: vec![],
1481 verification_time: Duration::ZERO,
1482 }
1483 }
1484 fn to_html(&self) -> String {
1485 String::new()
1486 }
1487 fn to_css(&self) -> String {
1488 String::new()
1489 }
1490 }
1491
1492 fn always_fail(_: &BrickState) -> bool {
1493 false
1494 }
1495 fn always_pass(_: &BrickState) -> bool {
1496 true
1497 }
1498
1499 let guard1 = InvariantGuard::new("first_fail", always_fail, GuardSeverity::Error);
1500 let guard2 = InvariantGuard::new("second_pass", always_pass, GuardSeverity::Warning);
1501
1502 let guarded = GuardedBrick::new(TestBrick).guard(guard1).guard(guard2);
1503
1504 let state = BrickState::new();
1505 let result = guarded.check_guards(&state);
1506 assert!(result.is_err());
1507 assert_eq!(result.unwrap_err().guard_name, "first_fail");
1509 }
1510
1511 #[test]
1512 fn test_guard_severity_clone() {
1513 let severity = GuardSeverity::Critical;
1514 let cloned = severity;
1515 assert_eq!(severity, cloned);
1516 }
1517
1518 #[test]
1519 fn test_guard_severity_copy() {
1520 let severity = GuardSeverity::Warning;
1521 let copied: GuardSeverity = severity;
1522 assert_eq!(severity, copied);
1523 }
1524
1525 #[test]
1526 fn test_guard_severity_debug() {
1527 let warning = GuardSeverity::Warning;
1528 let error = GuardSeverity::Error;
1529 let critical = GuardSeverity::Critical;
1530
1531 assert!(format!("{:?}", warning).contains("Warning"));
1532 assert!(format!("{:?}", error).contains("Error"));
1533 assert!(format!("{:?}", critical).contains("Critical"));
1534 }
1535
1536 #[test]
1537 fn test_deterministic_brick_trait_default_impls() {
1538 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1539
1540 #[derive(Debug)]
1541 struct TestDeterministicBrick;
1542
1543 #[derive(Clone, Default)]
1544 struct TestState {
1545 value: i32,
1546 }
1547
1548 impl Brick for TestDeterministicBrick {
1549 fn brick_name(&self) -> &'static str {
1550 "TestDeterministicBrick"
1551 }
1552 fn assertions(&self) -> &[BrickAssertion] {
1553 &[]
1554 }
1555 fn budget(&self) -> BrickBudget {
1556 BrickBudget::uniform(16)
1557 }
1558 fn verify(&self) -> BrickVerification {
1559 BrickVerification {
1560 passed: vec![],
1561 failed: vec![],
1562 verification_time: Duration::ZERO,
1563 }
1564 }
1565 fn to_html(&self) -> String {
1566 String::new()
1567 }
1568 fn to_css(&self) -> String {
1569 String::new()
1570 }
1571 }
1572
1573 impl DeterministicBrick for TestDeterministicBrick {
1574 type State = TestState;
1575 type Input = i32;
1576 type Output = i32;
1577
1578 fn execute_pure(
1579 state: Self::State,
1580 input: Self::Input,
1581 ) -> Result<(Self::State, Self::Output), BrickError> {
1582 let new_state = TestState {
1583 value: state.value + input,
1584 };
1585 let output = new_state.value;
1586 Ok((new_state, output))
1587 }
1588 }
1589
1590 let initial = TestDeterministicBrick::initial_state();
1592 assert_eq!(initial.value, 0);
1593
1594 let brick = TestDeterministicBrick;
1596 let deps = brick.state_dependencies();
1597 assert!(deps.is_empty());
1598
1599 let state = TestState { value: 10 };
1601 let (new_state, output) = TestDeterministicBrick::execute_pure(state, 5).unwrap();
1602 assert_eq!(new_state.value, 15);
1603 assert_eq!(output, 15);
1604 }
1605
1606 #[test]
1607 fn test_deterministic_brick_with_custom_state_dependencies() {
1608 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1609
1610 struct CustomDepsBrick {
1611 deps: Vec<&'static str>,
1612 }
1613
1614 #[derive(Clone, Default)]
1615 struct SimpleState;
1616
1617 impl Brick for CustomDepsBrick {
1618 fn brick_name(&self) -> &'static str {
1619 "CustomDepsBrick"
1620 }
1621 fn assertions(&self) -> &[BrickAssertion] {
1622 &[]
1623 }
1624 fn budget(&self) -> BrickBudget {
1625 BrickBudget::uniform(16)
1626 }
1627 fn verify(&self) -> BrickVerification {
1628 BrickVerification {
1629 passed: vec![],
1630 failed: vec![],
1631 verification_time: Duration::ZERO,
1632 }
1633 }
1634 fn to_html(&self) -> String {
1635 String::new()
1636 }
1637 fn to_css(&self) -> String {
1638 String::new()
1639 }
1640 }
1641
1642 impl DeterministicBrick for CustomDepsBrick {
1643 type State = SimpleState;
1644 type Input = ();
1645 type Output = ();
1646
1647 fn execute_pure(
1648 state: Self::State,
1649 _input: Self::Input,
1650 ) -> Result<(Self::State, Self::Output), BrickError> {
1651 Ok((state, ()))
1652 }
1653
1654 fn state_dependencies(&self) -> &[&str] {
1655 &self.deps
1656 }
1657 }
1658
1659 let brick = CustomDepsBrick {
1660 deps: vec!["audio_buffer", "mel_filterbank"],
1661 };
1662
1663 let deps = brick.state_dependencies();
1664 assert_eq!(deps.len(), 2);
1665 assert_eq!(deps[0], "audio_buffer");
1666 assert_eq!(deps[1], "mel_filterbank");
1667 }
1668
1669 #[test]
1670 fn test_brick_history_current_edge_cases() {
1671 let mut history = BrickHistory::new(10);
1672
1673 assert!(history.current().is_none());
1675
1676 let mut state = BrickState::new();
1678 state.set_metadata("v", StateValue::Int(100));
1679 let trace = ExecutionTrace {
1680 operation: "op".into(),
1681 input_summary: String::new(),
1682 output_summary: String::new(),
1683 duration: Duration::ZERO,
1684 state_version_before: 0,
1685 state_version_after: 1,
1686 };
1687 history.record(state, trace);
1688
1689 let current = history.current();
1691 assert!(current.is_some());
1692 assert_eq!(
1693 current.unwrap().get_metadata("v"),
1694 Some(&StateValue::Int(100))
1695 );
1696 }
1697
1698 #[test]
1699 fn test_brick_history_step_forward_returns_correct_state() {
1700 let mut history = BrickHistory::new(10);
1701
1702 for i in 1..=3 {
1704 let mut state = BrickState::new();
1705 state.set_metadata("val", StateValue::Int(i * 10));
1706 let trace = ExecutionTrace {
1707 operation: format!("op_{}", i),
1708 input_summary: String::new(),
1709 output_summary: String::new(),
1710 duration: Duration::ZERO,
1711 state_version_before: (i - 1) as u64,
1712 state_version_after: i as u64,
1713 };
1714 history.record(state, trace);
1715 }
1716
1717 history.goto(0);
1719 assert_eq!(history.position(), 0);
1720
1721 let state = history.step_forward().unwrap();
1723 assert_eq!(state.get_metadata("val"), Some(&StateValue::Int(10)));
1724 assert_eq!(history.position(), 1);
1725
1726 let state = history.step_forward().unwrap();
1728 assert_eq!(state.get_metadata("val"), Some(&StateValue::Int(20)));
1729 assert_eq!(history.position(), 2);
1730 }
1731
1732 #[test]
1733 fn test_deterministic_rng_reproducibility_across_types() {
1734 let mut rng1 = DeterministicRng::new(99999);
1735 let mut rng2 = DeterministicRng::new(99999);
1736
1737 for _ in 0..10 {
1739 assert_eq!(rng1.next_u64(), rng2.next_u64());
1740 let f64_1 = rng1.next_f64();
1741 let f64_2 = rng2.next_f64();
1742 assert!((f64_1 - f64_2).abs() < f64::EPSILON);
1743 let f32_1 = rng1.next_f32();
1744 let f32_2 = rng2.next_f32();
1745 assert!((f32_1 - f32_2).abs() < f32::EPSILON);
1746 }
1747 }
1748
1749 #[test]
1750 fn test_deterministic_clock_tick_sequence() {
1751 let mut clock = DeterministicClock::new(0, 16_666_667); for _ in 0..60 {
1755 clock.tick();
1756 }
1757
1758 let expected_ns = 16_666_667u64 * 60;
1760 assert_eq!(clock.now_ns(), expected_ns);
1761
1762 let duration = clock.now();
1764 assert!(duration.as_secs_f64() > 0.99 && duration.as_secs_f64() < 1.01);
1765 }
1766
1767 #[test]
1768 fn test_brick_state_multiple_tensors() {
1769 let mut state = BrickState::new();
1770
1771 state.set_tensor("audio", vec![1.0, 2.0, 3.0], vec![3]);
1772 state.set_tensor("mel", vec![4.0, 5.0], vec![1, 2]);
1773 state.set_tensor("empty", vec![], vec![0]);
1774
1775 let (audio_data, audio_shape) = state.get_tensor("audio").unwrap();
1776 assert_eq!(audio_data, &[1.0, 2.0, 3.0]);
1777 assert_eq!(audio_shape, &[3]);
1778
1779 let (mel_data, mel_shape) = state.get_tensor("mel").unwrap();
1780 assert_eq!(mel_data, &[4.0, 5.0]);
1781 assert_eq!(mel_shape, &[1, 2]);
1782
1783 let (empty_data, empty_shape) = state.get_tensor("empty").unwrap();
1784 assert!(empty_data.is_empty());
1785 assert_eq!(empty_shape, &[0]);
1786 }
1787
1788 #[test]
1789 fn test_brick_state_overwrite_tensor() {
1790 let mut state = BrickState::new();
1791
1792 state.set_tensor("data", vec![1.0], vec![1]);
1793 let (data, shape) = state.get_tensor("data").unwrap();
1794 assert_eq!(data, &[1.0]);
1795 assert_eq!(shape, &[1]);
1796
1797 state.set_tensor("data", vec![2.0, 3.0, 4.0], vec![3]);
1799 let (data, shape) = state.get_tensor("data").unwrap();
1800 assert_eq!(data, &[2.0, 3.0, 4.0]);
1801 assert_eq!(shape, &[3]);
1802 }
1803
1804 #[test]
1805 fn test_brick_state_overwrite_metadata() {
1806 let mut state = BrickState::new();
1807
1808 state.set_metadata("key", StateValue::Int(1));
1809 assert_eq!(state.get_metadata("key"), Some(&StateValue::Int(1)));
1810
1811 state.set_metadata("key", StateValue::String("replaced".into()));
1812 assert_eq!(
1813 state.get_metadata("key"),
1814 Some(&StateValue::String("replaced".into()))
1815 );
1816 }
1817
1818 #[test]
1819 fn test_brick_state_snapshot_preserves_data() {
1820 let mut state = BrickState::new();
1821 state.set_tensor("t", vec![1.0, 2.0], vec![2]);
1822 state.set_metadata("m", StateValue::Float(3.14));
1823 state.version = 10;
1824
1825 let snapshot = state.snapshot();
1826
1827 assert_eq!(snapshot.version, 11);
1829
1830 let (data, shape) = snapshot.get_tensor("t").unwrap();
1832 assert_eq!(data, &[1.0, 2.0]);
1833 assert_eq!(shape, &[2]);
1834 assert_eq!(snapshot.get_metadata("m"), Some(&StateValue::Float(3.14)));
1835
1836 assert_eq!(state.version, 10);
1838 }
1839
1840 #[test]
1841 fn test_execution_trace_all_fields() {
1842 let trace = ExecutionTrace {
1843 operation: "mel_spectrogram".into(),
1844 input_summary: "1024 samples @ 16kHz".into(),
1845 output_summary: "80 mel bands".into(),
1846 duration: Duration::from_micros(1500),
1847 state_version_before: 42,
1848 state_version_after: 43,
1849 };
1850
1851 assert_eq!(trace.operation, "mel_spectrogram");
1852 assert_eq!(trace.input_summary, "1024 samples @ 16kHz");
1853 assert_eq!(trace.output_summary, "80 mel bands");
1854 assert_eq!(trace.duration, Duration::from_micros(1500));
1855 assert_eq!(trace.state_version_before, 42);
1856 assert_eq!(trace.state_version_after, 43);
1857 }
1858
1859 #[test]
1860 fn test_invariant_guard_different_severities() {
1861 fn check(_: &BrickState) -> bool {
1862 true
1863 }
1864
1865 let warning_guard = InvariantGuard::new("warning", check, GuardSeverity::Warning);
1866 let error_guard = InvariantGuard::new("error", check, GuardSeverity::Error);
1867 let critical_guard = InvariantGuard::new("critical", check, GuardSeverity::Critical);
1868
1869 assert_eq!(warning_guard.severity, GuardSeverity::Warning);
1870 assert_eq!(error_guard.severity, GuardSeverity::Error);
1871 assert_eq!(critical_guard.severity, GuardSeverity::Critical);
1872
1873 let state = BrickState::new();
1874 assert!(warning_guard.check(&state));
1875 assert!(error_guard.check(&state));
1876 assert!(critical_guard.check(&state));
1877 }
1878
1879 #[test]
1880 fn test_guard_violation_all_severities() {
1881 let warning = GuardViolation {
1882 guard_name: "w",
1883 severity: GuardSeverity::Warning,
1884 };
1885 let error = GuardViolation {
1886 guard_name: "e",
1887 severity: GuardSeverity::Error,
1888 };
1889 let critical = GuardViolation {
1890 guard_name: "c",
1891 severity: GuardSeverity::Critical,
1892 };
1893
1894 assert!(format!("{}", warning).contains("Warning"));
1895 assert!(format!("{}", error).contains("Error"));
1896 assert!(format!("{}", critical).contains("Critical"));
1897 }
1898
1899 #[test]
1900 fn test_deterministic_rng_zero_seed() {
1901 let mut rng = DeterministicRng::new(0);
1903
1904 let mut seen_nonzero = false;
1907 for _ in 0..100 {
1908 if rng.next_u64() != 0 {
1909 seen_nonzero = true;
1910 break;
1911 }
1912 }
1913 let _ = seen_nonzero;
1916 }
1917
1918 #[test]
1919 fn test_deterministic_clock_zero_tick() {
1920 let mut clock = DeterministicClock::new(100, 0);
1921
1922 clock.tick();
1923 assert_eq!(clock.now_ns(), 100); clock.advance(100);
1926 assert_eq!(clock.now_ns(), 100); }
1928
1929 #[test]
1930 fn test_brick_history_size_one() {
1931 let mut history = BrickHistory::new(1);
1932
1933 let mut state1 = BrickState::new();
1935 state1.set_metadata("v", StateValue::Int(1));
1936 let trace1 = ExecutionTrace {
1937 operation: "op1".into(),
1938 input_summary: String::new(),
1939 output_summary: String::new(),
1940 duration: Duration::ZERO,
1941 state_version_before: 0,
1942 state_version_after: 1,
1943 };
1944 history.record(state1, trace1);
1945 assert_eq!(history.len(), 1);
1946
1947 let mut state2 = BrickState::new();
1949 state2.set_metadata("v", StateValue::Int(2));
1950 let trace2 = ExecutionTrace {
1951 operation: "op2".into(),
1952 input_summary: String::new(),
1953 output_summary: String::new(),
1954 duration: Duration::ZERO,
1955 state_version_before: 1,
1956 state_version_after: 2,
1957 };
1958 history.record(state2, trace2);
1959 assert_eq!(history.len(), 1);
1960
1961 let current = history.goto(0).unwrap();
1963 assert_eq!(current.get_metadata("v"), Some(&StateValue::Int(2)));
1964 }
1965
1966 #[test]
1967 fn test_guarded_brick_no_guards() {
1968 use super::super::{Brick, BrickAssertion, BrickBudget, BrickVerification};
1969
1970 struct TestBrick;
1971 impl Brick for TestBrick {
1972 fn brick_name(&self) -> &'static str {
1973 "TestBrick"
1974 }
1975 fn assertions(&self) -> &[BrickAssertion] {
1976 &[]
1977 }
1978 fn budget(&self) -> BrickBudget {
1979 BrickBudget::uniform(16)
1980 }
1981 fn verify(&self) -> BrickVerification {
1982 BrickVerification {
1983 passed: vec![],
1984 failed: vec![],
1985 verification_time: Duration::ZERO,
1986 }
1987 }
1988 fn to_html(&self) -> String {
1989 String::new()
1990 }
1991 fn to_css(&self) -> String {
1992 String::new()
1993 }
1994 }
1995
1996 let guarded = GuardedBrick::new(TestBrick);
1997 assert!(guarded.guards().is_empty());
1998
1999 let state = BrickState::new();
2001 assert!(guarded.check_guards(&state).is_ok());
2002 }
2003
2004 #[test]
2005 fn test_deterministic_rng_distribution() {
2006 let mut rng = DeterministicRng::new(777);
2007 let mut sum = 0.0f64;
2008 let n = 10000;
2009
2010 for _ in 0..n {
2011 sum += rng.next_f64();
2012 }
2013
2014 let avg = sum / n as f64;
2015 assert!(avg > 0.4 && avg < 0.6);
2017 }
2018
2019 mod shared_brick {
2025 use super::*;
2026 use crate::brick::{BrickAssertion, BrickBudget, BrickVerification};
2027
2028 pub struct ComprehensiveTestBrick {
2029 pub name: &'static str,
2030 }
2031
2032 impl Brick for ComprehensiveTestBrick {
2033 fn brick_name(&self) -> &'static str {
2034 self.name
2035 }
2036 fn assertions(&self) -> &[BrickAssertion] {
2037 &[]
2038 }
2039 fn budget(&self) -> BrickBudget {
2040 BrickBudget::uniform(16)
2041 }
2042 fn verify(&self) -> BrickVerification {
2043 BrickVerification {
2044 passed: vec![],
2045 failed: vec![],
2046 verification_time: Duration::ZERO,
2047 }
2048 }
2049 fn to_html(&self) -> String {
2050 format!("<div>{}</div>", self.name)
2051 }
2052 fn to_css(&self) -> String {
2053 ".brick { color: red; }".into()
2054 }
2055 }
2056 }
2057
2058 #[test]
2059 fn test_comprehensive_brick_all_methods() {
2060 use shared_brick::ComprehensiveTestBrick;
2061
2062 let brick = ComprehensiveTestBrick { name: "TestBrick" };
2063
2064 assert_eq!(brick.brick_name(), "TestBrick");
2066 assert!(brick.assertions().is_empty());
2067 assert_eq!(brick.budget().total_ms, 16);
2068
2069 let verification = brick.verify();
2070 assert!(verification.passed.is_empty());
2071 assert!(verification.failed.is_empty());
2072 assert_eq!(verification.verification_time, Duration::ZERO);
2073
2074 assert!(brick.to_html().contains("TestBrick"));
2075 assert!(brick.to_css().contains(".brick"));
2076 }
2077
2078 #[test]
2079 fn test_guarded_brick_exercises_inner_brick_methods() {
2080 use shared_brick::ComprehensiveTestBrick;
2081
2082 fn always_pass(_: &BrickState) -> bool {
2083 true
2084 }
2085
2086 let guard = InvariantGuard::new("pass", always_pass, GuardSeverity::Warning);
2087 let guarded = GuardedBrick::new(ComprehensiveTestBrick { name: "Guarded" }).guard(guard);
2088
2089 let inner = guarded.inner();
2091 assert_eq!(inner.brick_name(), "Guarded");
2092 assert!(inner.assertions().is_empty());
2093 assert_eq!(inner.budget().total_ms, 16);
2094
2095 let verification = inner.verify();
2096 assert!(verification.passed.is_empty());
2097 assert!(inner.to_html().contains("Guarded"));
2098 assert!(inner.to_css().contains(".brick"));
2099 }
2100
2101 #[test]
2102 fn test_guard_check_function_all_state_value_variants() {
2103 fn check_any_value(state: &BrickState) -> bool {
2105 match state.get_metadata("val") {
2106 Some(StateValue::Int(_)) => true,
2107 Some(StateValue::Float(_)) => true,
2108 Some(StateValue::String(_)) => true,
2109 Some(StateValue::Bool(_)) => true,
2110 None => true,
2111 }
2112 }
2113
2114 let guard = InvariantGuard::new("any_value", check_any_value, GuardSeverity::Warning);
2115
2116 let mut state = BrickState::new();
2118 state.set_metadata("val", StateValue::Int(42));
2119 assert!(guard.check(&state));
2120
2121 state.set_metadata("val", StateValue::Float(3.14));
2123 assert!(guard.check(&state));
2124
2125 state.set_metadata("val", StateValue::String("test".into()));
2127 assert!(guard.check(&state));
2128
2129 state.set_metadata("val", StateValue::Bool(true));
2131 assert!(guard.check(&state));
2132
2133 let empty_state = BrickState::new();
2135 assert!(guard.check(&empty_state));
2136 }
2137
2138 #[test]
2139 fn test_guard_check_positive_with_non_int_metadata() {
2140 fn check_positive_or_default(state: &BrickState) -> bool {
2142 match state.get_metadata("count") {
2143 Some(StateValue::Int(n)) => *n >= 0,
2144 _ => true, }
2146 }
2147
2148 let guard = InvariantGuard::new(
2149 "positive_or_default",
2150 check_positive_or_default,
2151 GuardSeverity::Error,
2152 );
2153
2154 let mut state = BrickState::new();
2156 state.set_metadata("count", StateValue::Float(42.0));
2157 assert!(guard.check(&state));
2158
2159 state.set_metadata("count", StateValue::String("not a number".into()));
2161 assert!(guard.check(&state));
2162
2163 state.set_metadata("count", StateValue::Bool(false));
2165 assert!(guard.check(&state));
2166
2167 let empty_state = BrickState::new();
2169 assert!(guard.check(&empty_state));
2170 }
2171
2172 #[test]
2173 fn test_deterministic_brick_error_propagation() {
2174 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
2175
2176 #[derive(Clone, Default)]
2177 struct ErrorState {
2178 should_fail: bool,
2179 }
2180
2181 struct FailingBrick;
2182
2183 impl Brick for FailingBrick {
2184 fn brick_name(&self) -> &'static str {
2185 "FailingBrick"
2186 }
2187 fn assertions(&self) -> &[BrickAssertion] {
2188 &[]
2189 }
2190 fn budget(&self) -> BrickBudget {
2191 BrickBudget::uniform(16)
2192 }
2193 fn verify(&self) -> BrickVerification {
2194 BrickVerification {
2195 passed: vec![],
2196 failed: vec![],
2197 verification_time: Duration::ZERO,
2198 }
2199 }
2200 fn to_html(&self) -> String {
2201 String::new()
2202 }
2203 fn to_css(&self) -> String {
2204 String::new()
2205 }
2206 }
2207
2208 impl DeterministicBrick for FailingBrick {
2209 type State = ErrorState;
2210 type Input = ();
2211 type Output = ();
2212
2213 fn execute_pure(
2214 state: Self::State,
2215 _input: Self::Input,
2216 ) -> Result<(Self::State, Self::Output), BrickError> {
2217 if state.should_fail {
2218 Err(BrickError::HtmlGenerationFailed {
2219 reason: "test failure".into(),
2220 })
2221 } else {
2222 Ok((state, ()))
2223 }
2224 }
2225 }
2226
2227 let state = ErrorState { should_fail: false };
2229 let result = FailingBrick::execute_pure(state, ());
2230 assert!(result.is_ok());
2231
2232 let state = ErrorState { should_fail: true };
2234 let result = FailingBrick::execute_pure(state, ());
2235 assert!(result.is_err());
2236
2237 let initial = FailingBrick::initial_state();
2239 assert!(!initial.should_fail);
2240
2241 let brick = FailingBrick;
2242 assert!(brick.state_dependencies().is_empty());
2243 }
2244
2245 #[test]
2246 fn test_brick_history_complex_navigation() {
2247 let mut history = BrickHistory::new(10);
2248
2249 for i in 0..5 {
2251 let mut state = BrickState::new();
2252 state.set_metadata("idx", StateValue::Int(i));
2253 let trace = ExecutionTrace {
2254 operation: format!("op_{}", i),
2255 input_summary: format!("input_{}", i),
2256 output_summary: format!("output_{}", i),
2257 duration: Duration::from_millis(i as u64),
2258 state_version_before: i as u64,
2259 state_version_after: (i + 1) as u64,
2260 };
2261 history.record(state, trace);
2262 }
2263
2264 let state = history.goto(2).unwrap();
2266 assert_eq!(state.get_metadata("idx"), Some(&StateValue::Int(2)));
2267
2268 let state = history.step_forward().unwrap();
2270 assert_eq!(state.get_metadata("idx"), Some(&StateValue::Int(2)));
2271
2272 let state = history.step_forward().unwrap();
2273 assert_eq!(state.get_metadata("idx"), Some(&StateValue::Int(3)));
2274
2275 let state = history.step_back().unwrap();
2277 assert_eq!(state.get_metadata("idx"), Some(&StateValue::Int(3)));
2278
2279 let current = history.current().unwrap();
2281 assert!(current.get_metadata("idx").is_some());
2282 }
2283
2284 #[test]
2285 fn test_execution_trace_with_all_fields_populated() {
2286 let trace = ExecutionTrace {
2287 operation: "complex_operation".into(),
2288 input_summary: "1024 samples, 16-bit PCM".into(),
2289 output_summary: "80 mel filterbank coefficients".into(),
2290 duration: Duration::from_micros(2500),
2291 state_version_before: 100,
2292 state_version_after: 101,
2293 };
2294
2295 assert_eq!(trace.operation, "complex_operation");
2297 assert!(trace.input_summary.contains("1024"));
2298 assert!(trace.output_summary.contains("mel"));
2299 assert_eq!(trace.duration.as_micros(), 2500);
2300 assert_eq!(trace.state_version_before, 100);
2301 assert_eq!(trace.state_version_after, 101);
2302
2303 let cloned = trace.clone();
2305 assert_eq!(trace.operation, cloned.operation);
2306 assert_eq!(trace.duration, cloned.duration);
2307 }
2308
2309 #[test]
2310 fn test_brick_state_comprehensive() {
2311 let mut state = BrickState::new();
2312
2313 state.set_tensor("scalar", vec![1.0], vec![]);
2315 state.set_tensor("vector", vec![1.0, 2.0, 3.0, 4.0], vec![4]);
2316 state.set_tensor("matrix", vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], vec![2, 3]);
2317
2318 state.set_metadata("int", StateValue::Int(-999));
2320 state.set_metadata("float", StateValue::Float(2.718281828));
2321 state.set_metadata("string", StateValue::String("deterministic".into()));
2322 state.set_metadata("bool", StateValue::Bool(false));
2323
2324 let (scalar_data, scalar_shape) = state.get_tensor("scalar").unwrap();
2326 assert_eq!(scalar_data, &[1.0]);
2327 assert!(scalar_shape.is_empty());
2328
2329 let (matrix_data, matrix_shape) = state.get_tensor("matrix").unwrap();
2330 assert_eq!(matrix_data.len(), 6);
2331 assert_eq!(matrix_shape, &[2, 3]);
2332
2333 assert_eq!(state.get_metadata("int"), Some(&StateValue::Int(-999)));
2335 assert_eq!(
2336 state.get_metadata("float"),
2337 Some(&StateValue::Float(2.718281828))
2338 );
2339 assert_eq!(
2340 state.get_metadata("string"),
2341 Some(&StateValue::String("deterministic".into()))
2342 );
2343 assert_eq!(state.get_metadata("bool"), Some(&StateValue::Bool(false)));
2344
2345 state.version = 50;
2347 let snapshot = state.snapshot();
2348 assert_eq!(snapshot.version, 51);
2349
2350 assert!(snapshot.get_tensor("scalar").is_some());
2352 assert!(snapshot.get_tensor("vector").is_some());
2353 assert!(snapshot.get_tensor("matrix").is_some());
2354 assert_eq!(snapshot.get_metadata("int"), Some(&StateValue::Int(-999)));
2355 }
2356
2357 #[test]
2358 fn test_guard_severity_all_variants_eq() {
2359 assert_eq!(GuardSeverity::Warning, GuardSeverity::Warning);
2361 assert_eq!(GuardSeverity::Error, GuardSeverity::Error);
2362 assert_eq!(GuardSeverity::Critical, GuardSeverity::Critical);
2363
2364 assert_ne!(GuardSeverity::Warning, GuardSeverity::Error);
2366 assert_ne!(GuardSeverity::Warning, GuardSeverity::Critical);
2367 assert_ne!(GuardSeverity::Error, GuardSeverity::Critical);
2368
2369 let severity = GuardSeverity::Error;
2371 let copied: GuardSeverity = severity;
2372 let cloned = severity;
2373 assert_eq!(severity, copied);
2374 assert_eq!(severity, cloned);
2375 }
2376
2377 #[test]
2378 fn test_invariant_guard_with_complex_check() {
2379 fn check_tensor_bounds(state: &BrickState) -> bool {
2380 if let Some((data, _shape)) = state.get_tensor("values") {
2381 data.iter().all(|&v| (0.0..=1.0).contains(&v))
2382 } else {
2383 true }
2385 }
2386
2387 let guard = InvariantGuard::new(
2388 "tensor_bounds",
2389 check_tensor_bounds,
2390 GuardSeverity::Critical,
2391 );
2392
2393 let mut state = BrickState::new();
2395 state.set_tensor("values", vec![0.0, 0.5, 1.0], vec![3]);
2396 assert!(guard.check(&state));
2397
2398 state.set_tensor("values", vec![0.0, 1.5, 0.5], vec![3]);
2400 assert!(!guard.check(&state));
2401
2402 let empty_state = BrickState::new();
2404 assert!(guard.check(&empty_state));
2405
2406 assert_eq!(guard.name, "tensor_bounds");
2408 assert_eq!(guard.severity, GuardSeverity::Critical);
2409 }
2410
2411 #[test]
2412 fn test_guarded_brick_chain_multiple_guards() {
2413 use shared_brick::ComprehensiveTestBrick;
2414
2415 fn guard1(_: &BrickState) -> bool {
2416 true
2417 }
2418 fn guard2(_: &BrickState) -> bool {
2419 true
2420 }
2421 fn guard3(_: &BrickState) -> bool {
2422 true
2423 }
2424
2425 let guarded = GuardedBrick::new(ComprehensiveTestBrick { name: "Multi" })
2426 .guard(InvariantGuard::new("g1", guard1, GuardSeverity::Warning))
2427 .guard(InvariantGuard::new("g2", guard2, GuardSeverity::Error))
2428 .guard(InvariantGuard::new("g3", guard3, GuardSeverity::Critical));
2429
2430 assert_eq!(guarded.guards().len(), 3);
2431 assert_eq!(guarded.guards()[0].name, "g1");
2432 assert_eq!(guarded.guards()[1].name, "g2");
2433 assert_eq!(guarded.guards()[2].name, "g3");
2434
2435 assert_eq!(guarded.guards()[0].severity, GuardSeverity::Warning);
2436 assert_eq!(guarded.guards()[1].severity, GuardSeverity::Error);
2437 assert_eq!(guarded.guards()[2].severity, GuardSeverity::Critical);
2438
2439 let state = BrickState::new();
2441 assert!(guarded.check_guards(&state).is_ok());
2442 }
2443
2444 #[test]
2445 fn test_guard_violation_display_all_severities() {
2446 let warning = GuardViolation {
2447 guard_name: "warn_guard",
2448 severity: GuardSeverity::Warning,
2449 };
2450 let error = GuardViolation {
2451 guard_name: "err_guard",
2452 severity: GuardSeverity::Error,
2453 };
2454 let critical = GuardViolation {
2455 guard_name: "crit_guard",
2456 severity: GuardSeverity::Critical,
2457 };
2458
2459 let warning_str = format!("{}", warning);
2460 let error_str = format!("{}", error);
2461 let critical_str = format!("{}", critical);
2462
2463 assert!(warning_str.contains("warn_guard"));
2464 assert!(warning_str.contains("Warning"));
2465
2466 assert!(error_str.contains("err_guard"));
2467 assert!(error_str.contains("Error"));
2468
2469 assert!(critical_str.contains("crit_guard"));
2470 assert!(critical_str.contains("Critical"));
2471
2472 let debug_str = format!("{:?}", warning);
2474 assert!(debug_str.contains("GuardViolation"));
2475 assert!(debug_str.contains("warn_guard"));
2476 }
2477
2478 #[test]
2479 fn test_deterministic_rng_edge_cases() {
2480 let mut rng = DeterministicRng::new(u64::MAX);
2482 let _ = rng.next_u64();
2483 let _ = rng.next_f64();
2484 let _ = rng.next_f32();
2485
2486 let mut rng1 = DeterministicRng::new(0xDEADBEEF);
2488 for _ in 0..50 {
2489 let _ = rng1.next_u64();
2490 }
2491 let saved = rng1.state();
2492
2493 let mut rng2 = DeterministicRng::new(0);
2494 rng2.restore(saved);
2495
2496 for _ in 0..20 {
2498 assert_eq!(rng1.next_u64(), rng2.next_u64());
2499 }
2500 }
2501
2502 #[test]
2503 fn test_deterministic_clock_edge_cases() {
2504 let mut clock = DeterministicClock::new(0, u64::MAX / 2);
2506 clock.tick();
2507 assert_eq!(clock.now_ns(), u64::MAX / 2);
2508
2509 clock.set(u64::MAX - 1);
2511 assert_eq!(clock.now_ns(), u64::MAX - 1);
2512
2513 let clock2 = DeterministicClock::new(1_000_000_000, 1); let duration = clock2.now();
2516 assert_eq!(duration.as_secs(), 1);
2517 }
2518
2519 #[test]
2520 fn test_brick_history_boundary_conditions() {
2521 let history = BrickHistory::new(5);
2523
2524 assert!(history.trace_at(0).is_none());
2526
2527 assert!(history.traces().is_empty());
2529
2530 let mut history2 = BrickHistory::new(5);
2532 assert!(history2.step_back().is_none());
2533 assert!(history2.step_forward().is_none());
2534 assert!(history2.goto(0).is_none());
2535 assert!(history2.current().is_none());
2536 }
2537
2538 #[test]
2539 fn test_brick_history_full_cycle() {
2540 let mut history = BrickHistory::new(3);
2541
2542 for i in 0..3 {
2544 let mut state = BrickState::new();
2545 state.set_metadata("v", StateValue::Int(i));
2546 state.version = i as u64;
2547 let trace = ExecutionTrace {
2548 operation: format!("op_{}", i),
2549 input_summary: String::new(),
2550 output_summary: String::new(),
2551 duration: Duration::from_millis(i as u64 * 10),
2552 state_version_before: i as u64,
2553 state_version_after: (i + 1) as u64,
2554 };
2555 history.record(state, trace);
2556 }
2557
2558 assert_eq!(history.len(), 3);
2559
2560 history.step_back();
2562 history.step_back();
2563 history.step_back();
2564 assert_eq!(history.position(), 0);
2565
2566 let mut new_state = BrickState::new();
2568 new_state.set_metadata("v", StateValue::Int(100));
2569 let trace = ExecutionTrace {
2570 operation: "new_op".into(),
2571 input_summary: String::new(),
2572 output_summary: String::new(),
2573 duration: Duration::ZERO,
2574 state_version_before: 0,
2575 state_version_after: 1,
2576 };
2577 history.record(new_state, trace);
2578
2579 assert_eq!(history.len(), 1);
2581 assert_eq!(history.position(), 1);
2582
2583 let current = history.current().unwrap();
2585 assert_eq!(current.get_metadata("v"), Some(&StateValue::Int(100)));
2586 }
2587
2588 #[test]
2589 fn test_state_value_debug_format() {
2590 let values = [
2591 StateValue::Int(i64::MIN),
2592 StateValue::Int(i64::MAX),
2593 StateValue::Float(f64::MIN),
2594 StateValue::Float(f64::MAX),
2595 StateValue::Float(f64::NAN),
2596 StateValue::Float(f64::INFINITY),
2597 StateValue::String(String::new()),
2598 StateValue::String("a very long string with special chars: \n\t\"".into()),
2599 StateValue::Bool(true),
2600 StateValue::Bool(false),
2601 ];
2602
2603 for value in &values {
2604 let debug_str = format!("{:?}", value);
2605 assert!(!debug_str.is_empty());
2606 }
2607 }
2608
2609 #[test]
2610 fn test_invariant_guard_debug_format() {
2611 fn dummy(_: &BrickState) -> bool {
2612 true
2613 }
2614
2615 let guard = InvariantGuard::new("debug_test", dummy, GuardSeverity::Warning);
2616 let debug_str = format!("{:?}", guard);
2617
2618 assert!(debug_str.contains("InvariantGuard"));
2619 assert!(debug_str.contains("debug_test"));
2620 assert!(debug_str.contains("<fn>"));
2621 assert!(debug_str.contains("Warning"));
2622 }
2623
2624 #[test]
2625 fn test_brick_state_tensor_shape_mismatch() {
2626 let mut state = BrickState::new();
2627
2628 state.set_tensor("normal", vec![1.0, 2.0, 3.0], vec![3]);
2630 assert!(state.get_tensor("normal").is_some());
2631
2632 state.tensors.insert("orphan".into(), vec![1.0, 2.0]);
2634 assert!(state.get_tensor("orphan").is_none());
2635
2636 state.shapes.insert("ghost".into(), vec![2, 2]);
2638 assert!(state.get_tensor("ghost").is_none());
2639 }
2640
2641 #[test]
2642 fn test_deterministic_brick_with_non_default_initial_state() {
2643 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
2644
2645 #[derive(Clone)]
2646 struct CustomInitState {
2647 counter: i32,
2648 name: String,
2649 }
2650
2651 impl Default for CustomInitState {
2652 fn default() -> Self {
2653 Self {
2654 counter: 100, name: "initialized".into(),
2656 }
2657 }
2658 }
2659
2660 struct CustomInitBrick;
2661
2662 impl Brick for CustomInitBrick {
2663 fn brick_name(&self) -> &'static str {
2664 "CustomInitBrick"
2665 }
2666 fn assertions(&self) -> &[BrickAssertion] {
2667 &[]
2668 }
2669 fn budget(&self) -> BrickBudget {
2670 BrickBudget::uniform(16)
2671 }
2672 fn verify(&self) -> BrickVerification {
2673 BrickVerification {
2674 passed: vec![],
2675 failed: vec![],
2676 verification_time: Duration::ZERO,
2677 }
2678 }
2679 fn to_html(&self) -> String {
2680 String::new()
2681 }
2682 fn to_css(&self) -> String {
2683 String::new()
2684 }
2685 }
2686
2687 impl DeterministicBrick for CustomInitBrick {
2688 type State = CustomInitState;
2689 type Input = i32;
2690 type Output = String;
2691
2692 fn execute_pure(
2693 state: Self::State,
2694 input: Self::Input,
2695 ) -> Result<(Self::State, Self::Output), BrickError> {
2696 let new_state = CustomInitState {
2697 counter: state.counter + input,
2698 name: format!("{}-{}", state.name, input),
2699 };
2700 let output = format!("Counter: {}", new_state.counter);
2701 Ok((new_state, output))
2702 }
2703 }
2704
2705 let initial = CustomInitBrick::initial_state();
2707 assert_eq!(initial.counter, 100);
2708 assert_eq!(initial.name, "initialized");
2709
2710 let (new_state, output) = CustomInitBrick::execute_pure(initial, 5).unwrap();
2712 assert_eq!(new_state.counter, 105);
2713 assert_eq!(new_state.name, "initialized-5");
2714 assert!(output.contains("105"));
2715 }
2716
2717 #[test]
2718 fn test_guarded_brick_check_guards_returns_first_failure() {
2719 use shared_brick::ComprehensiveTestBrick;
2720
2721 fn pass(_: &BrickState) -> bool {
2722 true
2723 }
2724 fn fail1(_: &BrickState) -> bool {
2725 false
2726 }
2727 fn fail2(_: &BrickState) -> bool {
2728 false
2729 }
2730
2731 let guarded = GuardedBrick::new(ComprehensiveTestBrick { name: "Test" })
2732 .guard(InvariantGuard::new("pass", pass, GuardSeverity::Warning))
2733 .guard(InvariantGuard::new("fail1", fail1, GuardSeverity::Error))
2734 .guard(InvariantGuard::new("fail2", fail2, GuardSeverity::Critical));
2735
2736 let state = BrickState::new();
2737 let result = guarded.check_guards(&state);
2738 assert!(result.is_err());
2739
2740 let violation = result.unwrap_err();
2741 assert_eq!(violation.guard_name, "fail1");
2743 assert_eq!(violation.severity, GuardSeverity::Error);
2744 }
2745
2746 #[test]
2747 fn test_guard_violation_error_trait_source() {
2748 let violation = GuardViolation {
2749 guard_name: "test",
2750 severity: GuardSeverity::Warning,
2751 };
2752
2753 let err: &dyn std::error::Error = &violation;
2755 assert!(err.source().is_none());
2756
2757 let display = format!("{}", err);
2759 assert!(display.contains("test"));
2760 }
2761
2762 #[test]
2763 fn test_brick_history_current_after_modifications() {
2764 let mut history = BrickHistory::new(10);
2765
2766 assert!(history.current().is_none());
2768
2769 let mut state = BrickState::new();
2771 state.set_metadata("x", StateValue::Int(1));
2772 let trace = ExecutionTrace {
2773 operation: "op".into(),
2774 input_summary: String::new(),
2775 output_summary: String::new(),
2776 duration: Duration::ZERO,
2777 state_version_before: 0,
2778 state_version_after: 1,
2779 };
2780 history.record(state, trace);
2781
2782 let current = history.current();
2784 assert!(current.is_some());
2785 assert_eq!(
2786 current.unwrap().get_metadata("x"),
2787 Some(&StateValue::Int(1))
2788 );
2789
2790 let mut state2 = BrickState::new();
2792 state2.set_metadata("x", StateValue::Int(2));
2793 let trace2 = ExecutionTrace {
2794 operation: "op2".into(),
2795 input_summary: String::new(),
2796 output_summary: String::new(),
2797 duration: Duration::ZERO,
2798 state_version_before: 1,
2799 state_version_after: 2,
2800 };
2801 history.record(state2, trace2);
2802
2803 let current = history.current();
2805 assert!(current.is_some());
2806 assert_eq!(
2807 current.unwrap().get_metadata("x"),
2808 Some(&StateValue::Int(2))
2809 );
2810
2811 history.step_back();
2813 let current = history.current();
2815 assert!(current.is_some());
2816 }
2817
2818 fn exercise_brick_trait_methods<B: Brick>(brick: &B) {
2825 let _name = brick.brick_name();
2827 let _assertions = brick.assertions();
2828 let _budget = brick.budget();
2829 let _verification = brick.verify();
2830 let _html = brick.to_html();
2831 let _css = brick.to_css();
2832 let _test_id = brick.test_id();
2833 let _can_render = brick.can_render();
2834 }
2835
2836 #[test]
2837 fn test_exercise_guarded_brick_inner_all_methods() {
2838 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
2839
2840 struct FullBrick;
2841 impl Brick for FullBrick {
2842 fn brick_name(&self) -> &'static str {
2843 "FullBrick"
2844 }
2845 fn assertions(&self) -> &[BrickAssertion] {
2846 &[]
2847 }
2848 fn budget(&self) -> BrickBudget {
2849 BrickBudget::uniform(16)
2850 }
2851 fn verify(&self) -> BrickVerification {
2852 BrickVerification {
2853 passed: vec![],
2854 failed: vec![],
2855 verification_time: Duration::ZERO,
2856 }
2857 }
2858 fn to_html(&self) -> String {
2859 "<div>Full</div>".into()
2860 }
2861 fn to_css(&self) -> String {
2862 ".full { }".into()
2863 }
2864 }
2865
2866 fn check(_: &BrickState) -> bool {
2867 true
2868 }
2869
2870 let guard = InvariantGuard::new("g", check, GuardSeverity::Warning);
2871 let guarded = GuardedBrick::new(FullBrick).guard(guard);
2872
2873 exercise_brick_trait_methods(guarded.inner());
2875 }
2876
2877 #[test]
2878 fn test_exercise_deterministic_brick_all_methods() {
2879 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
2880
2881 struct DetBrick;
2882
2883 #[derive(Clone, Default)]
2884 struct DetState;
2885
2886 impl Brick for DetBrick {
2887 fn brick_name(&self) -> &'static str {
2888 "DetBrick"
2889 }
2890 fn assertions(&self) -> &[BrickAssertion] {
2891 &[]
2892 }
2893 fn budget(&self) -> BrickBudget {
2894 BrickBudget::uniform(16)
2895 }
2896 fn verify(&self) -> BrickVerification {
2897 BrickVerification {
2898 passed: vec![],
2899 failed: vec![],
2900 verification_time: Duration::ZERO,
2901 }
2902 }
2903 fn to_html(&self) -> String {
2904 "<p>Det</p>".into()
2905 }
2906 fn to_css(&self) -> String {
2907 ".det { }".into()
2908 }
2909 }
2910
2911 impl DeterministicBrick for DetBrick {
2912 type State = DetState;
2913 type Input = ();
2914 type Output = ();
2915
2916 fn execute_pure(
2917 state: Self::State,
2918 _input: Self::Input,
2919 ) -> Result<(Self::State, Self::Output), BrickError> {
2920 Ok((state, ()))
2921 }
2922 }
2923
2924 let brick = DetBrick;
2925 exercise_brick_trait_methods(&brick);
2926
2927 let _ = DetBrick::initial_state();
2929 let _ = brick.state_dependencies();
2930 let state = DetState;
2931 let _ = DetBrick::execute_pure(state, ());
2932 }
2933
2934 #[test]
2935 fn test_exercise_various_guard_check_functions() {
2936 fn check_int_positive(state: &BrickState) -> bool {
2939 match state.get_metadata("val") {
2940 Some(StateValue::Int(n)) => *n >= 0,
2941 _ => true,
2942 }
2943 }
2944
2945 fn check_float_bounded(state: &BrickState) -> bool {
2946 match state.get_metadata("val") {
2947 Some(StateValue::Float(f)) => *f >= 0.0 && *f <= 1.0,
2948 _ => true,
2949 }
2950 }
2951
2952 fn check_string_nonempty(state: &BrickState) -> bool {
2953 match state.get_metadata("val") {
2954 Some(StateValue::String(s)) => !s.is_empty(),
2955 _ => true,
2956 }
2957 }
2958
2959 fn check_bool_true(state: &BrickState) -> bool {
2960 match state.get_metadata("val") {
2961 Some(StateValue::Bool(b)) => *b,
2962 _ => true,
2963 }
2964 }
2965
2966 let guard1 =
2967 InvariantGuard::new("int_positive", check_int_positive, GuardSeverity::Warning);
2968 let guard2 =
2969 InvariantGuard::new("float_bounded", check_float_bounded, GuardSeverity::Error);
2970 let guard3 = InvariantGuard::new(
2971 "string_nonempty",
2972 check_string_nonempty,
2973 GuardSeverity::Critical,
2974 );
2975 let guard4 = InvariantGuard::new("bool_true", check_bool_true, GuardSeverity::Warning);
2976
2977 let mut state = BrickState::new();
2979 state.set_metadata("val", StateValue::Int(5));
2980 assert!(guard1.check(&state));
2981 assert!(guard2.check(&state));
2982 assert!(guard3.check(&state));
2983 assert!(guard4.check(&state));
2984
2985 state.set_metadata("val", StateValue::Int(-5));
2987 assert!(!guard1.check(&state));
2988
2989 state.set_metadata("val", StateValue::Float(0.5));
2991 assert!(guard2.check(&state));
2992
2993 state.set_metadata("val", StateValue::Float(1.5));
2995 assert!(!guard2.check(&state));
2996
2997 state.set_metadata("val", StateValue::String("hello".into()));
2999 assert!(guard3.check(&state));
3000
3001 state.set_metadata("val", StateValue::String(String::new()));
3003 assert!(!guard3.check(&state));
3004
3005 state.set_metadata("val", StateValue::Bool(true));
3007 assert!(guard4.check(&state));
3008
3009 state.set_metadata("val", StateValue::Bool(false));
3011 assert!(!guard4.check(&state));
3012 }
3013
3014 #[test]
3015 fn test_guarded_brick_with_all_methods_exercised() {
3016 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
3017
3018 struct TestBrickFull;
3019
3020 impl Brick for TestBrickFull {
3021 fn brick_name(&self) -> &'static str {
3022 "TestBrickFull"
3023 }
3024 fn assertions(&self) -> &[BrickAssertion] {
3025 &[BrickAssertion::TextVisible]
3026 }
3027 fn budget(&self) -> BrickBudget {
3028 BrickBudget::new(5, 5, 6)
3029 }
3030 fn verify(&self) -> BrickVerification {
3031 BrickVerification {
3032 passed: vec![BrickAssertion::TextVisible],
3033 failed: vec![],
3034 verification_time: Duration::from_millis(1),
3035 }
3036 }
3037 fn to_html(&self) -> String {
3038 "<div class='test'>Content</div>".into()
3039 }
3040 fn to_css(&self) -> String {
3041 ".test { color: blue; }".into()
3042 }
3043 }
3044
3045 fn check_has_count(state: &BrickState) -> bool {
3046 state.get_metadata("count").is_some()
3047 }
3048
3049 let guard = InvariantGuard::new("has_count", check_has_count, GuardSeverity::Warning);
3050 let guarded = GuardedBrick::new(TestBrickFull).guard(guard);
3051
3052 let inner = guarded.inner();
3054 assert_eq!(inner.brick_name(), "TestBrickFull");
3055 assert_eq!(inner.assertions().len(), 1);
3056 assert_eq!(inner.budget().total_ms, 16);
3057 assert!(inner.verify().is_valid());
3058 assert!(inner.to_html().contains("Content"));
3059 assert!(inner.to_css().contains("blue"));
3060 assert!(inner.can_render());
3061 assert!(inner.test_id().is_none());
3062
3063 let mut state = BrickState::new();
3065 state.set_metadata("count", StateValue::Int(42));
3066 assert!(guarded.check_guards(&state).is_ok());
3067
3068 let empty_state = BrickState::new();
3070 let result = guarded.check_guards(&empty_state);
3071 assert!(result.is_err());
3072 }
3073
3074 #[test]
3075 fn test_deterministic_brick_with_state_dependencies_override() {
3076 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
3077
3078 struct DepsOverrideBrick;
3079
3080 #[derive(Clone, Default)]
3081 struct DepsState;
3082
3083 impl Brick for DepsOverrideBrick {
3084 fn brick_name(&self) -> &'static str {
3085 "DepsOverrideBrick"
3086 }
3087 fn assertions(&self) -> &[BrickAssertion] {
3088 &[]
3089 }
3090 fn budget(&self) -> BrickBudget {
3091 BrickBudget::uniform(16)
3092 }
3093 fn verify(&self) -> BrickVerification {
3094 BrickVerification {
3095 passed: vec![],
3096 failed: vec![],
3097 verification_time: Duration::ZERO,
3098 }
3099 }
3100 fn to_html(&self) -> String {
3101 String::new()
3102 }
3103 fn to_css(&self) -> String {
3104 String::new()
3105 }
3106 }
3107
3108 impl DeterministicBrick for DepsOverrideBrick {
3109 type State = DepsState;
3110 type Input = ();
3111 type Output = ();
3112
3113 fn execute_pure(
3114 state: Self::State,
3115 _input: Self::Input,
3116 ) -> Result<(Self::State, Self::Output), BrickError> {
3117 Ok((state, ()))
3118 }
3119
3120 fn state_dependencies(&self) -> &[&str] {
3121 &["dep1", "dep2", "dep3"]
3122 }
3123 }
3124
3125 let brick = DepsOverrideBrick;
3126
3127 exercise_brick_trait_methods(&brick);
3129
3130 let deps = brick.state_dependencies();
3132 assert_eq!(deps.len(), 3);
3133 assert_eq!(deps[0], "dep1");
3134 assert_eq!(deps[1], "dep2");
3135 assert_eq!(deps[2], "dep3");
3136 }
3137
3138 #[test]
3139 fn test_brick_history_position_tracking() {
3140 let mut history = BrickHistory::new(10);
3141
3142 assert_eq!(history.position(), 0);
3144
3145 for i in 0..3 {
3147 let mut state = BrickState::new();
3148 state.set_metadata("i", StateValue::Int(i));
3149 let trace = ExecutionTrace {
3150 operation: format!("op{}", i),
3151 input_summary: String::new(),
3152 output_summary: String::new(),
3153 duration: Duration::ZERO,
3154 state_version_before: i as u64,
3155 state_version_after: (i + 1) as u64,
3156 };
3157 history.record(state, trace);
3158 }
3159
3160 assert_eq!(history.position(), 3);
3162 assert_eq!(history.len(), 3);
3163
3164 let _ = history.goto(1);
3166 assert_eq!(history.position(), 1);
3167
3168 let _ = history.step_forward();
3170 assert_eq!(history.position(), 2);
3171
3172 let _ = history.step_back();
3174 assert_eq!(history.position(), 1);
3175
3176 let trace = history.trace_at(0).unwrap();
3178 assert_eq!(trace.operation, "op0");
3179
3180 let all_traces = history.traces();
3181 assert_eq!(all_traces.len(), 3);
3182 }
3183
3184 #[test]
3189 fn test_brick_history_current_position_equals_len() {
3190 let mut history = BrickHistory::new(10);
3191
3192 let mut state = BrickState::new();
3194 state.set_metadata("val", StateValue::Int(42));
3195 let trace = ExecutionTrace {
3196 operation: "op".into(),
3197 input_summary: String::new(),
3198 output_summary: String::new(),
3199 duration: Duration::ZERO,
3200 state_version_before: 0,
3201 state_version_after: 1,
3202 };
3203 history.record(state, trace);
3204
3205 assert_eq!(history.position(), 1);
3209 assert_eq!(history.len(), 1);
3210
3211 let current = history.current();
3212 assert!(current.is_some());
3213 assert_eq!(
3214 current.unwrap().get_metadata("val"),
3215 Some(&StateValue::Int(42))
3216 );
3217 }
3218
3219 #[test]
3220 fn test_brick_history_current_position_greater_than_len() {
3221 let mut history = BrickHistory::new(10);
3222
3223 for i in 0..2 {
3225 let mut state = BrickState::new();
3226 state.set_metadata("val", StateValue::Int(i));
3227 let trace = ExecutionTrace {
3228 operation: format!("op{}", i),
3229 input_summary: String::new(),
3230 output_summary: String::new(),
3231 duration: Duration::ZERO,
3232 state_version_before: i as u64,
3233 state_version_after: (i + 1) as u64,
3234 };
3235 history.record(state, trace);
3236 }
3237
3238 history.position = 5;
3242
3243 let current = history.current();
3246 assert!(current.is_some());
3247 assert_eq!(
3249 current.unwrap().get_metadata("val"),
3250 Some(&StateValue::Int(0))
3251 );
3252 }
3253
3254 #[test]
3255 fn test_brick_history_step_forward_at_exact_len() {
3256 let mut history = BrickHistory::new(10);
3257
3258 let state = BrickState::new();
3260 let trace = ExecutionTrace {
3261 operation: "op".into(),
3262 input_summary: String::new(),
3263 output_summary: String::new(),
3264 duration: Duration::ZERO,
3265 state_version_before: 0,
3266 state_version_after: 1,
3267 };
3268 history.record(state, trace);
3269
3270 assert_eq!(history.position(), 1);
3274 assert!(history.step_forward().is_none());
3275 }
3276
3277 #[test]
3278 fn test_brick_history_record_at_capacity_evicts_oldest() {
3279 let mut history = BrickHistory::new(2);
3280
3281 for i in 0..2 {
3283 let mut state = BrickState::new();
3284 state.set_metadata("val", StateValue::Int(i));
3285 let trace = ExecutionTrace {
3286 operation: format!("op{}", i),
3287 input_summary: String::new(),
3288 output_summary: String::new(),
3289 duration: Duration::ZERO,
3290 state_version_before: i as u64,
3291 state_version_after: (i + 1) as u64,
3292 };
3293 history.record(state, trace);
3294 }
3295
3296 assert_eq!(history.len(), 2);
3297
3298 let mut state = BrickState::new();
3300 state.set_metadata("val", StateValue::Int(99));
3301 let trace = ExecutionTrace {
3302 operation: "op_new".into(),
3303 input_summary: String::new(),
3304 output_summary: String::new(),
3305 duration: Duration::ZERO,
3306 state_version_before: 2,
3307 state_version_after: 3,
3308 };
3309 history.record(state, trace);
3310
3311 assert_eq!(history.len(), 2);
3313
3314 let first = history.goto(0).unwrap();
3316 assert_eq!(first.get_metadata("val"), Some(&StateValue::Int(1)));
3317
3318 let second = history.goto(1).unwrap();
3320 assert_eq!(second.get_metadata("val"), Some(&StateValue::Int(99)));
3321 }
3322
3323 #[test]
3324 fn test_deterministic_rng_all_value_ranges() {
3325 let mut rng = DeterministicRng::new(12345);
3326
3327 for _ in 0..1000 {
3329 let f = rng.next_f64();
3330 assert!(f >= 0.0);
3331 assert!(f < 1.0);
3332 }
3333
3334 for _ in 0..1000 {
3336 let f = rng.next_f32();
3337 assert!(f >= 0.0);
3338 assert!(f < 1.0);
3339 }
3340 }
3341
3342 #[test]
3343 fn test_deterministic_clock_now_returns_duration() {
3344 let clock = DeterministicClock::new(1_000_000_000, 1); let duration = clock.now();
3346 assert_eq!(duration.as_nanos(), 1_000_000_000);
3347 assert_eq!(duration.as_secs(), 1);
3348 }
3349
3350 #[test]
3351 fn test_state_value_all_variants_partial_eq() {
3352 let int = StateValue::Int(42);
3354 let float = StateValue::Float(42.0);
3355 let string = StateValue::String("42".into());
3356 let bool_val = StateValue::Bool(true);
3357
3358 assert_ne!(int, float);
3360 assert_ne!(int, string);
3361 assert_ne!(int, bool_val);
3362 assert_ne!(float, string);
3363 assert_ne!(float, bool_val);
3364 assert_ne!(string, bool_val);
3365 }
3366
3367 #[test]
3368 fn test_brick_state_snapshot_increments_version() {
3369 let mut state = BrickState::new();
3370 state.version = 0;
3371
3372 let snap1 = state.snapshot();
3373 assert_eq!(snap1.version, 1);
3374
3375 let snap2 = snap1.snapshot();
3376 assert_eq!(snap2.version, 2);
3377
3378 let snap3 = snap2.snapshot();
3379 assert_eq!(snap3.version, 3);
3380 }
3381
3382 #[test]
3383 fn test_invariant_guard_const_new() {
3384 fn check(_: &BrickState) -> bool {
3386 true
3387 }
3388
3389 const GUARD: InvariantGuard =
3390 InvariantGuard::new("const_guard", check, GuardSeverity::Warning);
3391
3392 assert_eq!(GUARD.name, "const_guard");
3393 assert_eq!(GUARD.severity, GuardSeverity::Warning);
3394 }
3395
3396 #[test]
3397 fn test_deterministic_rng_const_new() {
3398 const RNG: DeterministicRng = DeterministicRng::new(42);
3400 assert_eq!(RNG.state(), 42);
3401 }
3402
3403 #[test]
3404 fn test_deterministic_clock_const_methods() {
3405 const CLOCK: DeterministicClock = DeterministicClock::new(100, 10);
3407 const NS: u64 = CLOCK.now_ns();
3408 const DUR: Duration = CLOCK.now();
3409
3410 assert_eq!(NS, 100);
3411 assert_eq!(DUR.as_nanos(), 100);
3412 }
3413
3414 #[test]
3415 fn test_guarded_brick_empty_guards_check_passes() {
3416 use crate::brick::{Brick, BrickAssertion, BrickBudget, BrickVerification};
3417
3418 struct EmptyGuardBrick;
3419 impl Brick for EmptyGuardBrick {
3420 fn brick_name(&self) -> &'static str {
3421 "EmptyGuardBrick"
3422 }
3423 fn assertions(&self) -> &[BrickAssertion] {
3424 &[]
3425 }
3426 fn budget(&self) -> BrickBudget {
3427 BrickBudget::uniform(16)
3428 }
3429 fn verify(&self) -> BrickVerification {
3430 BrickVerification {
3431 passed: vec![],
3432 failed: vec![],
3433 verification_time: Duration::ZERO,
3434 }
3435 }
3436 fn to_html(&self) -> String {
3437 String::new()
3438 }
3439 fn to_css(&self) -> String {
3440 String::new()
3441 }
3442 }
3443
3444 let guarded = GuardedBrick::new(EmptyGuardBrick);
3445
3446 let state = BrickState::new();
3448 assert!(guarded.check_guards(&state).is_ok());
3449
3450 let mut state2 = BrickState::new();
3452 state2.set_tensor("data", vec![1.0, 2.0], vec![2]);
3453 state2.set_metadata("key", StateValue::String("value".into()));
3454 assert!(guarded.check_guards(&state2).is_ok());
3455 }
3456
3457 #[test]
3458 fn test_brick_history_record_not_at_end_truncates() {
3459 let mut history = BrickHistory::new(10);
3460
3461 for i in 0..5 {
3463 let mut state = BrickState::new();
3464 state.set_metadata("val", StateValue::Int(i));
3465 let trace = ExecutionTrace {
3466 operation: format!("op{}", i),
3467 input_summary: String::new(),
3468 output_summary: String::new(),
3469 duration: Duration::ZERO,
3470 state_version_before: i as u64,
3471 state_version_after: (i + 1) as u64,
3472 };
3473 history.record(state, trace);
3474 }
3475
3476 assert_eq!(history.len(), 5);
3477
3478 history.goto(3);
3480 assert_eq!(history.position(), 3);
3481
3482 let mut new_state = BrickState::new();
3484 new_state.set_metadata("val", StateValue::Int(100));
3485 let trace = ExecutionTrace {
3486 operation: "new_op".into(),
3487 input_summary: String::new(),
3488 output_summary: String::new(),
3489 duration: Duration::ZERO,
3490 state_version_before: 3,
3491 state_version_after: 4,
3492 };
3493 history.record(new_state, trace);
3494
3495 assert_eq!(history.len(), 4);
3497 assert_eq!(history.position(), 4);
3498
3499 let last = history.goto(3).unwrap();
3501 assert_eq!(last.get_metadata("val"), Some(&StateValue::Int(100)));
3502
3503 let traces = history.traces();
3505 assert_eq!(traces.len(), 4);
3506 assert_eq!(traces[3].operation, "new_op");
3507 }
3508
3509 #[test]
3510 fn test_execution_trace_clone_preserves_all_fields() {
3511 let original = ExecutionTrace {
3512 operation: "test_op".into(),
3513 input_summary: "test_input".into(),
3514 output_summary: "test_output".into(),
3515 duration: Duration::from_micros(12345),
3516 state_version_before: 10,
3517 state_version_after: 11,
3518 };
3519
3520 let cloned = original.clone();
3521
3522 assert_eq!(original.operation, cloned.operation);
3523 assert_eq!(original.input_summary, cloned.input_summary);
3524 assert_eq!(original.output_summary, cloned.output_summary);
3525 assert_eq!(original.duration, cloned.duration);
3526 assert_eq!(original.state_version_before, cloned.state_version_before);
3527 assert_eq!(original.state_version_after, cloned.state_version_after);
3528 }
3529
3530 #[test]
3531 fn test_brick_state_set_tensor_with_into() {
3532 let mut state = BrickState::new();
3533
3534 state.set_tensor(String::from("tensor1"), vec![1.0], vec![1]);
3536 assert!(state.get_tensor("tensor1").is_some());
3537
3538 state.set_tensor("tensor2", vec![2.0], vec![1]);
3540 assert!(state.get_tensor("tensor2").is_some());
3541 }
3542
3543 #[test]
3544 fn test_brick_state_set_metadata_with_into() {
3545 let mut state = BrickState::new();
3546
3547 state.set_metadata(String::from("key1"), StateValue::Int(1));
3549 assert!(state.get_metadata("key1").is_some());
3550
3551 state.set_metadata("key2", StateValue::Int(2));
3553 assert!(state.get_metadata("key2").is_some());
3554 }
3555
3556 #[test]
3557 fn test_guard_violation_source_is_none() {
3558 use std::error::Error;
3559
3560 let violation = GuardViolation {
3561 guard_name: "test",
3562 severity: GuardSeverity::Error,
3563 };
3564
3565 assert!(violation.source().is_none());
3567 }
3568
3569 #[test]
3570 fn test_brick_history_goto_returns_state_at_position() {
3571 let mut history = BrickHistory::new(10);
3572
3573 for i in 0..3 {
3575 let mut state = BrickState::new();
3576 state.set_metadata("idx", StateValue::Int(i * 10));
3577 let trace = ExecutionTrace {
3578 operation: format!("op{}", i),
3579 input_summary: String::new(),
3580 output_summary: String::new(),
3581 duration: Duration::ZERO,
3582 state_version_before: i as u64,
3583 state_version_after: (i + 1) as u64,
3584 };
3585 history.record(state, trace);
3586 }
3587
3588 let state0 = history.goto(0).unwrap();
3590 assert_eq!(state0.get_metadata("idx"), Some(&StateValue::Int(0)));
3591
3592 let state1 = history.goto(1).unwrap();
3593 assert_eq!(state1.get_metadata("idx"), Some(&StateValue::Int(10)));
3594
3595 let state2 = history.goto(2).unwrap();
3596 assert_eq!(state2.get_metadata("idx"), Some(&StateValue::Int(20)));
3597
3598 assert!(history.goto(3).is_none());
3600 assert!(history.goto(100).is_none());
3601 }
3602
3603 #[test]
3604 fn test_deterministic_rng_xorshift_sequence() {
3605 let mut rng = DeterministicRng::new(1);
3607
3608 let v1 = rng.next_u64();
3610 let v2 = rng.next_u64();
3611 let v3 = rng.next_u64();
3612
3613 assert_ne!(v1, v2);
3615 assert_ne!(v2, v3);
3616 assert_ne!(v1, v3);
3617
3618 let mut rng2 = DeterministicRng::new(1);
3620 assert_eq!(v1, rng2.next_u64());
3621 assert_eq!(v2, rng2.next_u64());
3622 assert_eq!(v3, rng2.next_u64());
3623 }
3624
3625 #[test]
3626 fn test_brick_state_get_tensor_returns_none_for_missing_data() {
3627 let mut state = BrickState::new();
3628
3629 state.shapes.insert("only_shape".into(), vec![2, 3]);
3631 assert!(state.get_tensor("only_shape").is_none());
3632
3633 state.tensors.insert("only_data".into(), vec![1.0, 2.0]);
3635 assert!(state.get_tensor("only_data").is_none());
3636
3637 state.tensors.insert("both".into(), vec![1.0, 2.0]);
3639 state.shapes.insert("both".into(), vec![2]);
3640 assert!(state.get_tensor("both").is_some());
3641 }
3642}