use crate::models::{Config, Result};
use crate::transpile;
pub struct BoundaryTester {
config: Config,
test_count: usize,
}
impl BoundaryTester {
pub fn new(config: Config) -> Self {
Self {
config,
test_count: 0,
}
}
pub fn run_all_boundary_tests(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
results.merge(self.test_integer_boundaries()?);
results.merge(self.test_string_boundaries()?);
results.merge(self.test_memory_boundaries()?);
results.merge(self.test_syntax_boundaries()?);
results.merge(self.test_unicode_boundaries()?);
results.merge(self.test_nesting_boundaries()?);
Ok(results)
}
pub fn test_integer_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
let test_cases = vec![
("0", true),
("1", true),
("-1", false), ("4294967295", true), ("4294967296", false), ("255", true), ("256", true), ("65535", true), ("65536", true), ("2147483647", true), ("2147483648", true), ("00042", true),
("000000000000042", true),
("0x42", false),
("0xFF", false),
];
for (input, should_succeed) in test_cases {
let source = format!("fn main() {{ let x = {input}; }}");
let result = self.test_transpile(&source);
match (result.is_ok(), should_succeed) {
(true, true) => results.passed += 1,
(false, false) => results.passed += 1,
_ => {
results.failed += 1;
results.failures.push(format!(
"Integer boundary test failed for: {} (expected: {})",
input,
if should_succeed { "success" } else { "failure" }
));
}
}
results.total += 1;
}
let arithmetic_cases = vec![
"let x = 2147483647; let y = x + 1;", "let x = 0; let y = x - 1;", "let x = 1000000; let y = x * x;", ];
for case in arithmetic_cases {
let source = format!("fn main() {{ {case} }}");
let result = self.test_transpile(&source);
if result.is_ok() {
results.passed += 1;
} else {
results.failed += 1;
results
.failures
.push(format!("Arithmetic boundary test failed: {case}"));
}
results.total += 1;
}
Ok(results)
}
pub fn test_string_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
results.merge_test(self.test_transpile(r#"fn main() { let x = ""; }"#), true);
for ch in ['a', '0', ' ', '\t', '\n'] {
let source = format!(r#"fn main() {{ let x = "{ch}"; }}"#);
results.merge_test(self.test_transpile(&source), true);
}
let special_chars = vec![
(r#"\""#, true), (r#"\\"#, true), (r#"\n"#, true), (r#"\t"#, true), (r#"\r"#, true), ];
for (escape_seq, should_succeed) in special_chars {
let source = format!(r#"fn main() {{ let x = "{escape_seq}"; }}"#);
results.merge_test(self.test_transpile(&source), should_succeed);
}
let sizes = vec![1, 10, 100, 1000, 10000, 100000];
for size in sizes {
let long_string = "x".repeat(size);
let source = format!(r#"fn main() {{ let x = "{long_string}"; }}"#);
results.merge_test(self.test_transpile(&source), true);
}
let mut all_ascii = String::new();
for byte in 1..128u8 {
if byte != b'"' && byte != b'\\' {
all_ascii.push(byte as char);
}
}
let source = format!(r#"fn main() {{ let x = "{all_ascii}"; }}"#);
results.merge_test(self.test_transpile(&source), true);
Ok(results)
}
pub fn test_memory_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
for count in [1, 10, 100, 1000] {
let mut lets = String::new();
for i in 0..count {
lets.push_str(&format!("let var{i} = {i}; "));
}
let source = format!("fn main() {{ {lets} }}");
results.merge_test(self.test_transpile(&source), true);
}
for param_count in [0, 1, 5, 10, 20] {
let mut params = Vec::new();
for i in 0..param_count {
params.push(format!("param{i}: u32"));
}
let source = format!("fn main({}) {{ let x = 42; }}", params.join(", "));
results.merge_test(self.test_transpile(&source), param_count <= 10);
}
Ok(results)
}
pub fn test_syntax_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
let minimal_cases = vec!["fn main(){}", "fn main(){let x=1;}", "fn main(){return;}"];
for case in minimal_cases {
results.merge_test(self.test_transpile(case), true);
}
let whitespace_cases = vec![
"fn main() { let x = 42; }", "fn main(){let x=42;}", "fn main ( ) { let x = 42 ; }", "fn\nmain()\n{\nlet\nx\n=\n42;\n}", "fn\tmain()\t{\tlet\tx\t=\t42;\t}", ];
for case in whitespace_cases {
results.merge_test(self.test_transpile(case), true);
}
let id_lengths = vec![1, 2, 10, 50, 100, 255];
for len in id_lengths {
let long_id = "a".repeat(len);
let source = format!("fn main() {{ let {long_id} = 42; }}");
results.merge_test(self.test_transpile(&source), len <= 255);
}
let comment_cases = vec![
"fn main() { /* comment */ let x = 1; }",
"fn main() { // comment\nlet x = 1; }",
"// comment\nfn main() { let x = 1; }",
];
for case in comment_cases {
results.merge_test(self.test_transpile(case), true);
}
Ok(results)
}
pub fn test_unicode_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
let unicode_cases = vec![
("α", true), ("中", true), ("🚀", true), ("𝔘𝔫𝔦𝔠𝔬𝔡𝔢", true), ];
for (unicode_char, should_succeed) in unicode_cases {
let source = format!(r#"fn main() {{ let x = "{unicode_char}"; }}"#);
results.merge_test(self.test_transpile(&source), should_succeed);
}
let unicode_id_cases = vec![("α", false), ("test_α", false), ("café", false)];
for (unicode_id, should_succeed) in unicode_id_cases {
let source = format!("fn main() {{ let {unicode_id} = 42; }}");
results.merge_test(self.test_transpile(&source), should_succeed);
}
let control_chars = vec!['\0', '\x01', '\x7F', '\u{FEFF}']; for ch in control_chars {
let source = format!("fn main() {{ let x = \"{ch}\"; }}");
results.merge_test(self.test_transpile(&source), false);
}
Ok(results)
}
pub fn test_nesting_boundaries(&mut self) -> Result<BoundaryTestResults> {
let mut results = BoundaryTestResults::default();
for depth in [1, 5, 10, 20, 50] {
let mut source = "fn main() {".to_string();
for i in 0..depth {
source.push_str(&format!("if true {{ let x{i} = {i}; "));
}
for _ in 0..depth {
source.push_str("} ");
}
source.push('}');
results.merge_test(self.test_transpile(&source), depth <= 20); }
for depth in [1, 5, 10, 15] {
let mut call_chain = "func".to_string();
for _ in 1..depth {
call_chain = format!("func({call_chain})");
}
let source = format!("fn main() {{ let x = {call_chain}; }}");
results.merge_test(self.test_transpile(&source), depth <= 10);
}
for depth in [1, 5, 10, 20] {
let mut expr = "1".to_string();
for i in 1..depth {
expr = format!("({expr} + {i})");
}
let source = format!("fn main() {{ let x = {expr}; }}");
results.merge_test(self.test_transpile(&source), depth <= 15);
}
Ok(results)
}
fn test_transpile(&mut self, input: &str) -> Result<String> {
self.test_count += 1;
transpile(input, &self.config)
}
}
#[derive(Debug, Default)]
pub struct BoundaryTestResults {
pub total: usize,
pub passed: usize,
pub failed: usize,
pub failures: Vec<String>,
}
impl BoundaryTestResults {
fn merge(&mut self, other: BoundaryTestResults) {
self.total += other.total;
self.passed += other.passed;
self.failed += other.failed;
self.failures.extend(other.failures);
}
fn merge_test(&mut self, result: Result<String>, expected_success: bool) {
self.total += 1;
match (result.is_ok(), expected_success) {
(true, true) | (false, false) => self.passed += 1,
_ => {
self.failed += 1;
self.failures.push("Test expectation mismatch".to_string());
}
}
}
pub fn success_rate(&self) -> f64 {
if self.total == 0 {
0.0
} else {
(self.passed as f64 / self.total as f64) * 100.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integer_boundaries() {
let mut tester = BoundaryTester::new(Config::default());
let results = tester.test_integer_boundaries().unwrap();
assert!(results.total > 0);
assert!(
results.success_rate() > 80.0,
"Success rate too low: {:.1}%",
results.success_rate()
);
if results.failed > 0 {
println!("Boundary test failures: {:?}", results.failures);
}
}
#[test]
fn test_string_boundaries() {
let mut tester = BoundaryTester::new(Config::default());
let results = tester.test_string_boundaries().unwrap();
assert!(results.total > 0);
assert!(
results.success_rate() > 80.0,
"Success rate too low: {:.1}%",
results.success_rate()
);
}
#[test]
fn test_all_boundaries() {
let mut tester = BoundaryTester::new(Config::default());
let results = tester.run_all_boundary_tests().unwrap();
assert!(results.total > 50, "Not enough boundary tests executed");
assert!(
results.success_rate() > 75.0,
"Overall boundary test success rate too low: {:.1}%",
results.success_rate()
);
println!(
"Boundary testing complete: {}/{} passed ({:.1}%)",
results.passed,
results.total,
results.success_rate()
);
}
}