Checkpoint reflection replacement

This commit is contained in:
Matt Nadareski
2026-04-06 10:18:00 -04:00
parent e2b2f4d8a5
commit c0872cb97b
3 changed files with 358 additions and 6 deletions

View File

@@ -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
}
}

View File

@@ -10,6 +10,8 @@ namespace SabreTools.Metadata.Filter
/// </summary>
public class FilterKey
{
#region Properties
/// <summary>
/// Item name associated with the filter
/// </summary>
@@ -20,6 +22,10 @@ namespace SabreTools.Metadata.Filter
/// </summary>
public readonly string FieldName;
#endregion
#region Constants
/// <summary>
/// Cached item type names for filter selection
/// </summary>
@@ -29,6 +35,111 @@ namespace SabreTools.Metadata.Filter
private static readonly string[] _datItemTypeNames = Enum.GetNames(typeof(ItemType));
#endif
/// <summary>
/// Known keys for Adjuster
/// </summary>
private static readonly string[] _adjusterKeys =
[
"default",
"name"
];
/// <summary>
/// Known keys for Analog
/// </summary>
private static readonly string[] _analogKeys =
[
"mask"
];
/// <summary>
/// Known keys for Archive
/// </summary>
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",
];
/// <summary>
/// Known keys for BiosSet
/// </summary>
private static readonly string[] _biossetKeys =
[
"default",
"description",
"name",
];
/// <summary>
/// Known keys for Chip
/// </summary>
private static readonly string[] _chipKeys =
[
"chiptype",
"clock",
"flags",
"name",
"soundonly",
"tag",
"type",
];
/// <summary>
/// Known keys for Condition
/// </summary>
private static readonly string[] _conditionKeys =
[
"mask",
"relation",
"tag",
"value",
];
/// <summary>
/// Known keys for Configuration
/// </summary>
private static readonly string[] _configurationKeys =
[
"mask",
"name",
"tag",
];
#endregion
/// <summary>
/// Validating combined key constructor
/// </summary>
@@ -202,13 +313,34 @@ namespace SabreTools.Metadata.Filter
/// </summary>
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;

View File

@@ -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;