#[path = "support/runtime.rs"]
mod runtime_support;
mod support;
use rsaeb::error::{
ParseErrorKind, ParseErrorLocation, ParseRepresentationError, PayloadKind, RunError,
RunFinishError, RunStepError,
};
use rsaeb::input::{RunSeed, RuntimeInput, RuntimeInputSource};
use rsaeb::limits::{DEFAULT_MAX_INPUT_LEN, RuntimeInputLimits};
use runtime_support::TestRunPolicy;
use support::{TestFailure, TestResult, ensure_eq, ensure_matches, parse_program};
fn expect_run_error<T>(result: Result<T, RunError>) -> Result<RunError, TestFailure> {
match result {
Ok(_) => Err(TestFailure::message("expected runtime error")),
Err(error) => Ok(error),
}
}
fn runtime_input(bytes: &[u8], limits: TestRunPolicy) -> Result<RunSeed, TestFailure> {
runtime_support::run_seed(bytes, limits)
}
#[test]
fn errors_parse_location_and_kind_are_structured() -> TestResult {
let Err(error) = parse_program("a=b=c") else {
return Err(TestFailure::message("expected parse error"));
};
ensure_eq!(error.line().get(), 1)?;
match error.location() {
ParseErrorLocation::Position(position) => {
ensure_eq!(position.line().get(), 1)?;
ensure_eq!(position.column().get(), 4)?;
}
ParseErrorLocation::Line(_) => {
return Err(TestFailure::message("expected positioned parse error"));
}
}
ensure_matches(
matches!(error.kind(), ParseErrorKind::MultipleEquals),
"expected multiple-equals parse error",
)
}
#[test]
fn errors_payload_and_modifier_kinds_keep_domain_information() -> TestResult {
let Err(error) = parse_program("a = b (") else {
return Err(TestFailure::message("expected reserved syntax error"));
};
ensure_matches(
matches!(
error.kind(),
ParseErrorKind::ReservedSyntaxInPayload {
payload_kind: PayloadKind::RightSideData,
..
}
),
"expected right payload syntax error",
)?;
let Err(error) = parse_program("(start)(once)a=b") else {
return Err(TestFailure::message("expected modifier order error"));
};
ensure_matches(
matches!(
error.kind(),
ParseErrorKind::UnsupportedLeftModifierOrder { .. }
),
"expected left modifier order error",
)
}
#[test]
fn errors_display_output_names_domain_contexts() -> TestResult {
let Err(parse_error) = parse_program("a=b=c") else {
return Err(TestFailure::message("expected parse error"));
};
ensure_eq!(
parse_error.to_string(),
"parse error at line 1, column 4: multiple '=' characters are not allowed",
)?;
let Err(input_error) = RuntimeInput::validate(
RuntimeInputSource::from_bytes(&[0xff]),
RuntimeInputLimits::new(DEFAULT_MAX_INPUT_LEN),
) else {
return Err(TestFailure::message("expected input error"));
};
ensure_eq!(
input_error.to_string(),
"input error: non-ASCII byte 0xff at column 1",
)?;
let return_limits = TestRunPolicy::new(
DEFAULT_MAX_INPUT_LEN,
rsaeb::limits::StepLimit::new(1),
rsaeb::limits::DEFAULT_MAX_STATE_LEN,
rsaeb::limits::ReturnByteLimit::new(1),
);
let return_error = parse_program("a=(return)ok")?.run(runtime_input(b"a", return_limits)?);
ensure_matches(
matches!(
expect_run_error(return_error)?,
RunError::Finish(RunFinishError::Step(RunStepError::ReturnOutputLimit(_)))
),
"expected return limit error",
)
}
#[test]
fn errors_representation_subdomain_is_public() -> TestResult {
ensure_eq!(
ParseRepresentationError::RulePosition.to_string(),
"rule position could not be represented",
)
}