Skip to main content

batuta/oracle/falsify/
template.rs

1//! 100-Point Falsification Template
2//!
3//! Defines the structure and point allocation for falsification categories.
4
5use serde::{Deserialize, Serialize};
6
7/// The 100-point falsification template
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct FalsificationTemplate {
10    /// Test categories with point allocations
11    pub categories: Vec<CategoryTemplate>,
12}
13
14impl Default for FalsificationTemplate {
15    fn default() -> Self {
16        Self {
17            categories: vec![
18                CategoryTemplate::boundary(),
19                CategoryTemplate::invariant(),
20                CategoryTemplate::numerical(),
21                CategoryTemplate::concurrency(),
22                CategoryTemplate::resource(),
23                CategoryTemplate::parity(),
24            ],
25        }
26    }
27}
28
29impl FalsificationTemplate {
30    /// Total points across all categories
31    pub fn total_points(&self) -> u32 {
32        self.categories.iter().map(|c| c.total_points()).sum()
33    }
34
35    /// Scale template to target point count
36    pub fn scale_to_points(&self, target: u32) -> Self {
37        let current = self.total_points();
38        if current == target {
39            return self.clone();
40        }
41
42        let scale = target as f64 / current as f64;
43        let mut scaled = self.clone();
44
45        for category in &mut scaled.categories {
46            for test in &mut category.tests {
47                test.points = ((test.points as f64) * scale).round() as u32;
48            }
49        }
50
51        scaled
52    }
53
54    /// Get category by name
55    pub fn get_category(&self, name: &str) -> Option<&CategoryTemplate> {
56        self.categories.iter().find(|c| c.name == name)
57    }
58}
59
60/// A category of falsification tests
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct CategoryTemplate {
63    /// Category name (e.g., "boundary")
64    pub name: String,
65    /// Category ID prefix (e.g., "BC")
66    pub id_prefix: String,
67    /// Description
68    pub description: String,
69    /// Test templates
70    pub tests: Vec<TestTemplate>,
71}
72
73impl CategoryTemplate {
74    /// Total points for this category
75    pub fn total_points(&self) -> u32 {
76        self.tests.iter().map(|t| t.points).sum()
77    }
78
79    /// Boundary conditions category (20 points)
80    pub fn boundary() -> Self {
81        Self {
82            name: "boundary".to_string(),
83            id_prefix: "BC".to_string(),
84            description: "Boundary condition tests".to_string(),
85            tests: vec![
86                TestTemplate {
87                    id: "BC-001".to_string(),
88                    name: "Empty input".to_string(),
89                    description: "Handle empty/null input gracefully".to_string(),
90                    severity: TestSeverity::Critical,
91                    points: 4,
92                    rust_template: Some(RUST_EMPTY_INPUT.to_string()),
93                    python_template: Some(PYTHON_EMPTY_INPUT.to_string()),
94                },
95                TestTemplate {
96                    id: "BC-002".to_string(),
97                    name: "Maximum size input".to_string(),
98                    description: "Handle maximum allowed input size".to_string(),
99                    severity: TestSeverity::Critical,
100                    points: 4,
101                    rust_template: Some(RUST_MAX_INPUT.to_string()),
102                    python_template: Some(PYTHON_MAX_INPUT.to_string()),
103                },
104                TestTemplate {
105                    id: "BC-003".to_string(),
106                    name: "Negative values".to_string(),
107                    description: "Handle negative values where positive expected".to_string(),
108                    severity: TestSeverity::High,
109                    points: 4,
110                    rust_template: Some(RUST_NEGATIVE.to_string()),
111                    python_template: Some(PYTHON_NEGATIVE.to_string()),
112                },
113                TestTemplate {
114                    id: "BC-004".to_string(),
115                    name: "Unicode edge cases".to_string(),
116                    description: "Handle combining chars, RTL, zero-width".to_string(),
117                    severity: TestSeverity::Medium,
118                    points: 4,
119                    rust_template: Some(RUST_UNICODE.to_string()),
120                    python_template: Some(PYTHON_UNICODE.to_string()),
121                },
122                TestTemplate {
123                    id: "BC-005".to_string(),
124                    name: "Numeric limits".to_string(),
125                    description: "Handle MAX_INT, MIN_INT, NaN, Inf".to_string(),
126                    severity: TestSeverity::Critical,
127                    points: 4,
128                    rust_template: Some(RUST_NUMERIC_LIMITS.to_string()),
129                    python_template: Some(PYTHON_NUMERIC_LIMITS.to_string()),
130                },
131            ],
132        }
133    }
134
135    /// Invariant violations category (20 points)
136    pub fn invariant() -> Self {
137        Self {
138            name: "invariant".to_string(),
139            id_prefix: "INV".to_string(),
140            description: "Mathematical invariant tests".to_string(),
141            tests: vec![
142                TestTemplate {
143                    id: "INV-001".to_string(),
144                    name: "Idempotency".to_string(),
145                    description: "f(f(x)) == f(x) for idempotent operations".to_string(),
146                    severity: TestSeverity::High,
147                    points: 5,
148                    rust_template: Some(RUST_IDEMPOTENT.to_string()),
149                    python_template: Some(PYTHON_IDEMPOTENT.to_string()),
150                },
151                TestTemplate {
152                    id: "INV-002".to_string(),
153                    name: "Commutativity".to_string(),
154                    description: "f(a,b) == f(b,a) for commutative operations".to_string(),
155                    severity: TestSeverity::High,
156                    points: 5,
157                    rust_template: Some(RUST_COMMUTATIVE.to_string()),
158                    python_template: Some(PYTHON_COMMUTATIVE.to_string()),
159                },
160                TestTemplate {
161                    id: "INV-003".to_string(),
162                    name: "Associativity".to_string(),
163                    description: "(a+b)+c == a+(b+c) for floating point".to_string(),
164                    severity: TestSeverity::Medium,
165                    points: 5,
166                    rust_template: Some(RUST_ASSOCIATIVE.to_string()),
167                    python_template: Some(PYTHON_ASSOCIATIVE.to_string()),
168                },
169                TestTemplate {
170                    id: "INV-004".to_string(),
171                    name: "Symmetry (encode/decode)".to_string(),
172                    description: "decode(encode(x)) == x for serialization".to_string(),
173                    severity: TestSeverity::Critical,
174                    points: 5,
175                    rust_template: Some(RUST_ROUNDTRIP.to_string()),
176                    python_template: Some(PYTHON_ROUNDTRIP.to_string()),
177                },
178            ],
179        }
180    }
181
182    /// Numerical stability category (20 points)
183    pub fn numerical() -> Self {
184        Self {
185            name: "numerical".to_string(),
186            id_prefix: "NUM".to_string(),
187            description: "Numerical stability tests".to_string(),
188            tests: vec![
189                TestTemplate {
190                    id: "NUM-001".to_string(),
191                    name: "Catastrophic cancellation".to_string(),
192                    description: "1e10 + 1 - 1e10 should not lose precision".to_string(),
193                    severity: TestSeverity::High,
194                    points: 7,
195                    rust_template: Some(RUST_CANCELLATION.to_string()),
196                    python_template: Some(PYTHON_CANCELLATION.to_string()),
197                },
198                TestTemplate {
199                    id: "NUM-002".to_string(),
200                    name: "Accumulation order".to_string(),
201                    description: "sum(shuffled) vs sum(sorted) within tolerance".to_string(),
202                    severity: TestSeverity::Medium,
203                    points: 7,
204                    rust_template: Some(RUST_ACCUMULATION.to_string()),
205                    python_template: Some(PYTHON_ACCUMULATION.to_string()),
206                },
207                TestTemplate {
208                    id: "NUM-003".to_string(),
209                    name: "Denormalized numbers".to_string(),
210                    description: "Handle subnormal/denormalized floats".to_string(),
211                    severity: TestSeverity::Medium,
212                    points: 6,
213                    rust_template: Some(RUST_DENORMAL.to_string()),
214                    python_template: Some(PYTHON_DENORMAL.to_string()),
215                },
216            ],
217        }
218    }
219
220    /// Concurrency category (15 points)
221    pub fn concurrency() -> Self {
222        Self {
223            name: "concurrency".to_string(),
224            id_prefix: "CONC".to_string(),
225            description: "Concurrency and race condition tests".to_string(),
226            tests: vec![
227                TestTemplate {
228                    id: "CONC-001".to_string(),
229                    name: "Data race".to_string(),
230                    description: "No data races under parallel iteration".to_string(),
231                    severity: TestSeverity::Critical,
232                    points: 5,
233                    rust_template: Some(RUST_DATA_RACE.to_string()),
234                    python_template: Some(PYTHON_DATA_RACE.to_string()),
235                },
236                TestTemplate {
237                    id: "CONC-002".to_string(),
238                    name: "Deadlock".to_string(),
239                    description: "No deadlock potential in lock ordering".to_string(),
240                    severity: TestSeverity::Critical,
241                    points: 5,
242                    rust_template: Some(RUST_DEADLOCK.to_string()),
243                    python_template: Some(PYTHON_DEADLOCK.to_string()),
244                },
245                TestTemplate {
246                    id: "CONC-003".to_string(),
247                    name: "ABA problem".to_string(),
248                    description: "Lock-free structures handle ABA".to_string(),
249                    severity: TestSeverity::High,
250                    points: 5,
251                    rust_template: Some(RUST_ABA.to_string()),
252                    python_template: Some(PYTHON_ABA.to_string()),
253                },
254            ],
255        }
256    }
257
258    /// Resource exhaustion category (15 points)
259    pub fn resource() -> Self {
260        Self {
261            name: "resource".to_string(),
262            id_prefix: "RES".to_string(),
263            description: "Resource exhaustion tests".to_string(),
264            tests: vec![
265                TestTemplate {
266                    id: "RES-001".to_string(),
267                    name: "Memory exhaustion".to_string(),
268                    description: "Controlled behavior under OOM".to_string(),
269                    severity: TestSeverity::High,
270                    points: 5,
271                    rust_template: Some(RUST_MEMORY.to_string()),
272                    python_template: Some(PYTHON_MEMORY.to_string()),
273                },
274                TestTemplate {
275                    id: "RES-002".to_string(),
276                    name: "File descriptor exhaustion".to_string(),
277                    description: "Handle FD limits gracefully".to_string(),
278                    severity: TestSeverity::Medium,
279                    points: 5,
280                    rust_template: Some(RUST_FD.to_string()),
281                    python_template: Some(PYTHON_FD.to_string()),
282                },
283                TestTemplate {
284                    id: "RES-003".to_string(),
285                    name: "Stack overflow".to_string(),
286                    description: "Deep recursion handled".to_string(),
287                    severity: TestSeverity::High,
288                    points: 5,
289                    rust_template: Some(RUST_STACK.to_string()),
290                    python_template: Some(PYTHON_STACK.to_string()),
291                },
292            ],
293        }
294    }
295
296    /// Cross-implementation parity category (10 points)
297    pub fn parity() -> Self {
298        Self {
299            name: "parity".to_string(),
300            id_prefix: "PAR".to_string(),
301            description: "Cross-implementation parity tests".to_string(),
302            tests: vec![
303                TestTemplate {
304                    id: "PAR-001".to_string(),
305                    name: "Python/Rust parity".to_string(),
306                    description: "Output matches reference Python implementation".to_string(),
307                    severity: TestSeverity::High,
308                    points: 5,
309                    rust_template: Some(RUST_PYTHON_PARITY.to_string()),
310                    python_template: Some(PYTHON_RUST_PARITY.to_string()),
311                },
312                TestTemplate {
313                    id: "PAR-002".to_string(),
314                    name: "CPU/GPU parity".to_string(),
315                    description: "CPU and GPU kernels produce same results".to_string(),
316                    severity: TestSeverity::High,
317                    points: 5,
318                    rust_template: Some(RUST_GPU_PARITY.to_string()),
319                    python_template: Some(PYTHON_GPU_PARITY.to_string()),
320                },
321            ],
322        }
323    }
324}
325
326/// A single test template
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct TestTemplate {
329    /// Test ID (e.g., "BC-001")
330    pub id: String,
331    /// Test name
332    pub name: String,
333    /// Description
334    pub description: String,
335    /// Severity level
336    pub severity: TestSeverity,
337    /// Point value
338    pub points: u32,
339    /// Rust code template
340    pub rust_template: Option<String>,
341    /// Python code template
342    pub python_template: Option<String>,
343}
344
345/// Severity level
346#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
347pub enum TestSeverity {
348    Critical,
349    High,
350    Medium,
351    Low,
352}
353
354// Rust templates
355const RUST_EMPTY_INPUT: &str = r#"#[test]
356fn falsify_{{id_lower}}_empty_input() {
357    let result = {{module}}::{{function}}(&[]);
358    assert!(result.is_err() || result.expect("operation failed").is_empty(),
359        "Should handle empty input gracefully");
360}"#;
361
362const RUST_MAX_INPUT: &str = r#"#[test]
363fn falsify_{{id_lower}}_max_input() {
364    let large_input = vec![0u8; {{max_size}}];
365    let result = {{module}}::{{function}}(&large_input);
366    assert!(result.is_ok(), "Should handle maximum size input");
367}"#;
368
369const RUST_NEGATIVE: &str = r#"#[test]
370fn falsify_{{id_lower}}_negative_values() {
371    let result = {{module}}::{{function}}(-1);
372    assert!(result.is_err(), "Should reject negative values");
373}"#;
374
375const RUST_UNICODE: &str = r#"#[test]
376fn falsify_{{id_lower}}_unicode() {
377    // Combining characters, RTL, zero-width
378    let inputs = ["café\u{0301}", "\u{202E}test", "a\u{200B}b"];
379    for input in inputs {
380        let result = {{module}}::{{function}}(input);
381        assert!(result.is_ok(), "Should handle Unicode: {}", input);
382    }
383}"#;
384
385const RUST_NUMERIC_LIMITS: &str = r#"#[test]
386fn falsify_{{id_lower}}_numeric_limits() {
387    let values = [f64::MAX, f64::MIN, f64::NAN, f64::INFINITY, f64::NEG_INFINITY];
388    for val in values {
389        let result = {{module}}::{{function}}(val);
390        assert!(!result.is_nan() || val.is_nan(), "Should handle {:?}", val);
391    }
392}"#;
393
394const RUST_IDEMPOTENT: &str = r#"proptest! {
395    #[test]
396    fn falsify_{{id_lower}}_idempotent(x in any::<{{type}}>()) {
397        let once = {{module}}::{{function}}(&x);
398        let twice = {{module}}::{{function}}(&once);
399        prop_assert_eq!(once, twice, "f(f(x)) should equal f(x)");
400    }
401}"#;
402
403const RUST_COMMUTATIVE: &str = r#"proptest! {
404    #[test]
405    fn falsify_{{id_lower}}_commutative(
406        a in any::<{{type}}>(),
407        b in any::<{{type}}>()
408    ) {
409        let ab = {{module}}::{{function}}(&a, &b);
410        let ba = {{module}}::{{function}}(&b, &a);
411        prop_assert_eq!(ab, ba, "f(a,b) should equal f(b,a)");
412    }
413}"#;
414
415const RUST_ASSOCIATIVE: &str = r#"proptest! {
416    #[test]
417    fn falsify_{{id_lower}}_associative(
418        a in -1e6f64..1e6,
419        b in -1e6f64..1e6,
420        c in -1e6f64..1e6
421    ) {
422        let ab_c = (a + b) + c;
423        let a_bc = a + (b + c);
424        // Allow small tolerance for floating point
425        prop_assert!((ab_c - a_bc).abs() < 1e-10,
426            "(a+b)+c vs a+(b+c): {} vs {}", ab_c, a_bc);
427    }
428}"#;
429
430const RUST_ROUNDTRIP: &str = r#"proptest! {
431    #[test]
432    fn falsify_{{id_lower}}_roundtrip(x in any::<{{type}}>()) {
433        let encoded = {{module}}::encode(&x);
434        let decoded = {{module}}::decode(&encoded).expect("unexpected failure");
435        prop_assert_eq!(x, decoded, "decode(encode(x)) should equal x");
436    }
437}"#;
438
439const RUST_CANCELLATION: &str = r#"#[test]
440fn falsify_{{id_lower}}_cancellation() {
441    let big = 1e15f64;
442    let small = 1.0;
443    let result = (big + small) - big;
444    assert!((result - small).abs() < 1e-10,
445        "Catastrophic cancellation: expected {}, got {}", small, result);
446}"#;
447
448const RUST_ACCUMULATION: &str = r#"proptest! {
449    #[test]
450    fn falsify_{{id_lower}}_accumulation(mut values in prop::collection::vec(-1e6f64..1e6, 10..100)) {
451        let sum_original: f64 = values.iter().sum();
452        values.sort_by(|a, b| a.partial_cmp(b).expect("comparison failed"));
453        let sum_sorted: f64 = values.iter().sum();
454        prop_assert!((sum_original - sum_sorted).abs() < 1e-6,
455            "Accumulation order matters: {} vs {}", sum_original, sum_sorted);
456    }
457}"#;
458
459const RUST_DENORMAL: &str = r#"#[test]
460fn falsify_{{id_lower}}_denormal() {
461    let denormal = 1e-308f64 * 1e-10;
462    assert!(denormal > 0.0 || denormal == 0.0,
463        "Should handle denormalized numbers");
464    let result = {{module}}::{{function}}(denormal);
465    assert!(!result.is_nan(), "Should not produce NaN from denormal");
466}"#;
467
468const RUST_DATA_RACE: &str = r#"#[test]
469fn falsify_{{id_lower}}_data_race() {
470    use std::sync::Arc;
471    use std::thread;
472
473    let data = Arc::new({{module}}::{{type}}::new());
474    let handles: Vec<_> = (0..10).map(|i| {
475        let data = Arc::clone(&data);
476        thread::spawn(move || {
477            data.operation(i);
478        })
479    }).collect();
480
481    for h in handles {
482        h.join().expect("Thread should not panic");
483    }
484}"#;
485
486const RUST_DEADLOCK: &str = r#"#[test]
487fn falsify_{{id_lower}}_deadlock() {
488    use std::time::Duration;
489    use std::sync::mpsc::channel;
490
491    let (tx, rx) = channel();
492    let handle = std::thread::spawn(move || {
493        {{module}}::potentially_blocking_operation();
494        tx.send(()).expect("channel send failed");
495    });
496
497    // Should complete within timeout
498    let result = rx.recv_timeout(Duration::from_secs(5));
499    assert!(result.is_ok(), "Operation should complete without deadlock");
500    handle.join().expect("thread join failed");
501}"#;
502
503const RUST_ABA: &str = r#"#[test]
504fn falsify_{{id_lower}}_aba() {
505    use std::sync::atomic::{AtomicUsize, Ordering};
506
507    let counter = AtomicUsize::new(0);
508    // Simulate ABA: 0 -> 1 -> 0
509    counter.store(1, Ordering::SeqCst);
510    counter.store(0, Ordering::SeqCst);
511
512    // CAS should detect the change
513    let result = {{module}}::atomic_operation(&counter);
514    assert!(result.is_ok(), "Should handle ABA problem");
515}"#;
516
517const RUST_MEMORY: &str = r"#[test]
518fn falsify_{{id_lower}}_memory() {
519    // Attempt allocation that might fail
520    let result = std::panic::catch_unwind(|| {
521        let _large = vec![0u8; 1_000_000_000]; // 1GB
522    });
523    // Should either succeed or fail gracefully
524    // (this test mainly verifies no UB on allocation failure)
525}";
526
527const RUST_FD: &str = r#"#[test]
528fn falsify_{{id_lower}}_fd_exhaustion() {
529    use std::fs::File;
530
531    let mut files = Vec::new();
532    for i in 0..10000 {
533        match File::create(format!("/tmp/test_{}", i)) {
534            Ok(f) => files.push(f),
535            Err(_) => break,
536        }
537    }
538    // Cleanup
539    for (i, _) in files.iter().enumerate() {
540        let _ = std::fs::remove_file(format!("/tmp/test_{}", i));
541    }
542    // Main test: verify module handles FD limits
543    let result = {{module}}::{{function}}();
544    assert!(result.is_ok(), "Should handle FD exhaustion gracefully");
545}"#;
546
547const RUST_STACK: &str = r#"#[test]
548fn falsify_{{id_lower}}_stack_overflow() {
549    // Test with iterative approach that might overflow naive recursion
550    let result = std::panic::catch_unwind(|| {
551        {{module}}::deep_operation(10000);
552    });
553    assert!(result.is_ok(), "Should handle deep recursion without stack overflow");
554}"#;
555
556const RUST_PYTHON_PARITY: &str = r#"#[test]
557fn falsify_{{id_lower}}_python_parity() {
558    // Reference values from Python implementation
559    let test_cases = vec![
560        (vec![1.0, 2.0, 3.0], vec![1.0, 2.0, 3.0]), // Expected output
561    ];
562
563    for (input, expected) in test_cases {
564        let result = {{module}}::{{function}}(&input);
565        assert_eq!(result, expected, "Should match Python reference");
566    }
567}"#;
568
569const RUST_GPU_PARITY: &str = r#"#[test]
570fn falsify_{{id_lower}}_gpu_parity() {
571    let input = vec![1.0f32; 1024];
572
573    let cpu_result = {{module}}::cpu_{{function}}(&input);
574    let gpu_result = {{module}}::gpu_{{function}}(&input);
575
576    for (cpu, gpu) in cpu_result.iter().zip(gpu_result.iter()) {
577        assert!((cpu - gpu).abs() < 1e-5,
578            "CPU/GPU mismatch: {} vs {}", cpu, gpu);
579    }
580}"#;
581
582// Python templates
583const PYTHON_EMPTY_INPUT: &str = r#"    result = module.function([])
584    assert result is None or len(result) == 0, "Should handle empty input"
585"#;
586
587const PYTHON_MAX_INPUT: &str = r#"    large_input = [0] * {{max_size}}
588    result = module.function(large_input)
589    assert result is not None, "Should handle maximum size input"
590"#;
591
592const PYTHON_NEGATIVE: &str = r"    with pytest.raises(ValueError):
593        module.function(-1)
594";
595
596const PYTHON_UNICODE: &str = r#"    inputs = ["café\u0301", "\u202Etest", "a\u200Bb"]
597    for inp in inputs:
598        result = module.function(inp)
599        assert result is not None, f"Should handle Unicode: {inp}"
600"#;
601
602const PYTHON_NUMERIC_LIMITS: &str = r"    import math
603    values = [float('inf'), float('-inf'), float('nan'), 1e308, -1e308]
604    for val in values:
605        result = module.function(val)
606        assert not math.isnan(result) or math.isnan(val)
607";
608
609const PYTHON_IDEMPOTENT: &str = r#"@given(st.{{strategy}}())
610def test_{{id_lower}}_idempotent(x):
611    once = module.function(x)
612    twice = module.function(once)
613    assert once == twice, "f(f(x)) should equal f(x)"
614"#;
615
616const PYTHON_COMMUTATIVE: &str = r#"@given(st.{{strategy}}(), st.{{strategy}}())
617def test_{{id_lower}}_commutative(a, b):
618    ab = module.function(a, b)
619    ba = module.function(b, a)
620    assert ab == ba, "f(a,b) should equal f(b,a)"
621"#;
622
623const PYTHON_ASSOCIATIVE: &str = r#"@given(st.floats(-1e6, 1e6), st.floats(-1e6, 1e6), st.floats(-1e6, 1e6))
624def test_{{id_lower}}_associative(a, b, c):
625    ab_c = (a + b) + c
626    a_bc = a + (b + c)
627    assert abs(ab_c - a_bc) < 1e-10, f"(a+b)+c vs a+(b+c): {ab_c} vs {a_bc}"
628"#;
629
630const PYTHON_ROUNDTRIP: &str = r#"@given(st.{{strategy}}())
631def test_{{id_lower}}_roundtrip(x):
632    encoded = module.encode(x)
633    decoded = module.decode(encoded)
634    assert x == decoded, "decode(encode(x)) should equal x"
635"#;
636
637const PYTHON_CANCELLATION: &str = r#"    big = 1e15
638    small = 1.0
639    result = (big + small) - big
640    assert abs(result - small) < 1e-10, f"Catastrophic cancellation: expected {small}, got {result}"
641"#;
642
643const PYTHON_ACCUMULATION: &str = r"@given(st.lists(st.floats(-1e6, 1e6), min_size=10, max_size=100))
644def test_{{id_lower}}_accumulation(values):
645    sum_original = sum(values)
646    sum_sorted = sum(sorted(values))
647    assert abs(sum_original - sum_sorted) < 1e-6
648";
649
650const PYTHON_DENORMAL: &str = r#"    denormal = 1e-308 * 1e-10
651    result = module.function(denormal)
652    assert not math.isnan(result), "Should not produce NaN from denormal"
653"#;
654
655const PYTHON_DATA_RACE: &str = r#"    import threading
656
657    errors = []
658    def worker(i):
659        try:
660            module.operation(i)
661        except Exception as e:
662            errors.append(e)
663
664    threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
665    for t in threads:
666        t.start()
667    for t in threads:
668        t.join()
669
670    assert len(errors) == 0, f"Data race detected: {errors}"
671"#;
672
673const PYTHON_DEADLOCK: &str = r#"    import threading
674    import queue
675
676    q = queue.Queue()
677
678    def worker():
679        module.potentially_blocking_operation()
680        q.put(True)
681
682    t = threading.Thread(target=worker)
683    t.start()
684
685    try:
686        q.get(timeout=5)
687    except queue.Empty:
688        pytest.fail("Operation deadlocked")
689    t.join()
690"#;
691
692const PYTHON_ABA: &str = r#"    # ABA problem test
693    counter = [0]
694    counter[0] = 1
695    counter[0] = 0
696    result = module.atomic_operation(counter)
697    assert result is not None, "Should handle ABA problem"
698"#;
699
700const PYTHON_MEMORY: &str = r"    try:
701        large = [0] * 1_000_000_000
702    except MemoryError:
703        pass  # Expected
704    # Main test: verify module handles memory limits
705    result = module.function_with_limit()
706    assert result is not None
707";
708
709const PYTHON_FD: &str = r#"    import os
710    files = []
711    try:
712        for i in range(10000):
713            f = open(f'/tmp/test_{i}', 'w')
714            files.append(f)
715    except OSError:
716        pass  # FD limit reached
717
718    for f in files:
719        f.close()
720    for i in range(len(files)):
721        os.remove(f'/tmp/test_{i}')
722
723    result = module.function()
724    assert result is not None, "Should handle FD exhaustion"
725"#;
726
727const PYTHON_STACK: &str = r"    import sys
728    old_limit = sys.getrecursionlimit()
729    sys.setrecursionlimit(100000)
730
731    try:
732        result = module.deep_operation(10000)
733        assert result is not None
734    finally:
735        sys.setrecursionlimit(old_limit)
736";
737
738const PYTHON_RUST_PARITY: &str = r#"    # Reference values from Rust implementation
739    test_cases = [
740        ([1.0, 2.0, 3.0], [1.0, 2.0, 3.0]),
741    ]
742
743    for input_data, expected in test_cases:
744        result = module.function(input_data)
745        assert result == expected, "Should match Rust reference"
746"#;
747
748const PYTHON_GPU_PARITY: &str = r#"    import numpy as np
749
750    input_data = np.ones(1024, dtype=np.float32)
751
752    cpu_result = module.cpu_function(input_data)
753    gpu_result = module.gpu_function(input_data)
754
755    np.testing.assert_allclose(cpu_result, gpu_result, rtol=1e-5,
756        err_msg="CPU/GPU mismatch")
757"#;
758
759#[cfg(test)]
760mod tests {
761    use super::*;
762
763    #[test]
764    fn test_default_template() {
765        let template = FalsificationTemplate::default();
766        assert_eq!(template.total_points(), 100);
767    }
768
769    #[test]
770    fn test_category_points() {
771        let boundary = CategoryTemplate::boundary();
772        assert_eq!(boundary.total_points(), 20);
773
774        let invariant = CategoryTemplate::invariant();
775        assert_eq!(invariant.total_points(), 20);
776
777        let numerical = CategoryTemplate::numerical();
778        assert_eq!(numerical.total_points(), 20);
779
780        let concurrency = CategoryTemplate::concurrency();
781        assert_eq!(concurrency.total_points(), 15);
782
783        let resource = CategoryTemplate::resource();
784        assert_eq!(resource.total_points(), 15);
785
786        let parity = CategoryTemplate::parity();
787        assert_eq!(parity.total_points(), 10);
788    }
789
790    #[test]
791    fn test_scale_template() {
792        let template = FalsificationTemplate::default();
793        let scaled = template.scale_to_points(50);
794        // Allow larger rounding error since we scale many individual tests
795        assert!(
796            (scaled.total_points() as i32 - 50).abs() <= 20,
797            "Scaled to {} points, expected around 50",
798            scaled.total_points()
799        );
800    }
801}