use super::*;
fn field(name: &str, ordinal: u32, ty: v2::FieldType) -> v2::StructMember {
v2::StructMember {
member: Some(v2::struct_member::Member::Field(Box::new(v2::Field {
name: name.to_string(),
ordinal,
r#type: Some(ty),
..Default::default()
}))),
}
}
fn retired(ordinal: u32) -> v2::StructMember {
v2::StructMember {
member: Some(v2::struct_member::Member::Reserved(v2::Reserved {
ordinal,
..Default::default()
})),
}
}
fn primitive(primitive: v2::PrimitiveType) -> v2::FieldType {
v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Primitive(primitive as i32)),
}
}
fn named(reference: &str) -> v2::FieldType {
v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Named(reference.to_string())),
}
}
fn decl(name: &str, kind: v2::decl::Kind) -> v2::Decl {
v2::Decl {
name: name.to_string(),
kind: Some(kind),
..Default::default()
}
}
fn package(name: &str, decls: Vec<v2::Decl>) -> v2::Package {
v2::Package {
name: name.to_string(),
decls,
..Default::default()
}
}
fn string_type(characters: u64) -> v2::decl::Kind {
v2::decl::Kind::TypeDef(v2::TypeDef {
backing: Some(v2::Backing {
kind: Some(v2::backing::Kind::Primitive(
v2::PrimitiveType::String as i32,
)),
}),
constraint: Some(v2::Constraint {
len_max: Some(characters),
..Default::default()
}),
..Default::default()
})
}
fn bytes_type(length: u64) -> v2::decl::Kind {
v2::decl::Kind::TypeDef(v2::TypeDef {
backing: Some(v2::Backing {
kind: Some(v2::backing::Kind::Primitive(
v2::PrimitiveType::Bytes as i32,
)),
}),
constraint: Some(v2::Constraint {
len_max: Some(length),
..Default::default()
}),
..Default::default()
})
}
fn int_type(width: v2::IntWidth) -> v2::decl::Kind {
v2::decl::Kind::TypeDef(v2::TypeDef {
backing: Some(v2::Backing {
kind: Some(v2::backing::Kind::Primitive(
v2::PrimitiveType::Integer as i32,
)),
}),
width: Some(v2::type_def::Width::IntWidth(width as i32)),
..Default::default()
})
}
fn holder_of(field_type: v2::FieldType) -> v2::Decl {
decl(
"Holder",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![field("value", 1, field_type)],
..Default::default()
}),
)
}
fn bound(packages: &[&v2::Package], name: &str) -> Option<u64> {
let home = packages[0];
let decl = home
.decls
.iter()
.find(|decl| decl.name == name)
.expect("the fixture declares it");
max_size(
Packages {
package: home,
others: &packages[1..],
},
decl,
)
}
#[test]
fn a_struct_slot_is_its_ordinal_minus_one_and_a_tombstone_keeps_its_slot() {
let def = v2::StructDef {
members: vec![
field("desired", 1, primitive(v2::PrimitiveType::Float)),
field("trim", 3, primitive(v2::PrimitiveType::Integer)),
retired(4),
],
..Default::default()
};
let layout = struct_table("Setpoint", &def).expect("layout");
assert_eq!(
layout.slots,
vec![
FieldSlot {
id: 0,
source: SlotSource::Field {
name: "desired".to_string(),
ordinal: 1
}
},
FieldSlot {
id: 2,
source: SlotSource::Field {
name: "trim".to_string(),
ordinal: 3
}
},
FieldSlot {
id: 3,
source: SlotSource::Retired { ordinal: 4 }
},
]
);
assert_eq!(layout.vtable_slots(), 4);
}
#[test]
fn ordinal_zero_is_refused_rather_than_underflowed() {
let def = v2::StructDef {
members: vec![field("bad", 0, primitive(v2::PrimitiveType::Boolean))],
..Default::default()
};
let error = struct_table("Broken", &def).expect_err("ordinal 0 is refused");
assert!(error.message.contains("ordinal 0"), "{}", error.message);
}
#[test]
fn the_generated_tables_take_the_slots_adr_0019_fixes() {
let ids = |layout: TableLayout| layout.slots.iter().map(|slot| slot.id).collect::<Vec<_>>();
assert_eq!(ids(map_entry_table()), vec![0, 1]);
assert_eq!(ids(union_wrapper_table()), vec![1]);
assert_eq!(union_wrapper_table().vtable_slots(), 2);
assert_eq!(ids(union_arm_box_table()), vec![0]);
}
#[test]
fn a_tuple_table_is_positional_from_zero() {
let tuple = v2::TupleType {
fields: vec![
v2::TupleField {
name: "min".to_string(),
r#type: Some(primitive(v2::PrimitiveType::Float)),
},
v2::TupleField {
name: "max".to_string(),
r#type: Some(primitive(v2::PrimitiveType::Float)),
},
],
};
let layout = tuple_table("TelemetryBounds", &tuple).expect("layout");
assert_eq!(
layout.slots,
vec![
FieldSlot {
id: 0,
source: SlotSource::TupleField { position: 1 }
},
FieldSlot {
id: 1,
source: SlotSource::TupleField { position: 2 }
},
]
);
}
#[test]
fn a_union_arms_discriminant_is_its_ordinal_and_a_tombstone_keeps_it_occupied() {
let def = v2::UnionDef {
arms: vec![
v2::UnionArm {
name: "engage".to_string(),
ordinal: 2,
type_ref: "Setpoint".to_string(),
..Default::default()
},
v2::UnionArm {
name: "disengage".to_string(),
ordinal: 3,
type_ref: "Percent".to_string(),
..Default::default()
},
],
reserved: vec![v2::Reserved {
ordinal: 1,
..Default::default()
}],
..Default::default()
};
let discriminants: Vec<u32> = def.arms.iter().map(union_arm_discriminant).collect();
assert_eq!(discriminants, vec![2, 3]);
}
#[test]
fn an_enum_with_no_zero_member_needs_the_null_default() {
let with_zero = v2::EnumDef {
values: vec![v2::EnumValue {
name: "OFF".to_string(),
value: 0,
..Default::default()
}],
..Default::default()
};
let without_zero = v2::EnumDef {
values: vec![v2::EnumValue {
name: "ARMED".to_string(),
value: 1,
..Default::default()
}],
..Default::default()
};
assert!(!enum_field_needs_null_default(&with_zero));
assert!(enum_field_needs_null_default(&without_zero));
}
#[test]
fn every_declaration_that_projects_a_type_is_rooted_somewhere() {
assert_eq!(
root_table(&decl(
"Setpoint",
v2::decl::Kind::StructDef(v2::StructDef::default())
)),
Some(RootTable::Own)
);
assert_eq!(
root_table(&decl(
"Command",
v2::decl::Kind::UnionDef(v2::UnionDef::default())
)),
Some(RootTable::UnionWrapper)
);
assert_eq!(
root_table(&decl("Percent", int_type(v2::IntWidth::U8))),
Some(RootTable::Box)
);
assert_eq!(
root_table(&decl(
"EngageState",
v2::decl::Kind::EnumDef(v2::EnumDef::default())
)),
Some(RootTable::Box)
);
assert_eq!(
root_table(&decl(
"Faults",
v2::decl::Kind::EnumSetDef(v2::EnumSetDef {
width: v2::IntWidth::U8 as i32,
..Default::default()
})
)),
Some(RootTable::Box)
);
}
#[test]
fn a_constant_is_rooted_nowhere() {
assert_eq!(
root_table(&decl(
"MAX_SPEED",
v2::decl::Kind::ConstDef(v2::ConstDef::default())
)),
None
);
}
#[test]
fn the_root_box_is_decision_2s_arm_box() {
assert_eq!(root_box_table(), union_arm_box_table());
}
#[test]
fn a_named_scalar_root_is_bounded_by_its_box() {
let pkg = package(
"veh.cruise",
vec![decl("Percent", int_type(v2::IntWidth::U8))],
);
assert_eq!(
bound(&[&pkg], "Percent"),
Some(ROOT + OFFSET + 1 + ALIGN_SLACK * 2 + (VTABLE_HEADER + VTABLE_SLOT + ALIGN_SLACK))
);
}
#[test]
fn an_enum_root_is_charged_its_long_and_an_enum_set_root_its_width() {
let pkg = package(
"veh.cruise",
vec![
decl(
"EngageState",
v2::decl::Kind::EnumDef(v2::EnumDef {
values: vec![v2::EnumValue {
name: "OFF".to_string(),
value: 0,
..Default::default()
}],
..Default::default()
}),
),
decl(
"Faults",
v2::decl::Kind::EnumSetDef(v2::EnumSetDef {
width: v2::IntWidth::U16 as i32,
..Default::default()
}),
),
],
);
let box_overhead =
ROOT + OFFSET + ALIGN_SLACK * 2 + (VTABLE_HEADER + VTABLE_SLOT + ALIGN_SLACK);
assert_eq!(bound(&[&pkg], "EngageState"), Some(box_overhead + 8));
assert_eq!(bound(&[&pkg], "Faults"), Some(box_overhead + 2));
}
#[test]
fn a_string_root_pays_its_box_and_its_bytes() {
let pkg = package("veh.cruise", vec![decl("Label", string_type(8))]);
assert_eq!(
bound(&[&pkg], "Label"),
Some(
ROOT + OFFSET
+ OFFSET
+ ALIGN_SLACK * 2
+ (VTABLE_HEADER + VTABLE_SLOT + ALIGN_SLACK)
+ (OFFSET + 8 * 4 + 1 + ALIGN_SLACK)
)
);
}
#[test]
fn a_scalar_struct_is_bounded_by_its_own_table() {
let pkg = package(
"veh.cruise",
vec![decl(
"Flags",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![field("on", 1, primitive(v2::PrimitiveType::Boolean))],
..Default::default()
}),
)],
);
assert_eq!(
bound(&[&pkg], "Flags"),
Some(ROOT + OFFSET + 1 + ALIGN_SLACK * 2 + (VTABLE_HEADER + VTABLE_SLOT + ALIGN_SLACK))
);
}
#[test]
fn a_wider_member_costs_more_than_a_narrower_one() {
let narrow = package(
"veh.cruise",
vec![
decl("Small", int_type(v2::IntWidth::U8)),
holder_of(named("Small")),
],
);
let wide = package(
"veh.cruise",
vec![
decl("Small", int_type(v2::IntWidth::U64)),
holder_of(named("Small")),
],
);
assert_eq!(
bound(&[&wide], "Holder").unwrap() - bound(&[&narrow], "Holder").unwrap(),
7
);
}
#[test]
fn a_string_is_charged_four_bytes_a_character() {
let eight = package(
"veh.cruise",
vec![decl("Label", string_type(8)), holder_of(named("Label"))],
);
let four = package(
"veh.cruise",
vec![decl("Label", string_type(4)), holder_of(named("Label"))],
);
assert_eq!(
bound(&[&eight], "Holder").unwrap() - bound(&[&four], "Holder").unwrap(),
16
);
}
#[test]
fn an_array_charges_its_maximum_element_count() {
let holder = |max: u64| {
package(
"veh.cruise",
vec![holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Array(Box::new(v2::ArrayType {
element: Some(Box::new(primitive(v2::PrimitiveType::Boolean))),
min: 0,
max,
}))),
})],
)
};
let eight = holder(8);
let four = holder(4);
assert_eq!(
bound(&[&eight], "Holder").unwrap() - bound(&[&four], "Holder").unwrap(),
4
);
}
#[test]
fn a_union_is_bounded_by_its_largest_arm() {
let pkg = package(
"veh.cruise",
vec![
decl("Percent", int_type(v2::IntWidth::U8)),
decl(
"Setpoint",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![
field("a", 1, primitive(v2::PrimitiveType::Float)),
field("b", 2, primitive(v2::PrimitiveType::Float)),
],
..Default::default()
}),
),
decl(
"Command",
v2::decl::Kind::UnionDef(v2::UnionDef {
arms: vec![
v2::UnionArm {
name: "engage".to_string(),
ordinal: 1,
type_ref: "Setpoint".to_string(),
..Default::default()
},
v2::UnionArm {
name: "disengage".to_string(),
ordinal: 2,
type_ref: "Percent".to_string(),
..Default::default()
},
],
..Default::default()
}),
),
],
);
let union_bound = bound(&[&pkg], "Command").expect("bounded");
let setpoint_bound = bound(&[&pkg], "Setpoint").expect("bounded");
assert!(
union_bound > setpoint_bound,
"{union_bound} vs {setpoint_bound}"
);
}
#[test]
fn an_arm_that_is_not_a_table_pays_for_its_box() {
let pkg = package(
"veh.cruise",
vec![
decl("Percent", int_type(v2::IntWidth::U8)),
decl(
"Command",
v2::decl::Kind::UnionDef(v2::UnionDef {
arms: vec![v2::UnionArm {
name: "disengage".to_string(),
ordinal: 1,
type_ref: "Percent".to_string(),
..Default::default()
}],
..Default::default()
}),
),
],
);
let wrapper_only = ROOT
+ OFFSET
+ (1 + OFFSET)
+ ALIGN_SLACK * 3
+ (VTABLE_HEADER + 2 * VTABLE_SLOT + ALIGN_SLACK);
assert_eq!(
bound(&[&pkg], "Command").expect("bounded") - wrapper_only,
OFFSET + 1 + ALIGN_SLACK * 2 + (VTABLE_HEADER + VTABLE_SLOT + ALIGN_SLACK)
);
}
#[test]
fn a_foreign_reference_is_followed_into_the_package_that_declares_it() {
let parts = package(
"proto.parts",
vec![decl("Percent", int_type(v2::IntWidth::U8))],
);
let vehicle = package(
"proto.vehicle",
vec![holder_of(named("proto.parts.Percent"))],
);
assert!(bound(&[&vehicle, &parts], "Holder").is_some());
assert_eq!(bound(&[&vehicle], "Holder"), None);
}
#[test]
fn a_bare_string_map_key_has_no_bound() {
let pkg = package(
"veh.cruise",
vec![holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Map(Box::new(v2::MapType {
key: Some(Box::new(primitive(v2::PrimitiveType::String))),
value: Some(Box::new(primitive(v2::PrimitiveType::Boolean))),
min: 0,
max: 8,
}))),
})],
);
assert_eq!(bound(&[&pkg], "Holder"), None);
}
#[test]
fn a_bounded_map_key_is_bounded() {
let pkg = package(
"veh.cruise",
vec![
decl("Label", string_type(8)),
holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Map(Box::new(v2::MapType {
key: Some(Box::new(named("Label"))),
value: Some(Box::new(primitive(v2::PrimitiveType::Boolean))),
min: 0,
max: 8,
}))),
}),
],
);
assert!(bound(&[&pkg], "Holder").is_some());
}
#[test]
fn a_type_that_reaches_itself_has_no_bound() {
let pkg = package(
"veh.cruise",
vec![
decl(
"Left",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![field("right", 1, named("Right"))],
..Default::default()
}),
),
decl(
"Right",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![field("left", 1, named("Left"))],
..Default::default()
}),
),
],
);
assert_eq!(bound(&[&pkg], "Left"), None);
}
#[test]
fn an_overflowing_count_has_no_bound() {
let pkg = package(
"veh.cruise",
vec![holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Array(Box::new(v2::ArrayType {
element: Some(Box::new(primitive(v2::PrimitiveType::Integer))),
min: 0,
max: u64::MAX,
}))),
})],
);
assert_eq!(bound(&[&pkg], "Holder"), None);
}
#[test]
fn a_table_charges_alignment_slack_for_every_slot() {
let alternating = package(
"veh.cruise",
vec![
decl("Narrow", int_type(v2::IntWidth::U8)),
decl("Wide", int_type(v2::IntWidth::U64)),
decl(
"Holder",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![
field("a", 1, named("Narrow")),
field("b", 2, named("Wide")),
field("c", 3, named("Narrow")),
field("d", 4, named("Wide")),
],
..Default::default()
}),
),
],
);
let charged = bound(&[&alternating], "Holder").expect("bounded");
let worst_case = OFFSET
+ ALIGN_SLACK
+ OFFSET
+ ALIGN_SLACK
+ 18
+ 4 * ALIGN_SLACK
+ (VTABLE_HEADER + 4 * VTABLE_SLOT + 1);
assert!(
charged >= worst_case,
"the bound {charged} must cover the worst write order, which costs {worst_case}"
);
}
#[test]
fn a_shared_type_is_walked_once() {
let mut decls = vec![decl(
"S30",
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![field("x", 1, primitive(v2::PrimitiveType::Boolean))],
..Default::default()
}),
)];
for level in (0..30).rev() {
decls.push(decl(
&format!("S{level}"),
v2::decl::Kind::StructDef(v2::StructDef {
members: vec![
field("a", 1, named(&format!("S{}", level + 1))),
field("b", 2, named(&format!("S{}", level + 1))),
],
..Default::default()
}),
));
}
let pkg = package("veh.cruise", decls);
assert_eq!(bound(&[&pkg], "S0"), None);
assert!(bound(&[&pkg], "S28").is_some());
}
#[test]
fn a_bound_larger_than_an_offset_can_address_is_refused() {
let pkg = package(
"veh.cruise",
vec![
decl("Blob", bytes_type(256)),
holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Array(Box::new(v2::ArrayType {
element: Some(Box::new(named("Blob"))),
min: 0,
max: 20_000_000,
}))),
}),
],
);
assert_eq!(bound(&[&pkg], "Holder"), None);
}
#[test]
fn a_bound_just_inside_the_offset_range_is_kept() {
let pkg = package(
"veh.cruise",
vec![
decl("Blob", bytes_type(256)),
holder_of(v2::FieldType {
optional: false,
kind: Some(v2::field_type::Kind::Array(Box::new(v2::ArrayType {
element: Some(Box::new(named("Blob"))),
min: 0,
max: 1_000,
}))),
}),
],
);
let charged = bound(&[&pkg], "Holder").expect("bounded");
assert!(charged <= MAX_ENCODABLE, "{charged}");
}
#[test]
fn a_declaration_that_projects_no_type_has_no_bound() {
let pkg = package(
"veh.cruise",
vec![decl(
"MAX_SPEED",
v2::decl::Kind::ConstDef(v2::ConstDef::default()),
)],
);
assert_eq!(bound(&[&pkg], "MAX_SPEED"), None);
}
#[test]
fn a_bare_name_resolves_in_the_home_package_not_the_root() {
let root = package(
"p",
vec![
decl("Inner", int_type(v2::IntWidth::U8)),
decl("RootOnly", int_type(v2::IntWidth::U8)),
],
);
let imported = package(
"q",
vec![
decl("Inner", int_type(v2::IntWidth::U64)),
decl("OtherOnly", int_type(v2::IntWidth::U64)),
],
);
let others = [&imported];
let packages = Packages {
package: &root,
others: &others,
};
let (decl, declaring) = packages
.resolve(&imported, "Inner")
.expect("q declares Inner");
assert_eq!(declaring.name, "q");
assert!(matches!(
&decl.kind,
Some(v2::decl::Kind::TypeDef(td))
if td.width == Some(v2::type_def::Width::IntWidth(v2::IntWidth::U64 as i32))
));
let (_, declaring) = packages.resolve(&root, "Inner").expect("p declares Inner");
assert_eq!(declaring.name, "p");
assert_eq!(packages.resolve(&imported, "p.Inner").unwrap().1.name, "p");
assert_eq!(packages.resolve(&root, "q.Inner").unwrap().1.name, "q");
assert!(packages.resolve(&root, "r.Inner").is_none());
assert!(packages.resolve(&root, "q.Nowhere").is_none());
assert!(packages.resolve(&root, "OtherOnly").is_none());
assert!(packages.resolve(&imported, "RootOnly").is_none());
assert!(packages.resolve(&root, "RootOnly").is_some());
assert!(packages.resolve(&imported, "OtherOnly").is_some());
}