use std::path::PathBuf;
use crate::fix::error_parser::{detect_language, parse_error};
use crate::fix::types::{FixConfidence, ParsedError};
use crate::fix::{diagnose, diagnose_parsed};
#[test]
fn test_benchmark_parser_detect_python_traceback() {
let error = "Traceback (most recent call last):\n File \"app.py\", line 10, in main\n x += 1\nNameError: name 'x' is not defined";
assert_eq!(detect_language(error), "python");
}
#[test]
fn test_benchmark_parser_detect_python_single_line() {
let error = "NameError: name 'x' is not defined";
assert_eq!(detect_language(error), "python");
}
#[test]
fn test_benchmark_parser_detect_javascript_stack() {
let error = "TypeError: Cannot read properties of undefined (reading 'foo')\n at Object.<anonymous> (file.js:1:1)";
assert_eq!(detect_language(error), "javascript");
}
#[test]
fn test_benchmark_parser_detect_javascript_reference_error() {
let error = "ReferenceError: x is not defined\n at Object.<anonymous> (file.js:1:1)";
assert_eq!(detect_language(error), "javascript");
}
#[test]
fn test_benchmark_parser_detect_typescript_full() {
let error = "app.ts(5,10): error TS2304: Cannot find name 'x'.";
assert_eq!(detect_language(error), "typescript");
}
#[test]
fn test_benchmark_parser_detect_typescript_bare() {
let error = "error TS2304: Cannot find name 'x'.";
assert_eq!(detect_language(error), "typescript");
}
#[test]
fn test_benchmark_parser_detect_rust_rendered() {
let error = "error[E0425]: cannot find value `x` in this scope";
assert_eq!(detect_language(error), "rust");
}
#[test]
fn test_benchmark_parser_detect_go_file_line() {
let error = "./main.go:5:2: undefined: x";
assert_eq!(detect_language(error), "go");
}
#[test]
fn test_benchmark_parser_detect_go_unused_var() {
let error = "x declared and not used";
assert_eq!(detect_language(error), "go");
}
#[test]
fn test_benchmark_parser_detect_ambiguous_bare_type_error() {
let error = "TypeError: 'int' object is not callable";
let lang = detect_language(error);
assert_eq!(lang, "python");
}
#[test]
fn test_benchmark_python_unbound_local_error() {
let error_text = "UnboundLocalError: cannot access local variable 'counter'";
let source = "counter = 0\ndef inc():\n counter += 1\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "UnboundLocalError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "UnboundLocalError");
assert_eq!(d.language, "python");
assert!(
d.fix.is_some(),
"UnboundLocalError should produce a fix with global injection"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("global counter"),
"Fix should inject 'global counter', got: {:?}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_python_type_error_not_callable() {
let error_text = "TypeError: 'dict' object is not callable";
let source = "d = {'a': 1}\ndef f():\n result = d.items()\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"TypeError callable must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
assert_eq!(d.language, "python");
}
#[test]
fn test_benchmark_python_type_error_json_serializable() {
let error_text = "TypeError: Object of type Foo is not JSON serializable";
let source = "from dataclasses import dataclass\nimport json\n\n@dataclass\nclass Foo:\n x: int\n\ndef f():\n obj = Foo(1)\n json.dumps(obj)\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"TypeError JSON serializable must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
assert!(
d.message.contains("JSON serializable"),
"Message should mention JSON, got: {}",
d.message
);
}
#[test]
fn test_benchmark_python_name_error_stdlib() {
let error_text = "NameError: name 'json' is not defined";
let source = "def f():\n data = json.loads('{}')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "NameError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "NameError");
assert!(
d.fix.is_some(),
"NameError for stdlib name should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("import json"),
"Fix should inject 'import json', got: {:?}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_python_name_error_unknown() {
let error_text = "NameError: name 'foobar_xyz' is not defined";
let source = "def f():\n x = foobar_xyz()\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"NameError for unknown name must still produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "NameError");
assert_eq!(
d.confidence,
FixConfidence::Low,
"Unknown name should have Low confidence"
);
assert!(d.fix.is_none(), "Unknown name should not produce a fix");
}
#[test]
fn test_benchmark_python_import_error_cannot_import() {
let error_text = "ImportError: cannot import name 'Path' from 'os'";
let source = "from os import Path\n\ndef f():\n p = Path('.')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "ImportError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "ImportError");
}
#[test]
fn test_benchmark_python_module_not_found() {
let error_text = "ModuleNotFoundError: No module named 'nonexistent_pkg'";
let source = "import nonexistent_pkg\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"ModuleNotFoundError must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "ImportError");
assert!(d.fix.is_none(), "Unknown module should not produce a fix");
}
#[test]
fn test_benchmark_python_attribute_error() {
let error_text = "AttributeError: 'str' object has no attribute 'append'";
let source = "def f():\n s = 'hello'\n s.append('!')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "AttributeError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "AttributeError");
assert!(
d.message.contains("has no attribute"),
"Message should mention attribute, got: {}",
d.message
);
}
#[test]
fn test_benchmark_python_value_error() {
let error_text = "ValueError: invalid literal for int() with base 10: 'abc'";
let source = "def f():\n x = int('abc')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "ValueError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "ValueError");
assert!(
d.fix.is_none(),
"ValueError is hint-only, should not produce a fix"
);
}
#[test]
fn test_benchmark_python_index_error() {
let error_text = "IndexError: list index out of range";
let source = "def f():\n items = [1, 2]\n return items[5]\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "IndexError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "IndexError");
assert!(
d.fix.is_none(),
"IndexError is hint-only, should not produce a fix"
);
}
#[test]
fn test_benchmark_python_key_error() {
let error_text = "KeyError: 'name'";
let source = "def lookup(key):\n d = {'a': 1}\n return d[key]\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "KeyError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "KeyError");
}
#[test]
fn test_benchmark_python_zero_division_error() {
let error_text = "ZeroDivisionError: division by zero";
let source = "def f():\n return 1 / 0\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "ZeroDivisionError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "ZeroDivisionError");
assert!(d.fix.is_none(), "ZeroDivisionError is hint-only");
}
#[test]
fn test_benchmark_python_recursion_error() {
let error_text = "RecursionError: maximum recursion depth exceeded";
let source = "def f():\n return f()\n";
let parsed = parse_error(error_text, Some("python"));
assert!(parsed.is_some(), "Parser should handle RecursionError");
let mut error = parsed.unwrap();
error.function_name = Some("f".to_string());
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "RecursionError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "RecursionError");
assert!(d.fix.is_none(), "RecursionError is hint-only");
}
#[test]
fn test_benchmark_python_stop_iteration() {
let source = "def f():\n it = iter([])\n return next(it)\n";
let error = ParsedError {
error_type: "StopIteration".to_string(),
message: String::new(),
file: Some(PathBuf::from("app.py")),
line: Some(3),
column: None,
language: "python".to_string(),
raw_text: "StopIteration".to_string(),
function_name: Some("f".to_string()),
offending_line: None,
};
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "StopIteration must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "StopIteration");
assert!(d.fix.is_none(), "StopIteration is hint-only");
}
#[test]
fn test_benchmark_python_stop_iteration_from_traceback() {
let error_text = "Traceback (most recent call last):\n File \"app.py\", line 3, in f\n return next(it)\nStopIteration";
let parsed = parse_error(error_text, Some("python"));
assert!(
parsed.is_some(),
"Parser should handle StopIteration in traceback"
);
let error = parsed.unwrap();
assert_eq!(error.error_type, "StopIteration");
}
#[test]
fn test_benchmark_python_assertion_error() {
let source = "def validate(x):\n assert x > 0\n";
let error = ParsedError {
error_type: "AssertionError".to_string(),
message: String::new(),
file: Some(PathBuf::from("app.py")),
line: Some(2),
column: None,
language: "python".to_string(),
raw_text: "AssertionError".to_string(),
function_name: Some("validate".to_string()),
offending_line: None,
};
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "AssertionError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "AssertionError");
assert!(d.fix.is_none(), "AssertionError is hint-only");
}
#[test]
fn test_benchmark_python_not_implemented_error() {
let source = "def f():\n raise NotImplementedError\n";
let error = ParsedError {
error_type: "NotImplementedError".to_string(),
message: String::new(),
file: Some(PathBuf::from("app.py")),
line: Some(2),
column: None,
language: "python".to_string(),
raw_text: "NotImplementedError".to_string(),
function_name: Some("f".to_string()),
offending_line: None,
};
let diag = diagnose_parsed(&error, source, None);
assert!(
diag.is_some(),
"NotImplementedError must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "NotImplementedError");
assert!(d.fix.is_none(), "NotImplementedError is hint-only");
}
#[test]
fn test_benchmark_python_file_not_found_error() {
let error_text =
"FileNotFoundError: [Errno 2] No such file or directory: '/tmp/missing/file.txt'";
let source = "def write_data():\n with open('/tmp/missing/file.txt', 'w') as f:\n f.write('data')\n";
let parsed = parse_error(error_text, Some("python"));
assert!(parsed.is_some());
let mut error = parsed.unwrap();
error.function_name = Some("write_data".to_string());
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "FileNotFoundError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "OSError");
}
#[test]
fn test_benchmark_python_permission_error() {
let error_text = "PermissionError: [Errno 13] Permission denied: '/root/secret'";
let source = "def f():\n with open('/root/secret') as f:\n pass\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "PermissionError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "OSError");
}
#[test]
fn test_benchmark_python_unicode_error() {
let error_text = "UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff";
let source = "def read_file():\n with open('data.bin') as f:\n return f.read()\n";
let parsed = parse_error(error_text, Some("python"));
assert!(parsed.is_some());
let mut error = parsed.unwrap();
error.function_name = Some("read_file".to_string());
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "UnicodeError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "UnicodeError");
}
#[test]
fn test_benchmark_python_syntax_error_missing_colon() {
let error_text = "SyntaxError: expected ':'";
let source = "def f()\n pass\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "SyntaxError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "SyntaxError");
assert!(
d.fix.is_some(),
"SyntaxError for missing colon should produce a fix"
);
}
#[test]
fn test_benchmark_python_syntax_error_return_outside_function() {
let error_text = "SyntaxError: 'return' outside function";
let source = "return 42\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"SyntaxError return outside function must diagnose"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "SyntaxError");
}
#[test]
fn test_benchmark_python_indentation_error_mixed_tabs() {
let error_text = "IndentationError: inconsistent use of tabs and spaces in indentation";
let source = "def f():\n\t pass\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "IndentationError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "IndentationError");
assert!(
d.fix.is_some(),
"IndentationError with tabs should produce a fix"
);
}
#[test]
fn test_benchmark_python_indentation_error_unexpected() {
let error_text = "IndentationError: unexpected indent";
let source = "x = 1\n y = 2\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"IndentationError unexpected indent must diagnose"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "IndentationError");
}
#[test]
fn test_benchmark_python_circular_import() {
let error_text = "ImportError: cannot import name 'helper' from partially initialized module 'mymod' (most likely due to a circular import)";
let source = "from mymod import helper\n\ndef use_it():\n return helper()\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(
diag.is_some(),
"CircularImportError must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "ImportError");
assert!(
d.message.contains("Circular import") || d.message.contains("partially initialized"),
"Message should mention circular import, got: {}",
d.message
);
}
#[test]
fn test_benchmark_python_type_error_subscriptable() {
let error_text = "TypeError: 'int' object is not subscriptable";
let source = "def f():\n x = 42\n return x[0]\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "TypeError subscriptable must diagnose");
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
assert!(d.message.contains("subscriptable"));
}
#[test]
fn test_benchmark_python_type_error_missing_args() {
let error_text = "TypeError: f() missing 2 required positional arguments: 'a' and 'b'";
let source = "def f(a, b):\n pass\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "TypeError missing args must diagnose");
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
}
#[test]
fn test_benchmark_python_type_error_unexpected_kwarg() {
let error_text = "TypeError: f() got an unexpected keyword argument 'bar'";
let source = "def f(a):\n pass\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "TypeError unexpected kwarg must diagnose");
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
}
#[test]
fn test_benchmark_python_runtime_error() {
let error_text = "RuntimeError: something went wrong";
let source = "def f():\n raise RuntimeError('something went wrong')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some(), "RuntimeError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "RuntimeError");
assert!(d.fix.is_none(), "RuntimeError is hint-only");
}
#[test]
fn test_benchmark_python_generic_exception() {
let source = "def f():\n raise CustomError('oops')\n";
let error = ParsedError {
error_type: "CustomError".to_string(),
message: "oops".to_string(),
file: Some(PathBuf::from("app.py")),
line: Some(2),
column: None,
language: "python".to_string(),
raw_text: "CustomError: oops".to_string(),
function_name: Some("f".to_string()),
offending_line: None,
};
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "Generic exception must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "CustomError");
assert!(d.fix.is_none(), "Generic exception is hint-only");
}
#[test]
fn test_benchmark_python_all_22_analyzers_dispatch() {
let cases: Vec<(&str, &str, &str)> = vec![
(
"UnboundLocalError",
"cannot access local variable 'x'",
"UnboundLocalError",
),
("TypeError", "'dict' object is not callable", "TypeError"),
(
"TypeError",
"Object of type Foo is not JSON serializable",
"TypeError",
),
("NameError", "name 'os' is not defined", "NameError"),
(
"ImportError",
"cannot import name 'Foo' from 'bar'",
"ImportError",
),
(
"AttributeError",
"'str' object has no attribute 'foo'",
"AttributeError",
),
(
"ValueError",
"invalid literal for int() with base 10",
"ValueError",
),
("IndexError", "list index out of range", "IndexError"),
("KeyError", "'name'", "KeyError"),
("ZeroDivisionError", "division by zero", "ZeroDivisionError"),
(
"RecursionError",
"maximum recursion depth exceeded",
"RecursionError",
),
("StopIteration", "", "StopIteration"),
("AssertionError", "", "AssertionError"),
("NotImplementedError", "", "NotImplementedError"),
("OSError", "No such file or directory: '/tmp/x'", "OSError"),
("UnicodeError", "codec can't decode byte", "UnicodeError"),
("SyntaxError", "expected ':'", "SyntaxError"),
("IndentationError", "unexpected indent", "IndentationError"),
(
"ImportError",
"cannot import name 'x' from partially initialized module 'y'",
"ImportError",
),
(
"TypeError",
"'int' object is not subscriptable",
"TypeError",
),
("RuntimeError", "something went wrong", "RuntimeError"),
("CustomException", "some custom error", "CustomException"),
];
let source = "x = 1\ndef f():\n pass\n";
let mut handled = 0;
for (error_type, message, expected_code) in &cases {
let error = ParsedError {
error_type: error_type.to_string(),
message: message.to_string(),
file: None,
line: Some(1),
column: None,
language: "python".to_string(),
raw_text: format!("{}: {}", error_type, message),
function_name: Some("f".to_string()),
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"Python analyzer for {} should return Some (message: {})",
error_type,
message
);
let d = result.unwrap();
assert_eq!(
d.error_code, *expected_code,
"Expected error_code '{}' for {}, got '{}'",
expected_code, error_type, d.error_code
);
handled += 1;
}
assert_eq!(
handled, 22,
"Expected 22 handled Python analyzers, got {}",
handled
);
}
#[test]
fn test_benchmark_rust_e0425_hashmap() {
let error_text = "error[E0425]: cannot find value `HashMap` in this scope";
let source = "fn main() {\n let m: HashMap<String, i32> = HashMap::new();\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some(), "Rust E0425 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "E0425");
assert_eq!(d.language, "rust");
assert!(d.fix.is_some(), "E0425 for known item should produce a fix");
let fix = d.fix.unwrap();
assert!(
fix.edits[0]
.new_text
.contains("use std::collections::HashMap"),
"Fix should inject HashMap use, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_rust_e0425_pathbuf() {
let error_text = "error[E0425]: cannot find type `PathBuf` in this scope";
let source = "fn main() {\n let p = PathBuf::from(\"/tmp\");\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert_eq!(d.error_code, "E0425");
assert!(d.fix.is_some());
assert!(d.fix.unwrap().edits[0]
.new_text
.contains("use std::path::PathBuf"));
}
#[test]
fn test_benchmark_rust_e0433_hashmap() {
let error_text = "error[E0433]: failed to resolve: use of undeclared type `HashMap`";
let source = "fn main() {\n let m = HashMap::new();\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some(), "Rust E0433 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "E0433");
assert!(d.fix.is_some(), "E0433 for known type should produce a fix");
let fix = d.fix.unwrap();
assert!(
fix.edits[0]
.new_text
.contains("use std::collections::HashMap"),
"Fix should inject HashMap use, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_rust_e0599_write_all() {
let error_text = "error[E0599]: no method named `write_all` found for struct `File`";
let source = "use std::fs::File;\n\nfn main() {\n let f = File::create(\"out.txt\").unwrap();\n f.write_all(b\"hello\");\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some(), "Rust E0599 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "E0599");
assert!(
d.fix.is_some(),
"E0599 for known trait should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("use std::io::Write"),
"Fix should inject Write use, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_rust_e0599_read_line() {
let error_text =
"error[E0599]: no method named `read_line` found for struct `Stdin` in the current scope";
let source = "fn main() {\n let mut buf = String::new();\n std::io::stdin().read_line(&mut buf);\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert_eq!(d.error_code, "E0599");
assert!(d.fix.is_some());
assert!(d.fix.unwrap().edits[0]
.new_text
.contains("use std::io::BufRead"));
}
#[test]
fn test_benchmark_rust_e0308_string_str() {
let error_text = "error[E0308]: mismatched types: expected `String`, found `&str`";
let source = "fn takes_string(s: String) {}\n\nfn main() {\n takes_string(\"hello\");\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some(), "Rust E0308 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "E0308");
}
#[test]
fn test_benchmark_rust_e0277_iterator_copied() {
let error_text = "error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&i32`";
let source =
"fn main() {\n let v = vec![1, 2, 3];\n let w: Vec<i32> = v.iter().collect();\n}\n";
let parsed = parse_error(error_text, Some("rust"));
assert!(parsed.is_some());
let mut error = parsed.unwrap();
error.line = Some(3);
let diag = diagnose_parsed(&error, source, None);
assert!(diag.is_some(), "Rust E0277 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "E0277");
assert!(
d.fix.is_some(),
"E0277 iterator copied should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains(".copied().collect()"),
"Fix should insert .copied(), got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_rust_all_5_analyzers_dispatch() {
let cases = [
("E0425", "cannot find value `HashMap` in this scope"),
(
"E0433",
"failed to resolve: use of undeclared type `HashMap`",
),
(
"E0599",
"no method named `write_all` found for struct `File`",
),
("E0308", "mismatched types: expected `String`, found `&str`"),
("E0277", "trait bound not satisfied"),
];
let source = "fn main() {}\n";
for (code, msg) in &cases {
let error = ParsedError {
error_type: code.to_string(),
message: msg.to_string(),
file: Some(PathBuf::from("main.rs")),
line: Some(1),
column: None,
language: "rust".to_string(),
raw_text: format!("error[{}]: {}", code, msg),
function_name: None,
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"Rust analyzer for {} should return Some (msg: {})",
code,
msg
);
let d = result.unwrap();
assert_eq!(
d.error_code, *code,
"Expected error_code '{}', got '{}'",
code, d.error_code
);
assert_eq!(d.language, "rust");
}
}
#[test]
fn test_benchmark_ts_2304_express() {
let error_text = "error TS2304: Cannot find name 'express'.";
let source = "const app = express();\napp.listen(3000);\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2304 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2304");
assert_eq!(d.language, "typescript");
assert!(
d.fix.is_some(),
"TS2304 for known package should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("import express"),
"Fix should inject express import, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_ts_2304_use_state() {
let error_text = "error TS2304: Cannot find name 'useState'.";
let source = "const [count, setCount] = useState(0);\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2304");
assert!(d.fix.is_some());
assert!(d.fix.unwrap().edits[0].new_text.contains("useState"));
}
#[test]
fn test_benchmark_ts_2305_no_export() {
let error_text = "error TS2305: Module '\"react\"' has no exported member 'createPortal'.";
let source = "import { createPortal } from 'react';\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2305 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2305");
}
#[test]
fn test_benchmark_ts_2307_module_not_found() {
let error_text =
"error TS2307: Cannot find module 'loadsh' or its corresponding type declarations.";
let source = "import loadsh from 'loadsh';\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2307 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2307");
}
#[test]
fn test_benchmark_ts_2322_type_not_assignable() {
let error_text = "error TS2322: Type 'string' is not assignable to type 'number'.";
let source = "let x: number = \"hello\";\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2322 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2322");
}
#[test]
fn test_benchmark_ts_2339_property_not_exists() {
let error_text = "error TS2339: Property 'foo' does not exist on type 'Bar'.";
let source =
"interface Bar { baz: string; }\nconst b: Bar = { baz: 'x' };\nconsole.log(b.foo);\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2339 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2339");
}
#[test]
fn test_benchmark_ts_2345_arg_type() {
let error_text =
"error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.";
let source = "function add(a: number) { return a + 1; }\nadd(\"hello\");\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2345 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2345");
}
#[test]
fn test_benchmark_ts_2554_wrong_arg_count() {
let error_text = "error TS2554: Expected 2 arguments, but got 1.";
let source = "function add(a: number, b: number) { return a + b; }\nadd(1);\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some(), "TS2554 must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "TS2554");
}
#[test]
fn test_benchmark_ts_all_8_analyzers_dispatch() {
let cases = [
("TS2304", "Cannot find name 'express'."),
(
"TS2305",
"Module '\"react\"' has no exported member 'createPortal'.",
),
("TS2307", "Cannot find module 'nonexistent'."),
(
"TS2322",
"Type 'string' is not assignable to type 'number'.",
),
("TS2339", "Property 'foo' does not exist on type 'Bar'."),
(
"TS2345",
"Argument of type 'string' is not assignable to parameter of type 'number'.",
),
("TS2554", "Expected 2 arguments, but got 1."),
("TS7006", "Parameter 'x' implicitly has an 'any' type."),
];
let source = "const x = 1;\n";
for (code, msg) in &cases {
let error = ParsedError {
error_type: code.to_string(),
message: msg.to_string(),
file: Some(PathBuf::from("app.ts")),
line: Some(1),
column: None,
language: "typescript".to_string(),
raw_text: format!("error {}: {}", code, msg),
function_name: None,
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"TypeScript analyzer for {} should return Some (msg: {})",
code,
msg
);
let d = result.unwrap();
assert_eq!(
d.error_code, *code,
"Expected error_code '{}', got '{}'",
code, d.error_code
);
assert_eq!(d.language, "typescript");
}
}
#[test]
fn test_benchmark_go_undefined_fmt() {
let error_text = "./main.go:4:7: undefined: fmt";
let source = "package main\n\nfunc main() {\n\tfmt.Println(\"hello\")\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some(), "Go undefined must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "undefined");
assert_eq!(d.language, "go");
assert!(
d.fix.is_some(),
"Go undefined for known package should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("\"fmt\""),
"Fix should inject fmt import, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_go_undefined_json() {
let error_text = "./main.go:6:14: undefined: json";
let source = "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tdata, _ := json.Marshal(nil)\n\tfmt.Println(data)\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert!(d.fix.is_some());
assert!(d.fix.unwrap().edits[0]
.new_text
.contains("\"encoding/json\""));
}
#[test]
fn test_benchmark_go_type_mismatch() {
let error_text =
"./main.go:5:10: cannot use s (variable of type string) as type []byte in argument";
let source = "package main\n\nfunc main() {\n\ts := \"hello\"\n\tprocessBytes(s)\n}\n\nfunc processBytes(b []byte) {}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some(), "Go type mismatch must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.language, "go");
}
#[test]
fn test_benchmark_go_unused_import() {
let error_text = "./main.go:3:8: \"os\" imported and not used";
let source = "package main\n\nimport \"os\"\n\nfunc main() {\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some(), "Go unused import must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "unused_import");
assert!(
d.fix.is_some(),
"Unused import should produce a fix (delete line)"
);
}
#[test]
fn test_benchmark_go_unused_var() {
let error_text = "./main.go:4:2: x declared but not used";
let source = "package main\n\nfunc main() {\n\tx := 42\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some(), "Go unused var must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "unused_var");
assert!(
d.fix.is_some(),
"Unused var should produce a fix (prefix with _)"
);
}
#[test]
fn test_benchmark_go_unused_var_declared_and_not_used() {
let error_text = "./main.go:4:2: x declared and not used";
let diag = diagnose(
error_text,
"package main\n\nfunc main() {\n\tx := 42\n}\n",
Some("go"),
None,
);
assert!(diag.is_some());
assert_eq!(diag.unwrap().error_code, "unused_var");
}
#[test]
fn test_benchmark_go_missing_return() {
let error_text = "./main.go:3:1: missing return at end of function";
let source = "package main\n\nfunc add(a, b int) int {\n\t_ = a + b\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some(), "Go missing return must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "missing_return");
}
#[test]
fn test_benchmark_go_too_many_args() {
let error_text = "./main.go:5:2: too many arguments in call to add";
let source = "package main\n\nfunc add(a, b int) int { return a + b }\n\nfunc main() {\n\tadd(1, 2, 3)\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
if let Some(d) = diag {
assert_eq!(d.language, "go");
}
}
#[test]
fn test_benchmark_go_all_6_patterns_dispatch() {
let cases: Vec<(&str, &str, &str, &str, usize)> = vec![
(
"undefined", "undefined: fmt",
"./main.go:4:7: undefined: fmt",
"package main\n\nfunc main() {\n\tfmt.Println(\"hello\")\n}\n",
4,
),
(
"type_mismatch",
"cannot use s (variable of type string) as type []byte",
"./main.go:5:10: cannot use s (variable of type string) as type []byte",
"package main\n\nfunc main() {\n\ts := \"hello\"\n\tprocessBytes(s)\n}\n\nfunc processBytes(b []byte) {}\n",
5,
),
(
"unused_import",
"\"os\" imported and not used",
"./main.go:3:8: \"os\" imported and not used",
"package main\n\nimport \"os\"\n\nfunc main() {\n}\n",
3,
),
(
"unused_var",
"x declared but not used",
"./main.go:4:2: x declared but not used",
"package main\n\nfunc main() {\n\tx := 42\n}\n",
4,
),
(
"missing_return",
"missing return at end of function",
"./main.go:3:1: missing return at end of function",
"package main\n\nfunc add(a, b int) int {\n\t_ = a + b\n}\n",
3,
),
];
for (error_type, msg, raw, source, line_no) in &cases {
let error = ParsedError {
error_type: error_type.to_string(),
message: msg.to_string(),
file: Some(PathBuf::from("./main.go")),
line: Some(*line_no),
column: None,
language: "go".to_string(),
raw_text: raw.to_string(),
function_name: None,
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"Go analyzer for '{}' should return Some (msg: {})",
error_type,
msg
);
let d = result.unwrap();
assert_eq!(d.language, "go");
}
}
#[test]
fn test_benchmark_js_reference_error_known_module() {
let error_text = "ReferenceError: fs is not defined\n at Object.<anonymous> (app.js:1:1)";
let source = "const data = fs.readFileSync('file.txt');\n";
let diag = diagnose(error_text, source, Some("javascript"), None);
assert!(diag.is_some(), "JS ReferenceError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "ReferenceError");
assert_eq!(d.language, "javascript");
assert!(
d.fix.is_some(),
"ReferenceError for known module should produce a fix"
);
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("require('fs')"),
"Fix should inject fs require, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_js_reference_error_unknown() {
let error_text =
"ReferenceError: customLib is not defined\n at Object.<anonymous> (app.js:1:1)";
let source = "const x = customLib.doStuff();\n";
let diag = diagnose(error_text, source, Some("javascript"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert_eq!(d.error_code, "ReferenceError");
}
#[test]
fn test_benchmark_js_type_error_undefined_property() {
let error_text = "TypeError: Cannot read properties of undefined (reading 'foo')\n at Object.<anonymous> (app.js:2:1)";
let source = "const obj = undefined;\nconst x = obj.foo;\n";
let diag = diagnose(error_text, source, Some("javascript"), None);
assert!(
diag.is_some(),
"JS TypeError undefined property must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
assert_eq!(d.language, "javascript");
}
#[test]
fn test_benchmark_js_type_error_not_a_function() {
let error_text =
"TypeError: obj.length is not a function\n at Object.<anonymous> (app.js:2:1)";
let source = "const obj = [1, 2, 3];\nconst x = obj.length();\n";
let diag = diagnose(error_text, source, Some("javascript"), None);
assert!(
diag.is_some(),
"JS TypeError not a function must produce a diagnosis"
);
let d = diag.unwrap();
assert_eq!(d.error_code, "TypeError");
}
#[test]
fn test_benchmark_js_syntax_error() {
let error_text = "SyntaxError: Unexpected token '}'\n at Object.<anonymous> (app.js:3:1)";
let source = "function f() {\n return 1\n}}\n";
let diag = diagnose(error_text, source, Some("javascript"), None);
assert!(diag.is_some(), "JS SyntaxError must produce a diagnosis");
let d = diag.unwrap();
assert_eq!(d.error_code, "SyntaxError");
assert_eq!(d.language, "javascript");
}
#[test]
fn test_benchmark_js_all_4_analyzers_dispatch() {
let cases = [
("ReferenceError", "fs is not defined"),
(
"TypeError",
"Cannot read properties of undefined (reading 'foo')",
),
("TypeError", "obj.length is not a function"),
("SyntaxError", "Unexpected token '}'"),
];
let source = "const x = 1;\n";
for (error_type, msg) in &cases {
let error = ParsedError {
error_type: error_type.to_string(),
message: msg.to_string(),
file: Some(PathBuf::from("app.js")),
line: Some(1),
column: None,
language: "javascript".to_string(),
raw_text: format!(
"{}: {}\n at Object.<anonymous> (app.js:1:1)",
error_type, msg
),
function_name: None,
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"JS analyzer for {} should return Some (msg: {})",
error_type,
msg
);
let d = result.unwrap();
assert_eq!(d.language, "javascript");
}
}
#[test]
fn test_benchmark_e2e_python_auto_detect() {
let error_text = "NameError: name 'os' is not defined";
let source = "def f():\n os.path.exists('.')\n";
let diag = diagnose(error_text, source, None, None);
assert!(diag.is_some(), "E2E Python auto-detect must work");
let d = diag.unwrap();
assert_eq!(d.language, "python");
assert_eq!(d.error_code, "NameError");
assert!(d.fix.is_some());
}
#[test]
fn test_benchmark_e2e_rust_auto_detect() {
let error_text = "error[E0425]: cannot find value `HashMap` in this scope";
let source = "fn main() {\n let m = HashMap::new();\n}\n";
let diag = diagnose(error_text, source, None, None);
assert!(diag.is_some(), "E2E Rust auto-detect must work");
let d = diag.unwrap();
assert_eq!(d.language, "rust");
assert_eq!(d.error_code, "E0425");
}
#[test]
fn test_benchmark_e2e_typescript_auto_detect() {
let error_text = "error TS2304: Cannot find name 'express'.";
let source = "const app = express();\n";
let diag = diagnose(error_text, source, None, None);
assert!(diag.is_some(), "E2E TypeScript auto-detect must work");
let d = diag.unwrap();
assert_eq!(d.language, "typescript");
assert_eq!(d.error_code, "TS2304");
}
#[test]
fn test_benchmark_e2e_go_auto_detect() {
let error_text = "./main.go:4:7: undefined: fmt";
let source = "package main\n\nfunc main() {\n\tfmt.Println(\"hello\")\n}\n";
let diag = diagnose(error_text, source, None, None);
assert!(diag.is_some(), "E2E Go auto-detect must work");
let d = diag.unwrap();
assert_eq!(d.language, "go");
assert_eq!(d.error_code, "undefined");
}
#[test]
fn test_benchmark_e2e_javascript_auto_detect() {
let error_text = "ReferenceError: path is not defined\n at Object.<anonymous> (app.js:1:1)";
let source = "const dir = path.join(__dirname, 'data');\n";
let diag = diagnose(error_text, source, None, None);
assert!(diag.is_some(), "E2E JavaScript auto-detect must work");
let d = diag.unwrap();
assert_eq!(d.language, "javascript");
assert_eq!(d.error_code, "ReferenceError");
}
#[test]
fn test_benchmark_fix_quality_python_name_error_import_position() {
let error_text = "NameError: name 'json' is not defined";
let source = "import os\nimport sys\n\ndef f():\n data = json.loads('{}')\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some());
let fix = diag.unwrap().fix.unwrap();
assert!(
fix.edits[0].line >= 2,
"Import should be placed after existing imports, line={}, expected >= 2",
fix.edits[0].line
);
}
#[test]
fn test_benchmark_fix_quality_python_unbound_local_indent() {
let error_text = "UnboundLocalError: cannot access local variable 'total'";
let source = "total = 0\ndef add(x):\n total += x\n";
let diag = diagnose(error_text, source, Some("python"), None);
assert!(diag.is_some());
let fix = diag.unwrap().fix.unwrap();
assert!(
fix.edits[0].new_text.starts_with(" "),
"global declaration should be indented with 4 spaces, got: {:?}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_fix_quality_go_import_injection() {
let error_text = "./main.go:4:7: undefined: strings";
let source =
"package main\n\nfunc main() {\n\ts := strings.ToUpper(\"hello\")\n\tprintln(s)\n}\n";
let diag = diagnose(error_text, source, Some("go"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert!(d.fix.is_some());
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("\"strings\""),
"Fix should inject strings import, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_fix_quality_rust_use_injection() {
let error_text = "error[E0425]: cannot find value `File` in this scope";
let source = "fn main() {\n let f = File::open(\"test.txt\").unwrap();\n}\n";
let diag = diagnose(error_text, source, Some("rust"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert!(d.fix.is_some());
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("use std::fs::File"),
"Fix should inject File use, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_fix_quality_ts_import_injection() {
let error_text = "error TS2304: Cannot find name 'useEffect'.";
let source = "useEffect(() => {}, []);\n";
let diag = diagnose(error_text, source, Some("typescript"), None);
assert!(diag.is_some());
let d = diag.unwrap();
assert!(d.fix.is_some());
let fix = d.fix.unwrap();
assert!(
fix.edits[0].new_text.contains("useEffect"),
"Fix should inject useEffect import, got: {}",
fix.edits[0].new_text
);
}
#[test]
fn test_benchmark_hint_only_python_all() {
let hint_only_cases: Vec<(&str, &str)> = vec![
("IndexError", "list index out of range"),
("ValueError", "invalid literal for int()"),
("ZeroDivisionError", "division by zero"),
("RecursionError", "maximum recursion depth exceeded"),
("StopIteration", ""),
("AssertionError", ""),
];
let source = "def f():\n pass\n";
for (error_type, msg) in &hint_only_cases {
let error = ParsedError {
error_type: error_type.to_string(),
message: msg.to_string(),
file: None,
line: Some(1),
column: None,
language: "python".to_string(),
raw_text: format!("{}: {}", error_type, msg),
function_name: Some("f".to_string()),
offending_line: None,
};
let result = diagnose_parsed(&error, source, None);
assert!(
result.is_some(),
"Hint-only analyzer for {} should return Some",
error_type
);
let d = result.unwrap();
assert!(
d.fix.is_none(),
"{} is hint-only and must NOT produce a fix, but got: {:?}",
error_type,
d.fix
);
}
}
#[test]
fn test_benchmark_parser_roundtrip_python() {
let raw = "Traceback (most recent call last):\n File \"app.py\", line 10, in main\n x += 1\nUnboundLocalError: cannot access local variable 'x'";
let parsed = parse_error(raw, None);
assert!(parsed.is_some());
let error = parsed.unwrap();
assert_eq!(error.language, "python");
assert_eq!(error.error_type, "UnboundLocalError");
assert_eq!(error.file, Some(PathBuf::from("app.py")));
assert_eq!(error.line, Some(10));
assert_eq!(error.function_name, Some("main".to_string()));
}
#[test]
fn test_benchmark_parser_roundtrip_go() {
let raw = "./main.go:5:2: undefined: x";
let parsed = parse_error(raw, None);
assert!(parsed.is_some());
let error = parsed.unwrap();
assert_eq!(error.language, "go");
assert!(error.file.is_some());
assert_eq!(error.line, Some(5));
}
#[test]
fn test_benchmark_parser_roundtrip_typescript() {
let raw = "error TS2304: Cannot find name 'x'.";
let parsed = parse_error(raw, None);
assert!(parsed.is_some());
let error = parsed.unwrap();
assert_eq!(error.language, "typescript");
assert_eq!(error.error_type, "TS2304");
}
#[test]
fn test_benchmark_parser_roundtrip_rust() {
let raw = "error[E0425]: cannot find value `x` in this scope";
let parsed = parse_error(raw, None);
assert!(parsed.is_some());
let error = parsed.unwrap();
assert_eq!(error.language, "rust");
assert_eq!(error.error_type, "E0425");
}
#[test]
fn test_benchmark_parser_roundtrip_javascript() {
let raw = "ReferenceError: x is not defined\n at Object.<anonymous> (file.js:1:1)";
let parsed = parse_error(raw, None);
assert!(parsed.is_some());
let error = parsed.unwrap();
assert_eq!(error.language, "javascript");
assert_eq!(error.error_type, "ReferenceError");
}