From aa9ecdfa83bf0493985ef8223c1bf8c9340bf15f Mon Sep 17 00:00:00 2001 From: juliancoffee Date: Sat, 17 Jul 2021 00:45:53 +0300 Subject: [PATCH] Add test for duplicates in `EntityConfig::meta` + make tests cleaner --- common/src/generation.rs | 187 ++++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 62 deletions(-) diff --git a/common/src/generation.rs b/common/src/generation.rs index f587a10f28..bfc819cc1b 100644 --- a/common/src/generation.rs +++ b/common/src/generation.rs @@ -383,6 +383,115 @@ pub fn get_npc_name< mod tests { use super::*; use crate::{comp::inventory::slot::EquipSlot, SkillSetBuilder}; + use hashbrown::HashMap; + + #[derive(Debug, Eq, Hash, PartialEq)] + enum MetaId { + LoadoutAsset, + SkillSetAsset, + } + + impl Meta { + fn id(&self) -> MetaId { + match self { + Meta::LoadoutAsset(_) => MetaId::LoadoutAsset, + Meta::SkillSetAsset(_) => MetaId::SkillSetAsset, + } + } + } + + fn validate_hands(hands: Hands, _config_asset: &str) { + match hands { + Hands::TwoHanded(main_tool) => { + main_tool.validate(EquipSlot::ActiveMainhand); + }, + Hands::Paired(tool) => { + tool.validate(EquipSlot::ActiveMainhand); + tool.validate(EquipSlot::ActiveOffhand); + }, + Hands::Mix { mainhand, offhand } => { + mainhand.validate(EquipSlot::ActiveMainhand); + offhand.validate(EquipSlot::ActiveOffhand); + }, + Hands::Uninit => {}, + } + } + + fn validate_body_and_name(body: BodyBuilder, name: NameKind, config_asset: &str) { + match body { + BodyBuilder::RandomWith(string) => { + let npc::NpcBody(_body_kind, mut body_creator) = + string.parse::().unwrap_or_else(|err| { + panic!( + "failed to parse body {:?} in {}. Err: {:?}", + &string, config_asset, err + ) + }); + let _ = body_creator(); + }, + BodyBuilder::Uninit => { + if let NameKind::Automatic = name { + // there is a big chance to call automatic name + // when body is yet undefined + // + // use .with_automatic_name() in code explicitly + panic!("Used Automatic name with Uninit body in {}", config_asset); + } + }, + BodyBuilder::Exact { .. } => {}, + } + } + + fn validate_loot(loot: LootKind, config_asset: &str) { + match loot { + LootKind::Item(asset) => { + if let Err(e) = Item::new_from_asset(&asset) { + panic!( + "Unable to parse loot item ({}) in {}. Err: {:?}", + asset, config_asset, e + ); + } + }, + LootKind::LootTable(asset) => { + // we need to just load it check if it exists, + // because all loot tables are tested in Lottery module + if let Err(e) = Lottery::>::load(&asset) { + panic!( + "Unable to parse loot table ({}) in {}. Err: {:?}", + asset, config_asset, e + ); + } + }, + LootKind::Uninit => {}, + } + } + + fn validate_meta(meta: Vec, config_asset: &str) { + let mut meta_counter = HashMap::new(); + for field in meta { + meta_counter + .entry(field.id()) + .and_modify(|c| *c += 1) + .or_insert(1); + match field { + Meta::LoadoutAsset(asset) => { + let rng = &mut rand::thread_rng(); + let builder = LoadoutBuilder::default(); + // we need to just load it check if it exists, + // because all loadouts are tested in LoadoutBuilder module + std::mem::drop(builder.with_asset_expect(&asset, rng)); + }, + Meta::SkillSetAsset(asset) => { + std::mem::drop(SkillSetBuilder::from_asset_expect(&asset)); + }, + } + } + for (meta_id, counter) in meta_counter { + if counter > 1 { + panic!("Duplicate {:?} in {}", meta_id, config_asset); + } + } + } #[test] fn test_all_entity_assets() { @@ -390,77 +499,31 @@ mod tests { let entity_configs = assets::load_dir::("common.entity", true) .expect("Failed to access entity directory"); for config_asset in entity_configs.ids() { + // print asset name so we don't need to find errors everywhere + // it'll be ignored by default so you'll see it only in case of errors + // + // TODO: + // 1) Add try_validate() for loadout_builder::ItemSpec which will return + // Result and we will happily panic in validate_hands() with name of + // config_asset. + // 2) Add try_from_asset() for LoadoutBuilder and + // SkillSet builder which will return Result and we will happily + // panic in validate_meta() with the name of config_asset println!("{}:", config_asset); + let EntityConfig { hands, - loot, body, name, + loot, meta, alignment: _alignment, // can't fail if serialized, it's a boring enum } = EntityConfig::from_asset_expect(config_asset); - match hands { - Hands::TwoHanded(main_tool) => { - main_tool.validate(EquipSlot::ActiveMainhand); - }, - Hands::Paired(tool) => { - tool.validate(EquipSlot::ActiveMainhand); - tool.validate(EquipSlot::ActiveOffhand); - }, - Hands::Mix { mainhand, offhand } => { - mainhand.validate(EquipSlot::ActiveMainhand); - offhand.validate(EquipSlot::ActiveOffhand); - }, - Hands::Uninit => {}, - } - - match body { - BodyBuilder::RandomWith(string) => { - let npc::NpcBody(_body_kind, mut body_creator) = - string.parse::().unwrap_or_else(|err| { - panic!("failed to parse body {:?}. Err: {:?}", &string, err) - }); - let _ = body_creator(); - }, - BodyBuilder::Uninit => { - if let NameKind::Automatic = name { - // there is a big chance to call automatic name - // when body is yet undefined - // - // use .with_automatic_name() in code explicitly - panic!("Used Automatic name with Uninit body in {}", config_asset); - } - }, - BodyBuilder::Exact { .. } => {}, - } - - match loot { - LootKind::Item(asset) => { - std::mem::drop(Item::new_from_asset_expect(&asset)); - }, - LootKind::LootTable(asset) => { - // we need to just load it check if it exists, - // because all loot tables are tested in Lottery module - let _ = Lottery::>::load_expect(&asset); - }, - LootKind::Uninit => {}, - } - - for field in meta { - match field { - Meta::LoadoutAsset(asset) => { - let rng = &mut rand::thread_rng(); - let builder = LoadoutBuilder::default(); - // we need to just load it check if it exists, - // because all loadouts are tested in LoadoutBuilder module - std::mem::drop(builder.with_asset_expect(&asset, rng)); - }, - Meta::SkillSetAsset(asset) => { - std::mem::drop(SkillSetBuilder::from_asset_expect(&asset)); - }, - } - } + validate_hands(hands, config_asset); + validate_body_and_name(body, name, config_asset); + validate_loot(loot, config_asset); + validate_meta(meta, config_asset); } } }