diff --git a/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs b/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs index b96571ae..5a679f5d 100644 --- a/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs +++ b/SabreTools.Metadata.Filter.Test/FilterObjectTests.cs @@ -472,5 +472,223 @@ namespace SabreTools.Metadata.Filter.Test } #endregion + + #region Adjuster + + [Theory] + [InlineData("adjuster.default", "yes")] + [InlineData("adjuster.name", "name")] + public void Matches_Adjsuter(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Adjuster obj = new Adjuster + { + Default = true, + Name = "name", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region Analog + + [Theory] + [InlineData("analog.mask", "mask")] + public void Matches_Analog(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Analog obj = new Analog + { + Mask = "mask", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region Archive + + [Theory] + [InlineData("archive.additional", "additional")] + [InlineData("archive.adult", "1")] + [InlineData("archive.alt", "1")] + [InlineData("archive.bios", "1")] + [InlineData("archive.categories", "categories")] + [InlineData("archive.clone", "clone")] + [InlineData("archive.clonetag", "clone")] + [InlineData("archive.complete", "1")] + [InlineData("archive.dat", "1")] + [InlineData("archive.datternote", "datternote")] + [InlineData("archive.description", "description")] + [InlineData("archive.devstatus", "devstatus")] + [InlineData("archive.gameid1", "gameid1")] + [InlineData("archive.gameid2", "gameid2")] + [InlineData("archive.langchecked", "langchecked")] + [InlineData("archive.languages", "languages")] + [InlineData("archive.licensed", "1")] + [InlineData("archive.listed", "1")] + [InlineData("archive.mergeof", "mergeof")] + [InlineData("archive.mergename", "mergename")] + [InlineData("archive.name", "name")] + [InlineData("archive.namealt", "namealt")] + [InlineData("archive.number", "number")] + [InlineData("archive.physical", "1")] + [InlineData("archive.pirate", "1")] + [InlineData("archive.private", "1")] + [InlineData("archive.region", "region")] + [InlineData("archive.regparent", "regparent")] + [InlineData("archive.showlang", "1")] + [InlineData("archive.special1", "special1")] + [InlineData("archive.special2", "special2")] + [InlineData("archive.stickynote", "stickynote")] + [InlineData("archive.version1", "version1")] + [InlineData("archive.version2", "version2")] + public void Matches_Archive(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Archive obj = new Archive + { + Additional = "additional", + Adult = true, + Alt = true, + Bios = true, + Categories = "categories", + CloneTag = "clone", + Complete = true, + Dat = true, + DatterNote = "datternote", + Description = "description", + DevStatus = "devstatus", + GameId1 = "gameid1", + GameId2 = "gameid2", + LangChecked = "langchecked", + Languages = "languages", + Licensed = true, + Listed = true, + MergeOf = "mergeof", + MergeName = "mergename", + Name = "name", + NameAlt = "namealt", + Number = "number", + Physical = true, + Pirate = true, + Private = true, + Region = "region", + RegParent = "regparent", + ShowLang = true, + Special1 = "special1", + Special2 = "special2", + StickyNote = "stickynote", + Version1 = "version1", + Version2 = "version2", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region BiosSet + + [Theory] + [InlineData("biosset.default", "yes")] + [InlineData("biosset.description", "description")] + [InlineData("biosset.name", "name")] + public void Matches_BiosSet(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + BiosSet obj = new BiosSet + { + Default = true, + Description = "description", + Name = "name", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region Chip + + [Theory] + [InlineData("chip.type", "audio")] + [InlineData("chip.chiptype", "audio")] + [InlineData("chip.clock", "12345")] + [InlineData("chip.flags", "flags")] + [InlineData("chip.name", "name")] + [InlineData("chip.soundonly", "yes")] + [InlineData("chip.tag", "tag")] + public void Matches_Chip(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Chip obj = new Chip + { + ChipType = ChipType.Audio, + Clock = 12345, + Flags = "flags", + Name = "name", + SoundOnly = true, + Tag = "tag", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region Condition + + [Theory] + [InlineData("condition.mask", "mask")] + [InlineData("condition.relation", "ne")] + [InlineData("condition.tag", "tag")] + [InlineData("condition.value", "value")] + public void Matches_Condition(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Condition obj = new Condition + { + Mask = "mask", + Relation = Relation.NotEqual, + Tag = "tag", + Value = "value", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion + + #region Configuration + + [Theory] + [InlineData("configuration.mask", "mask")] + [InlineData("configuration.name", "name")] + [InlineData("configuration.tag", "tag")] + public void Matches_Configuration(string itemField, string value) + { + var filter = new FilterObject(itemField, value, Operation.Equals); + Configuration obj = new Configuration + { + Mask = "mask", + Name = "name", + Tag = "tag", + }; + + bool actual = filter.Matches(obj); + Assert.True(actual); + } + + #endregion } } diff --git a/SabreTools.Metadata.Filter/FilterKey.cs b/SabreTools.Metadata.Filter/FilterKey.cs index 7666d353..64442a27 100644 --- a/SabreTools.Metadata.Filter/FilterKey.cs +++ b/SabreTools.Metadata.Filter/FilterKey.cs @@ -10,6 +10,8 @@ namespace SabreTools.Metadata.Filter /// public class FilterKey { + #region Properties + /// /// Item name associated with the filter /// @@ -20,6 +22,10 @@ namespace SabreTools.Metadata.Filter /// public readonly string FieldName; + #endregion + + #region Constants + /// /// Cached item type names for filter selection /// @@ -29,6 +35,111 @@ namespace SabreTools.Metadata.Filter private static readonly string[] _datItemTypeNames = Enum.GetNames(typeof(ItemType)); #endif + /// + /// Known keys for Adjuster + /// + private static readonly string[] _adjusterKeys = + [ + "default", + "name" + ]; + + /// + /// Known keys for Analog + /// + private static readonly string[] _analogKeys = + [ + "mask" + ]; + + /// + /// Known keys for Archive + /// + private static readonly string[] _archiveKeys = + [ + "additional", + "adult", + "alt", + "bios", + "categories", + "clone", + "clonetag", + "complete", + "dat", + "datternote", + "description", + "devstatus", + "gameid1", + "gameid2", + "langchecked", + "languages", + "licensed", + "listed", + "mergeof", + "mergename", + "name", + "namealt", + "number", + "physical", + "pirate", + "private", + "region", + "regparent", + "showlang", + "special1", + "special2", + "stickynote", + "version1", + "version2", + ]; + + /// + /// Known keys for BiosSet + /// + private static readonly string[] _biossetKeys = + [ + "default", + "description", + "name", + ]; + + /// + /// Known keys for Chip + /// + private static readonly string[] _chipKeys = + [ + "chiptype", + "clock", + "flags", + "name", + "soundonly", + "tag", + "type", + ]; + + /// + /// Known keys for Condition + /// + private static readonly string[] _conditionKeys = + [ + "mask", + "relation", + "tag", + "value", + ]; + + /// + /// Known keys for Configuration + /// + private static readonly string[] _configurationKeys = + [ + "mask", + "name", + "tag", + ]; + + #endregion + /// /// Validating combined key constructor /// @@ -202,13 +313,34 @@ namespace SabreTools.Metadata.Filter /// private static string? GetMatchingField(string itemName, string fieldName) { - // Get the correct item type - var itemType = GetDatItemType(itemName.ToLowerInvariant()); - if (itemType is null) - return null; - // Get the set of properties - var properties = GetProperties(itemType); + string[]? properties = itemName.ToLowerInvariant() switch + { + "adjuster" => _adjusterKeys, + "analog" => _analogKeys, + "archive" => _archiveKeys, + "biosset" => _biossetKeys, + "chip" => _chipKeys, + "condition" => _conditionKeys, + "configuration" => _configurationKeys, + _ => null, + }; + + // TODO: Remove this fallback path + if (properties is null) + { + // Get the correct item type + var itemType = GetDatItemType(itemName.ToLowerInvariant()); + if (itemType is null) + return null; + + properties = GetProperties(itemType); + + // Special cases for mismatched names + if (properties is not null && itemType == typeof(Rom)) + properties = [.. properties, "crc"]; + } + if (properties is null) return null; diff --git a/SabreTools.Metadata.Filter/FilterObject.cs b/SabreTools.Metadata.Filter/FilterObject.cs index cee98f14..def15fcf 100644 --- a/SabreTools.Metadata.Filter/FilterObject.cs +++ b/SabreTools.Metadata.Filter/FilterObject.cs @@ -455,6 +455,7 @@ namespace SabreTools.Metadata.Filter checkValue = obj.Categories; return true; case "clone": + case "clonetag": checkValue = obj.CloneTag; return true; case "complete": @@ -577,6 +578,7 @@ namespace SabreTools.Metadata.Filter { switch (fieldName) { + case "chiptype": case "type": checkValue = obj.ChipType?.AsStringValue(); return true;