use dvb_si::{
compatibility::DescriptorType,
descriptor_tag::DescriptorTag,
descriptors::{
ac3::Ac3ServiceType,
announcement_support::AnnouncementType,
cable_delivery_system::FecOuter,
content_identifier::CridType,
data_stream_alignment::AlignmentType,
extension::{
Ac4ChannelMode, C2TuningFrequencyType, ExtensionTag, S2XMode, ShDiversityMode,
T2SisoMiso, UriLinkageType,
},
fta_content_management::ControlRemoteAccess,
iso_639_language::AudioType,
linkage::LinkageType,
s2_satellite_delivery_system::TsGsMode,
satellite_delivery_system::Polarization,
scrambling::ScramblingMode,
service::ServiceType,
subtitling::SubtitlingType,
teletext::TeletextType,
tva_id::TvaRunningStatus,
},
table_id::TableId,
tables::{
ait::ControlCode, int::IntActionType, pmt::StreamType, protection_message::ReferenceType,
rct::LinkType, rnt::CridAuthorityPolicy, unt::UntActionType, RunningStatus,
},
};
use std::collections::{BTreeMap, BTreeSet};
fn parse_entries(toml: &str) -> Vec<(u8, String, String)> {
let mut results = Vec::new();
let mut cur_value: Option<u8> = None;
let mut cur_variant: Option<String> = None;
let mut cur_spec: Option<String> = None;
let flush = |v: &mut Option<u8>,
var: &mut Option<String>,
sp: &mut Option<String>,
out: &mut Vec<(u8, String, String)>| {
if let (Some(value), Some(variant), Some(spec)) = (v.take(), var.take(), sp.take()) {
out.push((value, variant, spec));
}
};
for raw in toml.lines() {
let line = raw.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if line == "[[entry]]" {
flush(
&mut cur_value,
&mut cur_variant,
&mut cur_spec,
&mut results,
);
continue;
}
if let Some(eq) = line.find('=') {
let key = line[..eq].trim();
let val = line[eq + 1..].trim();
match key {
"value" => {
let hex = val.trim_start_matches("0x").trim_start_matches("0X");
cur_value = Some(
u8::from_str_radix(hex, 16)
.unwrap_or_else(|_| panic!("bad hex in TOML: {val:?}")),
);
}
"variant" => {
cur_variant = Some(val.trim_matches('"').replace("\\\"", "\"").to_string());
}
"spec" => {
cur_spec = Some(val.trim_matches('"').replace("\\\"", "\"").to_string());
}
_ => {} }
}
}
flush(
&mut cur_value,
&mut cur_variant,
&mut cur_spec,
&mut results,
);
results
}
#[test]
fn table_id_toml_matches_enum() {
let toml = include_str!("../spec_tables/table_id.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
if let Ok(id) = TableId::try_from(b) {
code_set.insert((b, format!("{id:?}")));
}
}
assert_eq!(
code_set.len(),
29,
"TableId byte sweep produced {} variants, expected 29",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"TableId drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn descriptor_tag_toml_matches_enum() {
let toml = include_str!("../spec_tables/descriptor_tag.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
if let Ok(tag) = DescriptorTag::try_from(b) {
code_set.insert((b, format!("{tag:?}")));
}
}
assert_eq!(
code_set.len(),
82,
"DescriptorTag list has {} entries, expected 82",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"DescriptorTag drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn stream_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/stream_type.toml");
let entries = parse_entries(toml);
let mut toml_set: BTreeSet<(u8, String)> = BTreeSet::new();
let mut toml_spec: BTreeMap<u8, String> = BTreeMap::new();
for (v, var, spec) in &entries {
toml_set.insert((*v, var.clone()));
toml_spec.insert(*v, spec.clone());
}
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let st = StreamType::from_u8(b);
let is_catch_all = matches!(
st,
StreamType::ReservedRange(_) | StreamType::UserPrivate(_)
);
if is_catch_all {
continue;
}
let debug_name = format!("{st:?}");
if let Some(toml_sp) = toml_spec.get(&b) {
assert_eq!(
toml_sp,
st.name(),
"StreamType 0x{b:02X} ({debug_name}): TOML spec {toml_sp:?} != .name() {:?}",
st.name()
);
}
code_set.insert((st.to_u8(), debug_name));
}
assert_eq!(
code_set.len(),
58,
"StreamType sweep produced {} named variants, expected 58",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"StreamType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn service_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/service_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = ServiceType::from_u8(b);
if matches!(v, ServiceType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
28,
"ServiceType sweep produced {} variants, expected 28",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ServiceType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn subtitling_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/subtitling_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = SubtitlingType::from_u8(b);
if matches!(v, SubtitlingType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
19,
"SubtitlingType sweep produced {} variants, expected 19",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"SubtitlingType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn teletext_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/teletext_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = TeletextType::from_u8(b);
if matches!(v, TeletextType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
5,
"TeletextType sweep produced {} variants, expected 5",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"TeletextType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn linkage_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/linkage_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = LinkageType::from_u8(b);
if matches!(
v,
LinkageType::Reserved(_) | LinkageType::ExtendedEventLinkage(_)
) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
15,
"LinkageType sweep produced {} named variants, expected 15",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"LinkageType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn audio_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/audio_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = AudioType::from_u8(b);
if matches!(v, AudioType::UserPrivate(_) | AudioType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
9,
"AudioType sweep produced {} variants, expected 9",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"AudioType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn announcement_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/announcement_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = AnnouncementType::from_u8(b);
if matches!(v, AnnouncementType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
8,
"AnnouncementType sweep produced {} variants, expected 8",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"AnnouncementType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn alignment_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/alignment_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = AlignmentType::from_u8(b);
if matches!(v, AlignmentType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"AlignmentType sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"AlignmentType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn ac3_service_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/ac3_service_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=7 {
let v = Ac3ServiceType::from_u8(b);
if matches!(v, Ac3ServiceType::Unknown(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
8,
"Ac3ServiceType sweep produced {} variants, expected 8",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"Ac3ServiceType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn ac4_channel_mode_toml_matches_enum() {
let toml = include_str!("../spec_tables/ac4_channel_mode.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = Ac4ChannelMode::from_u8(b);
if matches!(v, Ac4ChannelMode::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"Ac4ChannelMode sweep produced {} variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"Ac4ChannelMode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn crid_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/crid_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = CridType::from_u8(b);
if matches!(v, CridType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"CridType sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"CridType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn control_remote_access_toml_matches_enum() {
let toml = include_str!("../spec_tables/control_remote_access.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=3 {
let v = ControlRemoteAccess::from_u8(b);
if matches!(v, ControlRemoteAccess::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"ControlRemoteAccess sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ControlRemoteAccess drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn scrambling_mode_toml_matches_enum() {
let toml = include_str!("../spec_tables/scrambling_mode.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = ScramblingMode::from_u8(b);
if matches!(v, ScramblingMode::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"ScramblingMode sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ScramblingMode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn polarization_toml_matches_enum() {
let toml = include_str!("../spec_tables/polarization.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=3 {
let v = Polarization::from_u8(b);
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"Polarization sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"Polarization drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn fec_outer_toml_matches_enum() {
let toml = include_str!("../spec_tables/fec_outer.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let named: &[(u8, FecOuter)] = &[
(0x00, FecOuter::NotDefined),
(0x01, FecOuter::NoOuterFec),
(0x02, FecOuter::ReedSolomon204_188),
];
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for (wire, v) in named {
code_set.insert((*wire, format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"FecOuter has {} named variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"FecOuter drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn ts_gs_mode_toml_matches_enum() {
let toml = include_str!("../spec_tables/ts_gs_mode.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = TsGsMode::from_u8(b);
if matches!(v, TsGsMode::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"TsGsMode sweep produced {} variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"TsGsMode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn s2x_mode_toml_matches_enum() {
let toml = include_str!("../spec_tables/s2x_mode.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = S2XMode::from_u8(b);
if matches!(v, S2XMode::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"S2XMode sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"S2XMode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn t2_siso_miso_toml_matches_enum() {
let toml = include_str!("../spec_tables/t2_siso_miso.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = T2SisoMiso::from_u8(b);
if matches!(v, T2SisoMiso::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
2,
"T2SisoMiso sweep produced {} variants, expected 2",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"T2SisoMiso drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn sh_diversity_mode_toml_matches_enum() {
let toml = include_str!("../spec_tables/sh_diversity_mode.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = ShDiversityMode::from_u8(b);
if matches!(v, ShDiversityMode::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
5,
"ShDiversityMode sweep produced {} variants, expected 5",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ShDiversityMode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn c2_tuning_frequency_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/c2_tuning_frequency_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = C2TuningFrequencyType::from_u8(b);
if matches!(v, C2TuningFrequencyType::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"C2TuningFrequencyType sweep produced {} variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"C2TuningFrequencyType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn uri_linkage_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/uri_linkage_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = UriLinkageType::from_u8(b);
if matches!(v, UriLinkageType::Other(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"UriLinkageType sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"UriLinkageType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn extension_tag_toml_matches_enum() {
let toml = include_str!("../spec_tables/extension_tag.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
use ExtensionTag::*;
let all_variants: &[ExtensionTag] = &[
ImageIcon,
T2DeliverySystem,
ShDeliverySystem,
SupplementaryAudio,
NetworkChangeNotify,
Message,
TargetRegion,
TargetRegionName,
ServiceRelocated,
C2DeliverySystem,
VideoDepthRange,
T2mi,
UriLinkage,
Ac4,
C2BundleDeliverySystem,
S2XSatelliteDeliverySystem,
AudioPreselection,
TtmlSubtitling,
ServiceProminence,
VvcSubpictures,
S2Xv2SatelliteDeliverySystem,
];
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for v in all_variants {
code_set.insert((*v as u8, format!("{v:?}")));
}
assert_eq!(
code_set.len(),
21,
"ExtensionTag has {} variants, expected 21",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ExtensionTag drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn running_status_toml_matches_enum() {
let toml = include_str!("../spec_tables/running_status.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=7 {
let v = RunningStatus::from_u8(b);
if matches!(v, RunningStatus::Reserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
6,
"RunningStatus sweep produced {} variants, expected 6",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"RunningStatus drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn int_action_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/int_action_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = IntActionType::from_u8(b);
if matches!(v, IntActionType::DvbReserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
2,
"IntActionType sweep produced {} variants, expected 2",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"IntActionType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn unt_action_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/unt_action_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = UntActionType::from_u8(b);
if matches!(
v,
UntActionType::DvbReserved(_) | UntActionType::UserDefined(_)
) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
2,
"UntActionType sweep produced {} variants, expected 2",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"UntActionType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn control_code_toml_matches_enum() {
let toml = include_str!("../spec_tables/control_code.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = ControlCode::from_u8(b);
if matches!(v, ControlCode::Unallocated(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
9,
"ControlCode sweep produced {} variants, expected 9",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ControlCode drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn reference_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/reference_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=15 {
let v = ReferenceType::from_u8(b);
if matches!(v, ReferenceType::Unallocated(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"ReferenceType sweep produced {} variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"ReferenceType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn crid_authority_policy_toml_matches_enum() {
let toml = include_str!("../spec_tables/crid_authority_policy.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=3 {
let v = CridAuthorityPolicy::from_u8(b);
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"CridAuthorityPolicy sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"CridAuthorityPolicy drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn link_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/link_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=15 {
let v = LinkType::from_u8(b);
if matches!(v, LinkType::DvbReserved(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
4,
"LinkType sweep produced {} variants, expected 4",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"LinkType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn descriptor_type_toml_matches_enum() {
let toml = include_str!("../spec_tables/descriptor_type.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = DescriptorType::from_u8(b);
if matches!(
v,
DescriptorType::IsoReserved(_)
| DescriptorType::DvbReserved(_)
| DescriptorType::UserDefined(_)
) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
3,
"DescriptorType sweep produced {} variants, expected 3",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"DescriptorType drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
#[test]
fn tva_running_status_toml_matches_enum() {
let toml = include_str!("../spec_tables/tva_running_status.toml");
let entries = parse_entries(toml);
let toml_set: BTreeSet<(u8, String)> = entries
.iter()
.map(|(v, var, _)| (*v, var.clone()))
.collect();
let mut code_set: BTreeSet<(u8, String)> = BTreeSet::new();
for b in 0u8..=255 {
let v = TvaRunningStatus::from_u8(b);
if matches!(v, TvaRunningStatus::Unallocated(_)) {
continue;
}
code_set.insert((v.to_u8(), format!("{v:?}")));
}
assert_eq!(
code_set.len(),
7,
"TvaRunningStatus sweep produced {} variants, expected 7",
code_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"TvaRunningStatus drift detected!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}
fn parse_biop_tag_entries(toml: &str) -> Vec<(u32, String, String)> {
let mut results = Vec::new();
let mut cur_value: Option<u32> = None;
let mut cur_variant: Option<String> = None;
let mut cur_spec: Option<String> = None;
let flush = |v: &mut Option<u32>,
var: &mut Option<String>,
sp: &mut Option<String>,
out: &mut Vec<(u32, String, String)>| {
if let (Some(value), Some(variant), Some(spec)) = (v.take(), var.take(), sp.take()) {
out.push((value, variant, spec));
}
};
for raw in toml.lines() {
let line = raw.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if line == "[[entry]]" {
flush(
&mut cur_value,
&mut cur_variant,
&mut cur_spec,
&mut results,
);
continue;
}
if let Some(eq) = line.find('=') {
let key = line[..eq].trim();
let val = line[eq + 1..].trim().trim_matches('"');
match key {
"value" => {
let hex = val.trim_start_matches("0x").trim_start_matches("0X");
cur_value = Some(
u32::from_str_radix(hex, 16)
.unwrap_or_else(|_| panic!("bad hex u32 in BIOP tag TOML: {val:?}")),
);
}
"variant" => {
cur_variant = Some(val.to_string());
}
"spec" => {
cur_spec = Some(val.to_string());
}
_ => {}
}
}
}
flush(
&mut cur_value,
&mut cur_variant,
&mut cur_spec,
&mut results,
);
results
}
#[test]
fn biop_tag_toml_matches_consts() {
use dvb_si::carousel::biop::{
TAG_BIOP, TAG_CONN_BINDER, TAG_LITE_OPTIONS, TAG_OBJECT_LOCATION, TAG_SERVICE_LOCATION,
};
use std::collections::BTreeMap;
let toml = include_str!("../spec_tables/biop_tag.toml");
let entries = parse_biop_tag_entries(toml);
let toml_map: BTreeMap<String, u32> = entries
.iter()
.map(|(v, var, _)| (var.clone(), *v))
.collect();
let code: &[(&str, u32)] = &[
("TAG_BIOP", TAG_BIOP),
("TAG_LITE_OPTIONS", TAG_LITE_OPTIONS),
("TAG_OBJECT_LOCATION", TAG_OBJECT_LOCATION),
("TAG_CONN_BINDER", TAG_CONN_BINDER),
("TAG_SERVICE_LOCATION", TAG_SERVICE_LOCATION),
];
assert_eq!(
toml_map.len(),
5,
"biop_tag.toml must have exactly 5 entries, found {}",
toml_map.len()
);
for (name, value) in code {
let toml_val = toml_map
.get(*name)
.unwrap_or_else(|| panic!("BIOP tag {name} missing from biop_tag.toml"));
assert_eq!(
*toml_val, *value,
"BIOP tag {name}: TOML has 0x{toml_val:08X}, code has 0x{value:08X}"
);
}
}
#[test]
fn biop_object_kind_toml_matches_enum() {
use dvb_si::carousel::biop::ObjectKind;
use std::collections::BTreeSet;
let toml = include_str!("../spec_tables/biop_object_kind.toml");
let mut toml_set: BTreeSet<(String, String)> = BTreeSet::new();
for raw in toml.lines() {
let _ = raw; }
let mut cur_value: Option<String> = None;
let mut cur_variant: Option<String> = None;
let mut cur_spec: Option<String> = None;
for raw in toml.lines() {
let line = raw.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if line == "[[entry]]" {
if let (Some(v), Some(var), Some(_)) =
(cur_value.take(), cur_variant.take(), cur_spec.take())
{
toml_set.insert((v, var));
}
continue;
}
if let Some(eq) = line.find('=') {
let key = line[..eq].trim();
let val = line[eq + 1..].trim().trim_matches('"').to_string();
match key {
"value" => cur_value = Some(val),
"variant" => cur_variant = Some(val),
"spec" => cur_spec = Some(val),
_ => {}
}
}
}
if let (Some(v), Some(var), Some(_)) = (cur_value, cur_variant, cur_spec) {
toml_set.insert((v, var));
}
let named: &[(&str, ObjectKind)] = &[
("dir", ObjectKind::Directory),
("fil", ObjectKind::File),
("str", ObjectKind::Stream),
("srg", ObjectKind::ServiceGateway),
("ste", ObjectKind::StreamEvent),
];
let mut code_set: BTreeSet<(String, String)> = BTreeSet::new();
for (alias, kind) in named {
code_set.insert((alias.to_string(), format!("{kind:?}")));
}
assert_eq!(
toml_set.len(),
5,
"biop_object_kind.toml must have exactly 5 entries, found {}",
toml_set.len()
);
let only_in_toml: BTreeSet<_> = toml_set.difference(&code_set).collect();
let only_in_code: BTreeSet<_> = code_set.difference(&toml_set).collect();
assert!(
only_in_toml.is_empty() && only_in_code.is_empty(),
"BIOP ObjectKind drift!\n only in TOML: {only_in_toml:?}\n only in code: {only_in_code:?}"
);
}