186 lines
6.1 KiB
Rust
186 lines
6.1 KiB
Rust
//! Forth 2012 compliance tests using Gerry Jackson's test suite.
|
|
//!
|
|
//! Each test loads the corresponding test file from the
|
|
//! forth2012-test-suite submodule and runs it through WAFER,
|
|
//! asserting 0 test failures.
|
|
|
|
use wafer_core::outer::ForthVM;
|
|
|
|
/// Path to the test suite source directory.
|
|
const SUITE_DIR: &str = concat!(
|
|
env!("CARGO_MANIFEST_DIR"),
|
|
"/../../tests/forth2012-test-suite/src"
|
|
);
|
|
|
|
/// Load a file and evaluate it line by line, ignoring errors on individual lines.
|
|
fn load_file(vm: &mut ForthVM, path: &str) {
|
|
let source = std::fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {path}"));
|
|
for line in source.lines() {
|
|
let _ = vm.evaluate(line);
|
|
}
|
|
vm.take_output(); // discard output
|
|
}
|
|
|
|
/// Boot a WAFER VM with full prerequisites loaded.
|
|
fn boot_with_prerequisites() -> ForthVM {
|
|
let mut vm = ForthVM::new().expect("Failed to create ForthVM");
|
|
|
|
// Load test framework
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/tester.fr"));
|
|
// Load core tests (prerequisite)
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/core.fr"));
|
|
// Switch to decimal and load utilities
|
|
let _ = vm.evaluate("DECIMAL");
|
|
vm.take_output();
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/utilities.fth"));
|
|
// Load core extensions
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/coreexttest.fth"));
|
|
|
|
vm
|
|
}
|
|
|
|
/// Run a test suite file and return the #ERRORS count.
|
|
fn run_suite(vm: &mut ForthVM, test_file: &str) -> u32 {
|
|
// Reset error counter
|
|
let _ = vm.evaluate("DECIMAL 0 #ERRORS !");
|
|
vm.take_output();
|
|
|
|
// Load the test file
|
|
load_file(vm, &format!("{SUITE_DIR}/{test_file}"));
|
|
|
|
// Read error count -- try multiple approaches to be robust
|
|
let _ = vm.evaluate("DECIMAL");
|
|
vm.take_output();
|
|
|
|
// Clear data stack first
|
|
let _ = vm.evaluate("DEPTH 0 > IF DEPTH 0 DO DROP LOOP THEN");
|
|
vm.take_output();
|
|
|
|
// Push error count
|
|
if vm.evaluate("#ERRORS @").is_err() {
|
|
// #ERRORS not accessible -- test framework was corrupted
|
|
return u32::MAX;
|
|
}
|
|
let stack = vm.data_stack();
|
|
let errors = stack.first().copied().unwrap_or(-1);
|
|
vm.take_output();
|
|
|
|
// Clean up
|
|
let _ = vm.evaluate("DEPTH 0 > IF DROP THEN");
|
|
vm.take_output();
|
|
|
|
if errors < 0 { u32::MAX } else { errors as u32 }
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_core() {
|
|
let mut vm = ForthVM::new().expect("Failed to create ForthVM");
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/tester.fr"));
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/core.fr"));
|
|
|
|
let _ = vm.evaluate("DECIMAL #ERRORS @");
|
|
let errors = vm.data_stack().first().copied().unwrap_or(-1);
|
|
assert_eq!(errors, 0, "Core word set: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_core_plus() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "coreplustest.fth");
|
|
assert_eq!(errors, 0, "Core Plus: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_core_ext() {
|
|
// Core Extensions are loaded as part of prerequisites.
|
|
// Run from scratch to get a clean error count.
|
|
let mut vm = ForthVM::new().expect("Failed to create ForthVM");
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/tester.fr"));
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/core.fr"));
|
|
let _ = vm.evaluate("DECIMAL");
|
|
vm.take_output();
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/utilities.fth"));
|
|
let _ = vm.evaluate("DECIMAL 0 #ERRORS !");
|
|
vm.take_output();
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/coreexttest.fth"));
|
|
let _ = vm.evaluate("DECIMAL #ERRORS @");
|
|
let errors = vm.data_stack().first().copied().unwrap_or(-1) as u32;
|
|
assert_eq!(errors, 0, "Core Extensions: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_double() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "doubletest.fth");
|
|
assert_eq!(errors, 0, "Double-Number: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_exception() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "exceptiontest.fth");
|
|
assert_eq!(errors, 0, "Exception: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_facility() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "facilitytest.fth");
|
|
assert_eq!(errors, 0, "Facility: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "File-Access requires WASI filesystem operations"]
|
|
fn compliance_file() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "filetest.fth");
|
|
assert_eq!(errors, 0, "File-Access: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_locals() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "localstest.fth");
|
|
assert_eq!(errors, 0, "Locals: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_memory() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "memorytest.fth");
|
|
assert_eq!(errors, 0, "Memory-Allocation: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_search_order() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "searchordertest.fth");
|
|
assert_eq!(errors, 0, "Search-Order: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
fn compliance_string() {
|
|
// Run from scratch -- the stringtest includes CoreExt tests that
|
|
// cascade failures when run on top of an already-loaded CoreExt suite.
|
|
let mut vm = ForthVM::new().expect("Failed to create ForthVM");
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/tester.fr"));
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/core.fr"));
|
|
let _ = vm.evaluate("DECIMAL");
|
|
vm.take_output();
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/utilities.fth"));
|
|
let _ = vm.evaluate("DECIMAL 0 #ERRORS !");
|
|
vm.take_output();
|
|
load_file(&mut vm, &format!("{SUITE_DIR}/stringtest.fth"));
|
|
let _ = vm.evaluate("DECIMAL #ERRORS @");
|
|
let errors = vm.data_stack().first().copied().unwrap_or(-1) as u32;
|
|
assert_eq!(errors, 0, "String: {errors} test failures");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "Programming-Tools: 1 error remaining (CS-PICK/CS-ROLL)"]
|
|
fn compliance_tools() {
|
|
let mut vm = boot_with_prerequisites();
|
|
let errors = run_suite(&mut vm, "toolstest.fth");
|
|
assert_eq!(errors, 0, "Programming-Tools: {errors} test failures");
|
|
}
|