alex/volcanic
Automated vulkan bindings
BRANCH main
SNAPSHOT Improved loading api and made ready for publish
DOWNLOAD
root codegen src emit tests.rs
use super::*;
#[test]
fn propagates_promoted_and_conditional_ownership() {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let vk = Registry::load(manifest_dir.join("../spec/vk.xml")).unwrap();
let video = Registry::load(manifest_dir.join("../spec/video.xml")).unwrap();
let selection = select::select_vulkan(&vk, &video);
let enum_index = enum_index(&vk, &video, &selection);
let mut modules = emit_modules(&selection, &enum_index);
expand_module_dependencies(&vk, &video, &enum_index, &mut modules);
let ctx = Context::new(&vk, &video, &modules);
let maintenance5 = select::FeatureExpr::feature("vk_khr_maintenance5");
assert!(maintenance5.implies(ctx.type_condition("VkPipelineCreateFlags2")));
assert!(maintenance5.implies(ctx.type_condition("VkPipelineCreateFlags2CreateInfo")));
let maintenance11_with_extended_flags = select::FeatureExpr::all([
select::FeatureExpr::feature("vk_khr_maintenance11"),
select::FeatureExpr::feature("vk_khr_extended_flags"),
]);
let image_flag = ctx.enum_condition("VK_IMAGE_CREATE_2_ALIAS_SINGLE_LAYER_DESCRIPTOR_BIT_KHR");
assert!(maintenance11_with_extended_flags.implies(image_flag));
assert!(
!maintenance11_with_extended_flags
.implies(ctx.enum_condition("VK_SHADER_CREATE_INDEPENDENT_SETS_BIT_KHR"))
);
}
#[test]
fn translates_c_constants() {
assert_eq!(rust_const_expr("(~0U)"), "u32::MAX");
assert_eq!(rust_const_expr("1000.0F"), "1000.0f32");
assert_eq!(rust_const_expr("0x7FFFFFFF"), "0x7FFFFFFF");
assert_eq!(rust_const_expr("0xFF"), "0xFF");
assert_eq!(rust_const_expr("\"VK_EXT_test\""), "c\"VK_EXT_test\"");
}
#[test]
fn parses_numeric_define_values() {
assert_eq!(
numeric_define_value("#define VK_HEADER_VERSION 349", "VK_HEADER_VERSION"),
Some("349".to_string())
);
assert_eq!(
numeric_define_value("#define EXAMPLE 123U", "EXAMPLE"),
Some("123".to_string())
);
assert_eq!(
numeric_define_value("#define EXAMPLE SOME_MACRO(1)", "EXAMPLE"),
None
);
}
#[test]
fn derives_bitflag_associated_names() {
assert_eq!(
flag_assoc_name("VkQueueFlagBits", "VK_QUEUE_GRAPHICS_BIT"),
"GRAPHICS"
);
assert_eq!(
flag_assoc_name(
"VkPipelineStageFlagBits2",
"VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR"
),
"ALL_TRANSFER_KHR"
);
assert_eq!(
flag_assoc_name(
"VkTensorCreateFlagBitsARM",
"VK_TENSOR_CREATE_MUTABLE_FORMAT_BIT_ARM"
),
"MUTABLE_FORMAT_ARM"
);
}
#[test]
fn derives_rust_enum_variant_names() {
assert_eq!(
enum_variant_name("VkStructureType", "VK_STRUCTURE_TYPE_APPLICATION_INFO"),
"ApplicationInfo"
);
assert_eq!(
enum_variant_name(
"VkStructureType",
"VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR"
),
"SwapchainCreateInfoKhr"
);
assert_eq!(enum_variant_name("VkResult", "VK_SUCCESS"), "Success");
assert_eq!(
enum_variant_name("VkResult", "VK_ERROR_OUT_OF_HOST_MEMORY"),
"ErrorOutOfHostMemory"
);
assert_eq!(
enum_variant_name("VkPresentModeKHR", "VK_PRESENT_MODE_FIFO_RELAXED_KHR"),
"FifoRelaxed"
);
assert_eq!(
enum_variant_name(
"StdVideoH264ProfileIdc",
"STD_VIDEO_H264_PROFILE_IDC_BASELINE"
),
"Baseline"
);
}
#[test]
fn resolves_enum_alias_chains_and_rejects_cycles() {
let condition = select::FeatureExpr::feature("core_1_0");
let resolved = |name, value, alias| ResolvedEnum {
entry: enum_entry(name, value, alias),
group_name: Some("VkResult".into()),
extension_number: None,
condition: condition.clone(),
};
let entries = [
resolved("VK_SUCCESS", Some("0"), None),
resolved("VK_SUCCESS_ALIAS", None, Some("VK_SUCCESS")),
resolved("VK_SUCCESS_ALIAS2", None, Some("VK_SUCCESS_ALIAS")),
resolved("VK_CYCLE", None, Some("VK_CYCLE")),
resolved("VK_MISSING", None, Some("VK_UNKNOWN")),
];
let index = entries
.iter()
.map(|entry| (entry.entry.name.as_str(), entry))
.collect();
let widths = IndexMap::from([("VkResult".into(), "i32")]);
assert_eq!(enum_value(&entries[2], &index, &widths), "0");
for entry in &entries[3..] {
assert!(std::panic::catch_unwind(|| enum_value(entry, &index, &widths)).is_err());
}
}
#[test]
fn enum_synonyms_keep_their_own_feature_conditions() {
let mut infos = IndexMap::new();
let core = select::FeatureExpr::feature("core_1_0");
let extension = select::FeatureExpr::feature("vk_ext_example");
insert_enum_constant(&mut infos, "VkResult", "Success", "0".into(), &core);
insert_enum_constant(
&mut infos,
"VkResult",
"SuccessAlias",
"0".into(),
&extension,
);
insert_enum_constant(&mut infos, "VkResult", "Success", "0".into(), &extension);
let constants = &infos["VkResult"].constants;
assert_eq!(constants.len(), 2);
assert_eq!(
constants["Success"].condition,
select::FeatureExpr::any([core, extension.clone()])
);
assert_eq!(constants["SuccessAlias"].condition, extension);
}
#[test]
fn selects_bitmask_storage_width() {
assert_eq!(bitmask_bits_ty(Some("VkFlags")), "u32");
assert_eq!(bitmask_bits_ty(Some("VkFlags64")), "u64");
assert_eq!(bitmask_bits_ty(None), "u32");
}
#[test]
fn classifies_command_scopes() {
let commands = [
command("vkCreateInstance", &[]),
command("vkGetInstanceProcAddr", &[("instance", "VkInstance")]),
command("vkGetDeviceProcAddr", &[("device", "VkDevice")]),
command(
"vkGetPhysicalDeviceProperties",
&[("physicalDevice", "VkPhysicalDevice")],
),
command("vkQueueSubmit", &[("queue", "VkQueue")]),
command("vkCmdDraw", &[("commandBuffer", "VkCommandBuffer")]),
];
let command_map: IndexMap<_, _> = commands
.iter()
.map(|command| (command.name.as_str(), command))
.collect();
let handle_parents = IndexMap::from([
("VkPhysicalDevice".to_string(), "VkInstance".to_string()),
("VkDevice".to_string(), "VkPhysicalDevice".to_string()),
("VkQueue".to_string(), "VkDevice".to_string()),
("VkCommandBuffer".to_string(), "VkCommandPool".to_string()),
("VkCommandPool".to_string(), "VkDevice".to_string()),
]);
let dispatchable_handles = IndexSet::from([
"VkInstance".to_string(),
"VkPhysicalDevice".to_string(),
"VkDevice".to_string(),
"VkQueue".to_string(),
"VkCommandBuffer".to_string(),
]);
let scope = |name| {
command_scope(
command_map.get(name).copied().unwrap(),
&command_map,
&handle_parents,
&dispatchable_handles,
)
};
assert_eq!(scope("vkCreateInstance"), CommandScope::Global);
assert_eq!(scope("vkGetInstanceProcAddr"), CommandScope::Global);
assert_eq!(scope("vkGetDeviceProcAddr"), CommandScope::Instance);
assert_eq!(
scope("vkGetPhysicalDeviceProperties"),
CommandScope::Instance
);
assert_eq!(scope("vkQueueSubmit"), CommandScope::Device);
assert_eq!(scope("vkCmdDraw"), CommandScope::Device);
}
#[test]
fn renders_loader_call_arguments() {
let decls = vec![
decl("commandBuffer", "VkCommandBuffer"),
decl("type", "VkImageType"),
];
assert_eq!(call_args(&decls), "commandBuffer, r#type");
}
fn enum_entry(name: &str, value: Option<&str>, alias: Option<&str>) -> EnumEntry {
EnumEntry {
name: name.to_string(),
value: value.map(ToOwned::to_owned),
bitpos: None,
offset: None,
alias: alias.map(ToOwned::to_owned),
extends: None,
extnumber: None,
dir: None,
ty: None,
api: None,
}
}
fn command(name: &str, params: &[(&str, &str)]) -> Command {
Command {
name: name.to_string(),
api: None,
alias: None,
proto: Some(decl(name, "void")),
params: params.iter().map(|(name, base)| decl(name, base)).collect(),
}
}
fn decl(name: &str, base: &str) -> Decl {
Decl {
name: name.to_string(),
api: None,
base: base.to_string(),
base_const: false,
pointer_const: Vec::new(),
arrays: Vec::new(),
bit_width: None,
}
}
#[test]
fn array_parameters_decay_only_the_outer_dimension() {
let doc = roxmltree::Document::parse(
"<param>const <type>float</type> <name>matrix</name>[3][4]</param>",
)
.unwrap();
let decl = crate::ctype::parse_decl(doc.root_element());
assert_eq!(rust_decl_type(&decl, false), "[[f32; 4]; 3]");
assert_eq!(rust_param_type(&decl), "*const [f32; 4]");
}
#[test]
fn empty_sections_preserve_surrounding_code() {
let mut out = "pub const BEFORE: u32 = 1;\n".to_string();
section(&mut out, "Feature and extension guards").finish(&mut out);
out.push_str("pub const AFTER: u32 = 2;\n");
assert_eq!(
out,
"pub const BEFORE: u32 = 1;\npub const AFTER: u32 = 2;\n"
);
}