use super::*; fn all_syscalls() -> Vec { 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, } ); }