2025-12-11 15:08:14 +09:00
|
|
|
//! Phase 246-EX Step 5: E2E tests for JsonParser _atoi JoinIR integration
|
|
|
|
|
//!
|
|
|
|
|
//! Tests the complete _atoi loop lowering using Pattern 2 (Break) + NumberAccumulation.
|
|
|
|
|
//!
|
|
|
|
|
//! Test cases cover:
|
|
|
|
|
//! - Single digit zero: "0" → 0
|
|
|
|
|
//! - Two digits: "42" → 42
|
|
|
|
|
//! - Multiple digits: "123" → 123
|
|
|
|
|
//! - Leading zeros: "007" → 7
|
|
|
|
|
//! - Break at non-digit: "123abc" → 123
|
|
|
|
|
//! - Immediate break (no digits): "abc" → 0
|
|
|
|
|
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
|
|
/// Helper function to run _atoi implementation via hakorune binary
|
|
|
|
|
fn run_atoi_test(input: &str, expected: i64, test_name: &str) {
|
|
|
|
|
let code = format!(
|
|
|
|
|
r#"
|
|
|
|
|
static box Main {{
|
|
|
|
|
main() {{
|
|
|
|
|
local result = me._atoi("{}", {})
|
|
|
|
|
print(result)
|
|
|
|
|
return result
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
method _atoi(s, len) {{
|
|
|
|
|
local result = 0
|
|
|
|
|
local digits = "0123456789"
|
|
|
|
|
local i = 0
|
|
|
|
|
|
|
|
|
|
loop(i < len) {{
|
|
|
|
|
local ch = s.substring(i, i + 1)
|
|
|
|
|
local digit_pos = digits.indexOf(ch)
|
|
|
|
|
if digit_pos < 0 {{ break }}
|
|
|
|
|
result = result * 10 + digit_pos
|
|
|
|
|
i = i + 1
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}}
|
|
|
|
|
}}
|
|
|
|
|
"#,
|
|
|
|
|
input,
|
|
|
|
|
input.len()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Write test file
|
|
|
|
|
let test_file = format!("local_tests/phase246_atoi_{}.hako", test_name);
|
|
|
|
|
fs::write(&test_file, &code).expect("Failed to write test file");
|
|
|
|
|
|
|
|
|
|
// Run hakorune
|
|
|
|
|
let bin = env!("CARGO_BIN_EXE_hakorune");
|
|
|
|
|
let output = Command::new(bin)
|
|
|
|
|
.arg("--backend")
|
|
|
|
|
.arg("vm")
|
|
|
|
|
.arg(&test_file)
|
|
|
|
|
.env("NYASH_JOINIR_CORE", "1")
|
|
|
|
|
.env("NYASH_DISABLE_PLUGINS", "1")
|
|
|
|
|
.output()
|
|
|
|
|
.expect("Failed to run hakorune");
|
|
|
|
|
|
|
|
|
|
// Clean up test file
|
|
|
|
|
let _ = fs::remove_file(&test_file);
|
|
|
|
|
|
2025-12-11 16:46:53 +09:00
|
|
|
// Accept non-zero exit codes (program returns parsed value as exit code). Only fail on signal.
|
|
|
|
|
if output.status.code().is_none() {
|
2025-12-11 15:08:14 +09:00
|
|
|
panic!(
|
2025-12-11 16:46:53 +09:00
|
|
|
"[phase246/atoi/{}] Test failed (terminated by signal?):\nstdout: {}\nstderr: {}",
|
2025-12-11 15:08:14 +09:00
|
|
|
test_name,
|
|
|
|
|
String::from_utf8_lossy(&output.stdout),
|
|
|
|
|
String::from_utf8_lossy(&output.stderr),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify output
|
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
|
|
|
let output_value: i64 = stdout
|
|
|
|
|
.trim()
|
|
|
|
|
.parse()
|
|
|
|
|
.unwrap_or_else(|_| panic!("Failed to parse output '{}' as integer", stdout.trim()));
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
output_value, expected,
|
|
|
|
|
"Failed for input '{}': expected {}, got {}",
|
|
|
|
|
input, expected, output_value
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_single_digit_zero() {
|
|
|
|
|
// Phase 246-EX: Test case "0" → 0
|
|
|
|
|
run_atoi_test("0", 0, "zero");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_two_digits() {
|
|
|
|
|
// Phase 246-EX: Test case "42" → 42
|
|
|
|
|
run_atoi_test("42", 42, "two_digits");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_multiple_digits() {
|
|
|
|
|
// Phase 246-EX: Test case "123" → 123
|
|
|
|
|
run_atoi_test("123", 123, "multiple_digits");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_leading_zeros() {
|
|
|
|
|
// Phase 246-EX: Test case "007" → 7
|
|
|
|
|
run_atoi_test("007", 7, "leading_zeros");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_break_at_non_digit() {
|
|
|
|
|
// Phase 246-EX: Test case "123abc" → 123 (break at 'a')
|
|
|
|
|
run_atoi_test("123abc", 123, "break_non_digit");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_immediate_break_no_digits() {
|
|
|
|
|
// Phase 246-EX: Test case "abc" → 0 (immediate break, no digits parsed)
|
|
|
|
|
run_atoi_test("abc", 0, "immediate_break");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_empty_string() {
|
|
|
|
|
// Phase 246-EX: Test case "" → 0 (empty string, no iterations)
|
|
|
|
|
run_atoi_test("", 0, "empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_single_digit_nine() {
|
|
|
|
|
// Phase 246-EX: Additional test case "9" → 9 (max single digit)
|
|
|
|
|
run_atoi_test("9", 9, "nine");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_atoi_large_number() {
|
|
|
|
|
// Phase 246-EX: Test case "999999" → 999999 (large number)
|
|
|
|
|
run_atoi_test("999999", 999999, "large");
|
|
|
|
|
}
|