170 lines
5.0 KiB
Rust
170 lines
5.0 KiB
Rust
use super::*;
|
|
|
|
fn all_syscalls() -> Vec<Syscall> {
|
|
domains::all_entries().map(|entry| entry.syscall).collect()
|
|
}
|
|
|
|
#[test]
|
|
fn every_syscall_has_metadata() {
|
|
for sc in all_syscalls() {
|
|
let m = meta_for(sc);
|
|
assert_eq!(m.id, sc as u32, "id mismatch for {:?}", sc);
|
|
assert!(!m.module.is_empty(), "module must be non-empty for id=0x{:08X}", m.id);
|
|
assert!(!m.name.is_empty(), "name must be non-empty for id=0x{:08X}", m.id);
|
|
assert!(m.version > 0, "version must be > 0 for id=0x{:08X}", m.id);
|
|
}
|
|
|
|
use std::collections::HashSet;
|
|
let mut ids = HashSet::new();
|
|
let mut identities = HashSet::new();
|
|
let mut count = 0usize;
|
|
for entry in domains::all_entries() {
|
|
count += 1;
|
|
assert!(ids.insert(entry.meta.id), "duplicate syscall id 0x{:08X}", entry.meta.id);
|
|
let parsed = Syscall::from_u32(entry.meta.id).expect("id not recognized by enum mapping");
|
|
assert_eq!(parsed as u32, entry.meta.id);
|
|
|
|
let key = (entry.meta.module, entry.meta.name, entry.meta.version);
|
|
assert!(
|
|
identities.insert(key),
|
|
"duplicate canonical identity: ({}.{}, v{})",
|
|
entry.meta.module,
|
|
entry.meta.name,
|
|
entry.meta.version
|
|
);
|
|
}
|
|
|
|
assert_eq!(count, all_syscalls().len());
|
|
}
|
|
|
|
#[test]
|
|
fn resolver_returns_expected_id_for_known_identity() {
|
|
let id = resolve_syscall("gfx", "clear", 1).expect("known identity must resolve");
|
|
assert_eq!(id.id, 0x1001);
|
|
assert_eq!(id.meta.module, "gfx");
|
|
assert_eq!(id.meta.name, "clear");
|
|
assert_eq!(id.meta.version, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn resolver_rejects_unknown_identity() {
|
|
let res = resolve_syscall("gfx", "nonexistent", 1);
|
|
assert!(res.is_none());
|
|
|
|
let requested = [SyscallIdentity { module: "gfx", name: "nonexistent", version: 1 }];
|
|
let err = resolve_program_syscalls(&requested, 0).unwrap_err();
|
|
match err {
|
|
LoadError::UnknownSyscall { module, name, version } => {
|
|
assert_eq!(module, "gfx");
|
|
assert_eq!(name, "nonexistent");
|
|
assert_eq!(version, 1);
|
|
}
|
|
_ => panic!("expected UnknownSyscall error"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn resolver_enforces_capabilities() {
|
|
let requested = [SyscallIdentity { module: "gfx", name: "clear", version: 1 }];
|
|
let err = resolve_program_syscalls(&requested, 0).unwrap_err();
|
|
match err {
|
|
LoadError::MissingCapability { required, provided, module, name, version } => {
|
|
assert_eq!(module, "gfx");
|
|
assert_eq!(name, "clear");
|
|
assert_eq!(version, 1);
|
|
assert_ne!(required, 0);
|
|
assert_eq!(provided, 0);
|
|
}
|
|
_ => panic!("expected MissingCapability error"),
|
|
}
|
|
|
|
let ok = resolve_program_syscalls(&requested, caps::GFX).expect("must resolve with caps");
|
|
assert_eq!(ok.len(), 1);
|
|
assert_eq!(ok[0].id, 0x1001);
|
|
}
|
|
|
|
#[test]
|
|
fn declared_resolver_returns_expected_id_for_known_identity() {
|
|
let declared = [prometeu_bytecode::SyscallDecl {
|
|
module: "gfx".into(),
|
|
name: "clear".into(),
|
|
version: 1,
|
|
arg_slots: 1,
|
|
ret_slots: 0,
|
|
}];
|
|
|
|
let ok =
|
|
resolve_declared_program_syscalls(&declared, caps::GFX).expect("must resolve with ABI");
|
|
assert_eq!(ok.len(), 1);
|
|
assert_eq!(ok[0].id, 0x1001);
|
|
}
|
|
|
|
#[test]
|
|
fn declared_resolver_rejects_unknown_identity() {
|
|
let declared = [prometeu_bytecode::SyscallDecl {
|
|
module: "gfx".into(),
|
|
name: "nonexistent".into(),
|
|
version: 1,
|
|
arg_slots: 1,
|
|
ret_slots: 0,
|
|
}];
|
|
|
|
let err = resolve_declared_program_syscalls(&declared, caps::GFX).unwrap_err();
|
|
assert_eq!(
|
|
err,
|
|
DeclaredLoadError::UnknownSyscall {
|
|
module: "gfx".into(),
|
|
name: "nonexistent".into(),
|
|
version: 1,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declared_resolver_rejects_missing_capability() {
|
|
let declared = [prometeu_bytecode::SyscallDecl {
|
|
module: "gfx".into(),
|
|
name: "clear".into(),
|
|
version: 1,
|
|
arg_slots: 1,
|
|
ret_slots: 0,
|
|
}];
|
|
|
|
let err = resolve_declared_program_syscalls(&declared, caps::NONE).unwrap_err();
|
|
assert_eq!(
|
|
err,
|
|
DeclaredLoadError::MissingCapability {
|
|
required: caps::GFX,
|
|
provided: caps::NONE,
|
|
module: "gfx".into(),
|
|
name: "clear".into(),
|
|
version: 1,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn declared_resolver_rejects_abi_mismatch() {
|
|
let declared = [prometeu_bytecode::SyscallDecl {
|
|
module: "gfx".into(),
|
|
name: "draw_line".into(),
|
|
version: 1,
|
|
arg_slots: 4,
|
|
ret_slots: 0,
|
|
}];
|
|
|
|
let err = resolve_declared_program_syscalls(&declared, caps::GFX).unwrap_err();
|
|
assert_eq!(
|
|
err,
|
|
DeclaredLoadError::AbiMismatch {
|
|
module: "gfx".into(),
|
|
name: "draw_line".into(),
|
|
version: 1,
|
|
declared_arg_slots: 4,
|
|
declared_ret_slots: 0,
|
|
expected_arg_slots: 5,
|
|
expected_ret_slots: 0,
|
|
}
|
|
);
|
|
}
|