use super::{
classify_emit_error, classify_validation_error, is_cfg_structurization_error,
is_cross_binding_pointer_merge_error, is_dynamic_struct_index_error,
is_logical_pointer_operand_error, is_logical_pointer_phi_error, is_pointer_typing_emit_error,
is_pointer_typing_validation_error, EmitErrorClass, ValidationClass,
};
#[test]
fn other_class_refinement_predicates_match_their_exact_messages() {
assert!(is_dynamic_struct_index_error(
"Index into a structure must be an OpConstant"
));
assert_eq!(
classify_validation_error("Index into a structure must be an OpConstant"),
ValidationClass::Other
);
assert!(!is_dynamic_struct_index_error(
"OpPhi may only have a logical pointer operand"
));
assert!(is_logical_pointer_operand_error(
"Instruction may not have a logical pointer operand"
));
assert_eq!(
classify_validation_error("Instruction may not have a logical pointer operand"),
ValidationClass::Other
);
assert!(!is_logical_pointer_operand_error(
"OpPhi may only have a logical pointer operand"
));
assert!(!is_logical_pointer_phi_error(
"Instruction may not have a logical pointer operand"
));
}
#[test]
fn pointer_typing_validation_matches_access_chain_messages() {
assert!(is_pointer_typing_validation_error(
"OpInBoundsAccessChain cannot find index 3"
));
assert!(is_pointer_typing_validation_error(
"Result Type does not match Pointer type"
));
assert!(is_pointer_typing_validation_error(
"Index 2 is out of bounds: reached non-composite type"
));
assert!(is_pointer_typing_validation_error(
"Result Type does not match the type used to index into the composite"
));
assert!(!is_pointer_typing_validation_error(
"some unrelated parser failure"
));
assert!(!is_pointer_typing_validation_error(
"diagnostic emitted prior to indexing the resource table"
));
assert!(!is_pointer_typing_validation_error(
"the pass failed to index the descriptor set"
));
}
#[test]
fn cfg_structurization_is_case_insensitive_over_its_family() {
assert!(is_cfg_structurization_error(
"Structured CFG rejected: unstructured back-edge"
));
assert!(is_cfg_structurization_error(
"Block 5 has a back-edge to a non-header block"
));
assert!(is_cfg_structurization_error(
"Block 5 appears in the binary before its dominator 3"
));
assert!(is_cfg_structurization_error("BACK-EDGE detected"));
assert!(is_cfg_structurization_error(
"Block '699[%699]' is already a merge block for another header"
));
assert!(!is_cfg_structurization_error("bit width mismatch"));
}
#[test]
fn cfg_structurization_routes_captured_spirv_val_messages() {
for msg in [
"Block '4122[%4122]' appears in the binary before its dominator '4540[%4540]'",
"block <ID> '600[%600]' exits the selection headed by <ID> '583[%583]', \
but not via a structured exit",
"block <ID> 4953 branches to the loop construct, but not to the loop header <ID> 4929",
"block <ID> 2640 branches to the selection construct, \
but not to the selection header <ID> 1849",
"Case construct that targets '193[%193]' has invalid branch to block '226[%226]' \
(not another case construct, corresponding merge, outer loop merge or outer loop continue)",
"Multiple case constructs have branches to the case construct that targets '501[%501]'",
"ID '1234[%1234]' defined in block '10[%10]' does not dominate its use in block '20[%20]'",
"Selection must be structured",
"The selection construct with the selection header '742[%742]' \
does not structurally dominate the merge block '3760[%3760]'",
] {
assert_eq!(
classify_validation_error(msg),
ValidationClass::CfgStructurization,
"captured spirv-val cfg message must route to CfgStructurization: {msg}"
);
}
}
#[test]
fn logical_pointer_phi_and_cross_binding_match_their_exact_messages() {
assert!(is_logical_pointer_phi_error(
"OpPhi may only have a logical pointer operand"
));
assert!(!is_logical_pointer_phi_error(
"Variable pointers must point into the same structure"
));
assert!(is_cross_binding_pointer_merge_error(
"Variable pointers must point into the same structure or array"
));
assert!(!is_cross_binding_pointer_merge_error(
"OpPhi may only have a logical pointer operand"
));
}
#[test]
fn pointer_typing_emit_matches_reinterpret_and_storage_gaps() {
assert!(is_pointer_typing_emit_error("load bit width mismatch"));
assert!(is_pointer_typing_emit_error(
"missing pointer storage class"
));
assert!(is_pointer_typing_emit_error(
"cannot reinterpret load of byte pointer"
));
assert!(is_pointer_typing_emit_error(
"cannot reinterpret workgroup pointer"
));
assert!(!is_pointer_typing_emit_error(
"Structured CFG rejected: unstructured back-edge"
));
}
#[test]
fn classify_validation_routes_each_family() {
assert_eq!(
classify_validation_error("OpInBoundsAccessChain cannot find index 0"),
ValidationClass::PointerTyping
);
assert_eq!(
classify_validation_error("loop header block 4 does not dominate its merge"),
ValidationClass::CfgStructurization
);
assert_eq!(
classify_validation_error("ID '4994[%4994]' has not been defined"),
ValidationClass::CfgStructurization
);
assert_eq!(
classify_validation_error("OpPhi may only have a logical pointer operand"),
ValidationClass::LogicalPointerPhi
);
assert_eq!(
classify_validation_error("Variable pointers must point into the same structure"),
ValidationClass::CrossBindingPointerMerge
);
assert_eq!(
classify_validation_error("unrelated intrinsic lowering failure"),
ValidationClass::Other
);
}
#[test]
fn classify_validation_precedence_is_pointer_typing_before_cfg() {
let both = "Result does not match Pointer type at a back-edge";
assert!(is_pointer_typing_validation_error(both));
assert!(is_cfg_structurization_error(both));
assert_eq!(
classify_validation_error(both),
ValidationClass::PointerTyping
);
}
#[test]
fn classify_validation_precedence_phi_before_cross_binding() {
let both = "OpPhi may only have a logical pointer operand; \
Variable pointers must point into the same structure";
assert!(is_logical_pointer_phi_error(both));
assert!(is_cross_binding_pointer_merge_error(both));
assert_eq!(
classify_validation_error(both),
ValidationClass::LogicalPointerPhi
);
}
#[test]
fn classify_emit_routes_pointer_typing_then_other() {
assert_eq!(
classify_emit_error("load bit width mismatch"),
EmitErrorClass::PointerTyping
);
assert_eq!(
classify_emit_error("native emitter: structured cfg rejected"),
EmitErrorClass::Other
);
assert_eq!(
classify_emit_error("out of registers"),
EmitErrorClass::Other
);
let both = "missing pointer storage in a structured cfg block";
assert!(is_pointer_typing_emit_error(both));
assert!(is_cfg_structurization_error(both));
assert_eq!(classify_emit_error(both), EmitErrorClass::PointerTyping);
}