#[cfg(feature = "write")] use bitbuffer::BitWriteStream; use bitbuffer::{BitReadBuffer, BitReadStream, LittleEndian}; use std::fs; use test_case::test_case; #[cfg(feature = "write")] use tf_demo_parser::demo::message::stringtable::StringTableMeta; #[cfg(feature = "write")] use tf_demo_parser::demo::message::stringtable::{ parse_string_table_update, write_string_table_update, }; #[cfg(feature = "write")] use tf_demo_parser::demo::packet::stringtable::FixedUserDataSize; use tf_demo_parser::demo::packet::stringtable::StringTable; #[cfg(feature = "write")] #[test_case("test_data/string_tables/decalprecache.bin", "test_data/string_tables/decalprecache_meta.json"; "decalprecache")] #[test_case("test_data/string_tables/downloadables.bin", "test_data/string_tables/downloadables_meta.json"; "downloadables")] #[test_case("test_data/string_tables/DynamicModels.bin", "test_data/string_tables/DynamicModels_meta.json"; "DynamicModels")] #[test_case("test_data/string_tables/EffectDispatch.bin", "test_data/string_tables/EffectDispatch_meta.json"; "EffectDispatch")] #[test_case("test_data/string_tables/GameRulesCreation.bin", "test_data/string_tables/GameRulesCreation_meta.json"; "GameRulesCreation")] #[test_case("test_data/string_tables/genericprecache.bin", "test_data/string_tables/genericprecache_meta.json"; "genericprecache")] #[test_case("test_data/string_tables/InfoPanel.bin", "test_data/string_tables/InfoPanel_meta.json"; "InfoPanel")] // #[test_case("test_data/string_tables/instancebaseline.bin", "test_data/string_tables/instancebaseline_meta.json"; "instancebaseline")] #[test_case("test_data/string_tables/lightstyles.bin", "test_data/string_tables/lightstyles_meta.json"; "lightstyles")] #[test_case("test_data/string_tables/Materials.bin", "test_data/string_tables/Materials_meta.json"; "Materials")] #[test_case("test_data/string_tables/modelprecache.bin", "test_data/string_tables/modelprecache_meta.json"; "modelprecache")] #[test_case("test_data/string_tables/ParticleEffectNames.bin", "test_data/string_tables/ParticleEffectNames_meta.json"; "ParticleEffectNames")] // #[test_case("test_data/string_tables/Scenes.bin", "test_data/string_tables/Scenes_meta.json"; "Scenes")] #[test_case("test_data/string_tables/server_query_info.bin", "test_data/string_tables/server_query_info_meta.json"; "server_query_info")] #[test_case("test_data/string_tables/ServerMapCycle.bin", "test_data/string_tables/ServerMapCycle_meta.json"; "ServerMapCycle")] #[test_case("test_data/string_tables/ServerMapCycleMvM.bin", "test_data/string_tables/ServerMapCycleMvM_meta.json"; "ServerMapCycleMvM")] #[test_case("test_data/string_tables/ServerPopFiles.bin", "test_data/string_tables/ServerPopFiles_meta.json"; "ServerPopFiles")] #[test_case("test_data/string_tables/soundprecache.bin", "test_data/string_tables/soundprecache_meta.json"; "soundprecache")] #[test_case("test_data/string_tables/userinfo.bin", "test_data/string_tables/userinfo_meta.json"; "userinfo")] #[test_case("test_data/string_tables/VguiScreen.bin", "test_data/string_tables/VguiScreen_meta.json"; "VguiScreen")] fn string_table_reencode(input_file: &str, meta_file: &str) { let data = fs::read(input_file).unwrap(); let meta: serde_json::Value = serde_json::from_str(&fs::read_to_string(meta_file).unwrap()).unwrap(); let count = meta["count"].as_u64().unwrap() as u16; let max_entries = meta["max_entries"].as_u64().unwrap(); let fixed_userdata_size = meta["fixed_userdata_size"] .as_object() .map(|size| FixedUserDataSize { size: size["size"].as_u64().unwrap() as u16, bits: size["bits"].as_u64().unwrap() as u8, }); let table_meta = StringTableMeta { max_entries: max_entries as u16, fixed_userdata_size, }; let mut stream = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian)); let parsed = parse_string_table_update(&mut stream, &table_meta, count).unwrap(); let mut out = Vec::with_capacity(data.len()); let written_bits = { let mut write = BitWriteStream::new(&mut out, LittleEndian); write_string_table_update(&parsed, &mut write, &table_meta).unwrap(); write.bit_len() }; let mut re_stream = BitReadStream::new(BitReadBuffer::new(&out, LittleEndian)); let re_parsed = parse_string_table_update(&mut re_stream, &table_meta, count).unwrap(); assert_eq!(written_bits, stream.pos()); assert_eq!(parsed, re_parsed); assert_eq!(data.len(), out.len()); if data.len() > 16 { pretty_assertions::assert_eq!(&data[0..data.len() - 8], &out[0..out.len() - 8]); pretty_assertions::assert_eq!(&data[data.len() - 8..], &out[out.len() - 8..]); } else { pretty_assertions::assert_eq!(data, out); } } #[test_case("test_data/string_tables/ServerMapCycleLarge.bin", "test_data/string_tables/ServerMapCycleLarge_meta.json"; "ServerMapCycleLarge")] fn large_string_table_parsing(input_file: &str, meta_file: &str) { let data = fs::read(input_file).unwrap(); let meta: serde_json::Value = serde_json::from_str(&fs::read_to_string(meta_file).unwrap()).unwrap(); let expected_table_name = meta["name"].as_str().unwrap(); let expected_marker = meta["marker"].as_u64().unwrap() as u32; let mut stream = BitReadStream::new(BitReadBuffer::new(&data, LittleEndian)); // Parse the table data let table: StringTable<'_> = stream.read().unwrap(); pretty_assertions::assert_eq!(expected_table_name, table.name); // Ensure the stream position is correct (previously the byte_len.saturated_mul(8) in ExtraData could overflow and would leave the BitReadStream in a bad state). let marker: u32 = stream.read().unwrap(); pretty_assertions::assert_eq!(expected_marker, marker); }