Conformance Regression Suite Fault Status
This commit is contained in:
parent
d5f38d778d
commit
9ac48379ed
@ -300,6 +300,49 @@ fn declared_resolver_rejects_legacy_status_first_signatures() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn declared_resolver_accepts_mixed_status_first_surface_as_a_single_module() {
|
||||
let declared = vec![
|
||||
prometeu_bytecode::SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
name: "set_sprite".into(),
|
||||
version: 1,
|
||||
arg_slots: 10,
|
||||
ret_slots: 1,
|
||||
},
|
||||
prometeu_bytecode::SyscallDecl {
|
||||
module: "audio".into(),
|
||||
name: "play".into(),
|
||||
version: 1,
|
||||
arg_slots: 7,
|
||||
ret_slots: 1,
|
||||
},
|
||||
prometeu_bytecode::SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
},
|
||||
prometeu_bytecode::SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "commit".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
},
|
||||
];
|
||||
|
||||
let resolved = resolve_declared_program_syscalls(&declared, caps::GFX | caps::AUDIO | caps::ASSET)
|
||||
.expect("mixed status-first surface must resolve together");
|
||||
|
||||
assert_eq!(resolved.len(), declared.len());
|
||||
assert_eq!(resolved[0].meta.ret_slots, 1);
|
||||
assert_eq!(resolved[1].meta.ret_slots, 1);
|
||||
assert_eq!(resolved[2].meta.ret_slots, 2);
|
||||
assert_eq!(resolved[3].meta.ret_slots, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memcard_syscall_signatures_are_pinned() {
|
||||
let slot_count = meta_for(Syscall::MemSlotCount);
|
||||
|
||||
@ -770,6 +770,179 @@ fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::InvalidState as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_cancel_unknown_handle_returns_status_not_crash() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_I32 999\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "cancel".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "unknown handle cancel must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_cancel_invalid_transition_returns_status_not_crash() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_I32 1\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "cancel".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
let asset_data = test_tile_asset_data();
|
||||
hardware.assets.initialize_for_cartridge(
|
||||
vec![test_tile_asset_entry("tile_asset", asset_data.len())],
|
||||
vec![],
|
||||
asset_data,
|
||||
);
|
||||
let handle = hardware
|
||||
.assets
|
||||
.load("tile_asset", prometeu_hal::asset::SlotRef::gfx(0))
|
||||
.expect("asset handle must be allocated");
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
|
||||
loop {
|
||||
match hardware.assets.status(handle) {
|
||||
LoadStatus::READY => break,
|
||||
LoadStatus::PENDING | LoadStatus::LOADING => {
|
||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||
}
|
||||
other => panic!("unexpected asset status before commit: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(hardware.assets.commit(handle), AssetOpStatus::Ok);
|
||||
hardware.assets.apply_commits();
|
||||
assert_eq!(hardware.assets.status(handle), LoadStatus::COMMITTED);
|
||||
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "cancel after commit must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::InvalidState as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_load_invalid_kind_surfaces_trap_not_panic() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_CONST 0\nPUSH_I32 2\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module_with_consts(
|
||||
code,
|
||||
vec![ConstantPoolEntry::String("tile_asset".into())],
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime
|
||||
.tick(&mut vm, &signals, &mut hardware)
|
||||
.expect("invalid asset kind must surface as trap");
|
||||
match report {
|
||||
CrashReport::VmTrap { trap } => {
|
||||
assert_eq!(trap.code, TRAP_TYPE);
|
||||
assert!(trap.message.contains("Invalid asset type"));
|
||||
}
|
||||
other => panic!("expected VmTrap crash report, got {:?}", other),
|
||||
}
|
||||
assert!(matches!(runtime.last_crash_report, Some(CrashReport::VmTrap { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_status_first_surface_smoke_across_gfx_audio_and_asset() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble(
|
||||
"PUSH_CONST 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_BOOL 1\nPUSH_BOOL 0\nPUSH_BOOL 0\nPUSH_I32 0\nHOSTCALL 0\n\
|
||||
PUSH_CONST 1\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 255\nPUSH_I32 128\nPUSH_I32 1\nPUSH_I32 0\nHOSTCALL 1\n\
|
||||
PUSH_CONST 2\nPUSH_I32 0\nPUSH_I32 0\nHOSTCALL 2\n\
|
||||
HALT"
|
||||
)
|
||||
.expect("assemble");
|
||||
let program = serialized_single_function_module_with_consts(
|
||||
code,
|
||||
vec![
|
||||
ConstantPoolEntry::String("missing_tile_bank".into()),
|
||||
ConstantPoolEntry::String("missing_sound_bank".into()),
|
||||
ConstantPoolEntry::String("missing_asset".into()),
|
||||
],
|
||||
vec![
|
||||
SyscallDecl {
|
||||
module: "gfx".into(),
|
||||
name: "set_sprite".into(),
|
||||
version: 1,
|
||||
arg_slots: 10,
|
||||
ret_slots: 1,
|
||||
},
|
||||
SyscallDecl {
|
||||
module: "audio".into(),
|
||||
name: "play".into(),
|
||||
version: 1,
|
||||
arg_slots: 7,
|
||||
ret_slots: 1,
|
||||
},
|
||||
SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
},
|
||||
],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::GFX | caps::AUDIO | caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "mixed status-first surface must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(
|
||||
vm.operand_stack_top(4),
|
||||
vec![
|
||||
Value::Int64(0),
|
||||
Value::Int64(AssetLoadError::AssetNotFound as i64),
|
||||
Value::Int64(AudioOpStatus::AssetNotFound as i64),
|
||||
Value::Int64(GfxOpStatus::AssetNotFound as i64),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_gfx_set_sprite_type_mismatch_surfaces_trap_not_panic() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
# PR006 - Conformance Regression Suite Fault Status
|
||||
|
||||
## Briefing
|
||||
|
||||
Depois de migrar `gfx`, `audio` e `asset` para status-first, precisamos blindar regressao.
|
||||
|
||||
Esta PR fecha cobertura de conformidade para fronteira `status`/`Trap`/`Panic`.
|
||||
|
||||
## Alvo
|
||||
|
||||
Adicionar/ajustar suite de testes para garantir que o contrato decidido continue estavel.
|
||||
|
||||
Arquivos principais (esperados):
|
||||
|
||||
- testes de `crates/console/prometeu-system/src/virtual_machine_runtime/`
|
||||
- testes de `crates/console/prometeu-vm/src/virtual_machine.rs`
|
||||
- testes de `crates/console/prometeu-hal/src/syscalls/tests.rs`
|
||||
|
||||
## Escopo Funcional
|
||||
|
||||
- testes negativos: erro operacional nao pode virar `Panic`;
|
||||
- testes de shape ABI: aridade/tipo/capability continuam `Trap`;
|
||||
- testes para proibicao de no-op silencioso nos dominios atualizados;
|
||||
- smoke de interoperacao entre registry, loader e dispatch apos migracao.
|
||||
|
||||
## Fora de Escopo
|
||||
|
||||
- cobertura exaustiva de performance;
|
||||
- novos dominios alem de `gfx`, `audio`, `asset`.
|
||||
|
||||
## Critérios de Aceite
|
||||
|
||||
- matriz minima de cenarios `status`/`Trap`/`Panic` coberta por dominio;
|
||||
- regressao de panic operacional bloqueada por teste;
|
||||
- execucao dos pacotes de teste alvo sem falha.
|
||||
|
||||
## Tests
|
||||
|
||||
- `cargo test -p prometeu-hal`
|
||||
- `cargo test -p prometeu-vm`
|
||||
- `cargo test -p prometeu-system`
|
||||
- `cargo test -p prometeu-drivers`
|
||||
@ -37,17 +37,3 @@ Uma PR deste diretório deve:
|
||||
## Roadmap Publicado
|
||||
|
||||
PRs propostas para execucao da rodada atual:
|
||||
|
||||
1. `PR001-spec-core-sync-16-and-16a.md`
|
||||
2. `PR002-gfx-status-first-surface-and-fault-matrix.md`
|
||||
3. `PR003-audio-status-first-surface-and-fault-matrix.md`
|
||||
4. `PR004-asset-status-first-surface-and-lifecycle.md`
|
||||
5. `PR005-abi-verifier-loader-and-stress-regeneration.md`
|
||||
6. `PR006-conformance-regression-suite-fault-status.md`
|
||||
|
||||
Sequenciamento recomendado:
|
||||
|
||||
- `PR001` primeiro;
|
||||
- `PR002`, `PR003` e `PR004` em paralelo;
|
||||
- `PR005` depois das tres verticais;
|
||||
- `PR006` por ultimo para consolidacao de regressao.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user