Remove old Filter and variants

This commit is contained in:
Matt Nadareski
2024-03-05 22:51:19 -05:00
parent 3c0d190dc3
commit 03c6fb641c
6 changed files with 11 additions and 3131 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,455 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.DatFiles;
using SabreTools.DatItems;
using SabreTools.Logging;
namespace SabreTools.Filtering
{
/// <summary>
/// Represents the filtering operations that need to be performed on a set of items, usually a DAT
/// </summary>
public class Filter
{
#region Fields
/// <summary>
/// Filter for DatItem fields
/// </summary>
public DatItemFilter? DatItemFilter { get; set; }
/// <summary>
/// Filter for Machine fields
/// </summary>
public MachineFilter? MachineFilter { get; set; }
#endregion
#region Logging
/// <summary>
/// Logging object
/// </summary>
protected Logger logger;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public Filter()
{
logger = new Logger(this);
}
#endregion
#region Population
/// <summary>
/// Populate the filters objects using a set of key:value filters
/// </summary>
/// <param name="filters">List of key:value where ~key/!key is negated</param>
public void PopulateFiltersFromList(List<string>? filters)
{
// Instantiate the filters, if necessary
MachineFilter ??= new MachineFilter();
DatItemFilter ??= new DatItemFilter();
// If the list is null or empty, just return
if (filters == null || filters.Count == 0)
return;
InternalStopwatch watch = new("Populating filters from list");
foreach (string filterPair in filters)
{
(string? field, string? value, bool negate) = ProcessFilterPair(filterPair);
// If we don't even have a possible filter pair
if (field == null && value == null)
continue;
// Machine fields
MachineField machineField = field.AsMachineField();
if (machineField != MachineField.NULL)
{
MachineFilter.SetFilter(machineField, value, negate);
MachineFilter.HasFilters = true;
continue;
}
// DatItem fields
DatItemField datItemField = field.AsDatItemField();
if (datItemField != DatItemField.NULL)
{
DatItemFilter.SetFilter(datItemField, value, negate);
DatItemFilter.HasFilters = true;
continue;
}
// If we didn't match anything, log an error
logger.Warning($"The value {field} did not match any filterable field names. Please check the wiki for more details on supported field names.");
}
watch.Stop();
}
/// <summary>
/// Split the parts of a filter statement
/// </summary>
/// <param name="filter">key:value where ~key/!key is negated</param>
protected (string? field, string? value, bool negate) ProcessFilterPair(string filter)
{
// If we don't even have a possible filter pair
if (!filter.Contains(':'))
{
logger.Warning($"'{filter}` is not a valid filter string. Valid filter strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details.");
return (null, null, false);
}
string filterTrimmed = filter.Trim('"', ' ', '\t');
bool negate = filterTrimmed.StartsWith("!")
|| filterTrimmed.StartsWith("~")
|| filterTrimmed.StartsWith("not-");
filterTrimmed = filterTrimmed.TrimStart('!', '~');
filterTrimmed = filterTrimmed.StartsWith("not-") ? filterTrimmed.Substring(4) : filterTrimmed;
string filterFieldString = filterTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
string filterValue = filterTrimmed.Substring(filterFieldString.Length + 1).Trim('"', ' ', '\t');
return (filterFieldString, filterValue, negate);
}
/// <summary>
/// Set a bool? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
protected static void SetBooleanFilter(FilterItem<bool?> filterItem, string? value, bool negate)
{
if (negate || (value?.Equals("false", StringComparison.OrdinalIgnoreCase) ?? false))
filterItem.Neutral = false;
else
filterItem.Neutral = true;
}
/// <summary>
/// Set a long? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
protected static void SetDoubleFilter(FilterItem<double?> filterItem, string? value, bool negate)
{
bool? operation = null;
if (value?.StartsWith(">") == true)
operation = true;
else if (value?.StartsWith("<") == true)
operation = false;
else if (value?.StartsWith("=") == true)
operation = null;
string? valueString = value?.TrimStart('>', '<', '=');
if (!Double.TryParse(valueString, out double valueDouble))
return;
// Equal
if (operation == null && !negate)
{
filterItem.Neutral = valueDouble;
}
// Not Equal
else if (operation == null && negate)
{
filterItem.Negative = valueDouble - 1;
filterItem.Positive = valueDouble + 1;
}
// Greater Than or Equal
else if (operation == true && !negate)
{
filterItem.Positive = valueDouble;
}
// Strictly Less Than
else if (operation == true && negate)
{
filterItem.Negative = valueDouble - 1;
}
// Less Than or Equal
else if (operation == false && !negate)
{
filterItem.Negative = valueDouble;
}
// Strictly Greater Than
else if (operation == false && negate)
{
filterItem.Positive = valueDouble + 1;
}
}
/// <summary>
/// Set a long? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
protected static void SetLongFilter(FilterItem<long?> filterItem, string? value, bool negate)
{
bool? operation = null;
if (value?.StartsWith(">") == true)
operation = true;
else if (value?.StartsWith("<") == true)
operation = false;
else if (value?.StartsWith("=") == true)
operation = null;
string? valueString = value?.TrimStart('>', '<', '=');
long? valueLong = NumberHelper.ConvertToInt64(valueString);
if (valueLong == null)
return;
// Equal
if (operation == null && !negate)
{
filterItem.Neutral = valueLong;
}
// Not Equal
else if (operation == null && negate)
{
filterItem.Negative = valueLong - 1;
filterItem.Positive = valueLong + 1;
}
// Greater Than or Equal
else if (operation == true && !negate)
{
filterItem.Positive = valueLong;
}
// Strictly Less Than
else if (operation == true && negate)
{
filterItem.Negative = valueLong - 1;
}
// Less Than or Equal
else if (operation == false && !negate)
{
filterItem.Negative = valueLong;
}
// Strictly Greater Than
else if (operation == false && negate)
{
filterItem.Positive = valueLong + 1;
}
}
/// <summary>
/// Set a string filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
protected static void SetStringFilter(FilterItem<string> filterItem, string? value, bool negate)
{
if (negate)
filterItem.NegativeSet.Add(value);
else
filterItem.PositiveSet.Add(value);
}
#endregion
#region Running
/// <summary>
/// Apply a set of Filters on the DatFile
/// </summary>
/// <param name="datFile">Current DatFile object to run operations on</param>
/// <param name="perMachine">True if entire machines are considered, false otherwise (default)</param>
/// <param name="throwOnError">True if the error that is thrown should be thrown back to the caller, false otherwise</param>
/// <returns>True if the DatFile was filtered, false on error</returns>
public bool ApplyFilters(DatFile datFile, bool perMachine = false, bool throwOnError = false)
{
// If we have null filters, return false
if (MachineFilter == null || DatItemFilter == null)
return false;
// If no filters were set, return true
if (!MachineFilter.HasFilters && !DatItemFilter.HasFilters)
return true;
InternalStopwatch watch = new("Applying filters to DAT");
// If we're filtering per machine, bucket by machine first
if (perMachine)
datFile.Items.BucketBy(ItemKey.Machine, DedupeType.None);
try
{
// Loop over every key in the dictionary
List<string> keys = [.. datFile.Items.Keys];
foreach (string key in keys)
{
// For every item in the current key
bool machinePass = true;
var items = datFile.Items[key];
if (items == null)
continue;
foreach (DatItem item in items)
{
// If we have a null item, we can't pass it
if (item == null)
continue;
// If the item is already filtered out, we skip
if (item.Remove)
continue;
// If the rom doesn't pass the filter, mark for removal
if (!PassesAllFilters(item))
{
item.Remove = true;
// If we're in machine mode, set and break
if (perMachine)
{
machinePass = false;
break;
}
}
}
// If we didn't pass and we're in machine mode, set all items as remove
if (perMachine && !machinePass)
{
foreach (DatItem item in items)
{
item.Remove = true;
}
}
// Assign back for caution
datFile.Items[key] = items;
}
}
catch (Exception ex) when (!throwOnError)
{
logger.Error(ex);
return false;
}
finally
{
watch.Stop();
}
return true;
}
/// <summary>
/// Check to see if a DatItem passes the filters
/// </summary>
/// <param name="datItem">DatItem to check</param>
/// <returns>True if the item passed the filter, false otherwise</returns>
internal bool PassesAllFilters(DatItem datItem)
{
// Null item means it will never pass
if (datItem == null)
return false;
// Filter on Machine fields
if (MachineFilter == null || (MachineFilter.HasFilters && !MachineFilter.PassesFilters(datItem.Machine)))
return false;
// If we have no DatItemFilters set, just return true
if (DatItemFilter == null || !DatItemFilter.HasFilters)
return true;
// Filter on DatItem fields
return DatItemFilter.PassesFilters(datItem);
}
/// <summary>
/// Determines if a value passes a bool? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
protected static bool PassBoolFilter(FilterItem<bool?> filterItem, bool? value)
{
if (filterItem.MatchesNeutral(null, value) == false)
return false;
return true;
}
/// <summary>
/// Determines if a value passes a double? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
protected static bool PassDoubleFilter(FilterItem<double?> filterItem, double? value)
{
if (filterItem.MatchesNeutral(null, value) == false)
return false;
else if (filterItem.MatchesPositive(null, value) == false)
return false;
else if (filterItem.MatchesNegative(null, value) == false)
return false;
return true;
}
/// <summary>
/// Determines if a value passes a long? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
protected static bool PassLongFilter(FilterItem<long?> filterItem, long? value)
{
if (filterItem.MatchesNeutral(null, value) == false)
return false;
else if (filterItem.MatchesPositive(null, value) == false)
return false;
else if (filterItem.MatchesNegative(null, value) == false)
return false;
return true;
}
/// <summary>
/// Determines if a value passes a string filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
protected static bool PassStringFilter(FilterItem<string> filterItem, string? value)
{
if (filterItem.MatchesPositiveSet(value) == false)
return false;
if (filterItem.MatchesNegativeSet(value) == true)
return false;
return true;
}
#endregion
}
}

View File

@@ -1,459 +0,0 @@
using System.Collections.Generic;
using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.DatItems;
using SabreTools.Logging;
namespace SabreTools.Filtering
{
/// <summary>
/// Represents the filtering operations that need to be performed on a set of items, usually a DAT
/// </summary>
public class MachineFilter : Filter
{
#region Fields
#region Filters
public FilterItem<string> Board { get; private set; } = new FilterItem<string>();
public FilterItem<string> Buttons { get; private set; } = new FilterItem<string>();
public FilterItem<string> Category { get; private set; } = new FilterItem<string>();
public FilterItem<string> CloneOf { get; private set; } = new FilterItem<string>();
public FilterItem<string> CloneOfID { get; private set; } = new FilterItem<string>();
public FilterItem<string> Comment { get; private set; } = new FilterItem<string>();
public FilterItem<string> Control { get; private set; } = new FilterItem<string>();
public FilterItem<string> Country { get; private set; } = new FilterItem<string>();
public FilterItem<bool?> CRC { get; private set; } = new FilterItem<bool?>() { Neutral = null };
public FilterItem<string> Description { get; private set; } = new FilterItem<string>();
public FilterItem<string> Developer { get; private set; } = new FilterItem<string>();
public FilterItem<string> DisplayCount { get; private set; } = new FilterItem<string>();
public FilterItem<string> DisplayType { get; private set; } = new FilterItem<string>();
public FilterItem<string> Enabled { get; private set; } = new FilterItem<string>();
public FilterItem<string> GenMSXID { get; private set; } = new FilterItem<string>();
public FilterItem<string> Genre { get; private set; } = new FilterItem<string>();
public FilterItem<string> History { get; private set; } = new FilterItem<string>();
public FilterItem<string> ID { get; private set; } = new FilterItem<string>();
public FilterItem<string> Manufacturer { get; private set; } = new FilterItem<string>();
public FilterItem<string> Name { get; private set; } = new FilterItem<string>();
public FilterItem<string> Players { get; private set; } = new FilterItem<string>();
public FilterItem<string> Publisher { get; private set; } = new FilterItem<string>();
public FilterItem<string> Ratings { get; private set; } = new FilterItem<string>();
public FilterItem<string> RebuildTo { get; private set; } = new FilterItem<string>();
public FilterItem<string> RelatedTo { get; private set; } = new FilterItem<string>();
public FilterItem<string> RomOf { get; private set; } = new FilterItem<string>();
public FilterItem<string> Rotation { get; private set; } = new FilterItem<string>();
public FilterItem<Runnable> Runnable { get; private set; } = new FilterItem<Runnable>() { Positive = Core.Runnable.NULL, Negative = Core.Runnable.NULL };
public FilterItem<string> SampleOf { get; private set; } = new FilterItem<string>();
public FilterItem<string> Score { get; private set; } = new FilterItem<string>();
public FilterItem<string> SourceFile { get; private set; } = new FilterItem<string>();
public FilterItem<string> Status { get; private set; } = new FilterItem<string>();
public FilterItem<string> Subgenre { get; private set; } = new FilterItem<string>();
public FilterItem<Supported> Supported { get; private set; } = new FilterItem<Supported>() { Positive = Core.Supported.NULL, Negative = Core.Supported.NULL };
public FilterItem<string> System { get; private set; } = new FilterItem<string>();
public FilterItem<string> TitleID { get; private set; } = new FilterItem<string>();
public FilterItem<MachineType> Type { get; private set; } = new FilterItem<MachineType>() { Positive = 0x0, Negative = 0x0 };
public FilterItem<string> Year { get; private set; } = new FilterItem<string>();
#endregion // Machine Filters
#region Additional Flags
/// <summary>
/// Include romof and cloneof when filtering machine names
/// </summary>
public bool IncludeOfInGame { get; set; }
/// <summary>
/// Determines if any filters have been set
/// </summary>
public bool HasFilters { get; set; } = false;
#endregion
#endregion // Fields
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public MachineFilter()
{
logger = new Logger(this);
}
#endregion
#region Population
/// <summary>
/// Set multiple filters from key
/// </summary>
/// <param name="key">Key for the filter to be set</param>
/// <param name="values">List of values for the filter</param>
/// <param name="negate">True if negative filter, false otherwise</param>
public void SetFilter(MachineField key, List<string> values, bool negate)
{
foreach (string value in values)
{
SetFilter(key, value, negate);
}
}
/// <summary>
/// Set a single filter from key
/// </summary>
/// <param name="key">Key for the filter to be set</param>
/// <param name="value">Value of the filter</param>
/// <param name="negate">True if negative filter, false otherwise</param>
public void SetFilter(MachineField key, string? value, bool negate)
{
switch (key)
{
case MachineField.Board:
SetStringFilter(Board, value, negate);
break;
case MachineField.Buttons:
SetStringFilter(Buttons, value, negate);
break;
case MachineField.Category:
SetStringFilter(Category, value, negate);
break;
case MachineField.CloneOf:
SetStringFilter(CloneOf, value, negate);
break;
case MachineField.CloneOfID:
SetStringFilter(CloneOfID, value, negate);
break;
case MachineField.Comment:
SetStringFilter(Comment, value, negate);
break;
case MachineField.Control:
SetStringFilter(Control, value, negate);
break;
case MachineField.CRC:
SetBooleanFilter(CRC, value, negate);
break;
case MachineField.Country:
SetStringFilter(Country, value, negate);
break;
case MachineField.Description:
SetStringFilter(Description, value, negate);
break;
case MachineField.Developer:
SetStringFilter(Developer, value, negate);
break;
case MachineField.DisplayCount:
SetStringFilter(DisplayCount, value, negate);
break;
case MachineField.DisplayType:
SetStringFilter(DisplayType, value, negate);
break;
case MachineField.Enabled:
SetStringFilter(Enabled, value, negate);
break;
case MachineField.GenMSXID:
SetStringFilter(GenMSXID, value, negate);
break;
case MachineField.Genre:
SetStringFilter(Genre, value, negate);
break;
case MachineField.History:
SetStringFilter(History, value, negate);
break;
case MachineField.ID:
SetStringFilter(ID, value, negate);
break;
case MachineField.Manufacturer:
SetStringFilter(Manufacturer, value, negate);
break;
case MachineField.Name:
SetStringFilter(Name, value, negate);
break;
case MachineField.Players:
SetStringFilter(Players, value, negate);
break;
case MachineField.Publisher:
SetStringFilter(Publisher, value, negate);
break;
case MachineField.Ratings:
SetStringFilter(Ratings, value, negate);
break;
case MachineField.RebuildTo:
SetStringFilter(RebuildTo, value, negate);
break;
case MachineField.RelatedTo:
SetStringFilter(RelatedTo, value, negate);
break;
case MachineField.RomOf:
SetStringFilter(RomOf, value, negate);
break;
case MachineField.Rotation:
SetStringFilter(Rotation, value, negate);
break;
case MachineField.Runnable:
if (negate)
Runnable.Negative |= value.AsEnumValue<Runnable>();
else
Runnable.Positive |= value.AsEnumValue<Runnable>();
break;
case MachineField.SampleOf:
SetStringFilter(SampleOf, value, negate);
break;
case MachineField.Score:
SetStringFilter(Score, value, negate);
break;
case MachineField.SourceFile:
SetStringFilter(SourceFile, value, negate);
break;
case MachineField.Status:
SetStringFilter(Status, value, negate);
break;
case MachineField.Subgenre:
SetStringFilter(Subgenre, value, negate);
break;
case MachineField.Supported:
if (negate)
Supported.Negative |= value.AsEnumValue<Supported>();
else
Supported.Positive |= value.AsEnumValue<Supported>();
break;
case MachineField.System:
SetStringFilter(System, value, negate);
break;
case MachineField.TitleID:
SetStringFilter(TitleID, value, negate);
break;
case MachineField.Type:
if (negate)
Type.Negative |= value.AsEnumValue<MachineType>();
else
Type.Positive |= value.AsEnumValue<MachineType>();
break;
case MachineField.Year:
SetStringFilter(Year, value, negate);
break;
}
}
#endregion
#region Running
/// <summary>
/// Check to see if a Machine passes the filters
/// </summary>
/// <param name="machine">Machine to check</param>
/// <returns>True if the machine passed the filter, false otherwise</returns>
public bool PassesFilters(Machine machine)
{
if (machine == null)
return false;
// Machine_Board
if (!PassStringFilter(Board, machine.Board))
return false;
// Machine_Buttons
if (!PassStringFilter(Buttons, machine.Buttons))
return false;
// Machine_Category
if (!PassStringFilter(Category, machine.Category))
return false;
// Machine_CloneOf
if (!PassStringFilter(CloneOf, machine.CloneOf))
return false;
// Machine_CloneOfID
if (!PassStringFilter(CloneOfID, value: machine.NoIntroCloneOfId))
return false;
// Machine_Comment
if (!PassStringFilter(Comment, machine.Comment))
return false;
// Machine_Control
if (!PassStringFilter(Control, machine.Control))
return false;
// Machine_Country
if (!PassStringFilter(Country, machine.Country))
return false;
// Machine_CRC
if (!PassBoolFilter(CRC, machine.Crc))
return false;
// Machine_Description
if (!PassStringFilter(Description, machine.Description))
return false;
// Machine_Developer
if (!PassStringFilter(Developer, machine.Developer))
return false;
// Machine_DisplayCount
if (!PassStringFilter(DisplayCount, machine.DisplayCount))
return false;
// Machine_DisplayType
if (!PassStringFilter(DisplayType, machine.DisplayType))
return false;
// Machine_Enabled
if (!PassStringFilter(Enabled, machine.Enabled))
return false;
// Machine_GenMSXID
if (!PassStringFilter(GenMSXID, machine.GenMSXID))
return false;
// Machine_Genre
if (!PassStringFilter(Genre, machine.Genre))
return false;
// Machine_History
if (!PassStringFilter(History, machine.History))
return false;
// Machine_ID
if (!PassStringFilter(ID, machine.NoIntroId))
return false;
// Machine_Manufacturer
if (!PassStringFilter(Manufacturer, machine.Manufacturer))
return false;
// Machine_Name
bool passes = PassStringFilter(Name, machine.Name);
if (IncludeOfInGame)
{
passes |= PassStringFilter(Name, machine.CloneOf);
passes |= PassStringFilter(Name, machine.RomOf);
}
if (!passes)
return false;
// Machine_Players
if (!PassStringFilter(Players, machine.Players))
return false;
// Machine_Publisher
if (!PassStringFilter(Publisher, machine.Publisher))
return false;
// Machine_Ratings
if (!PassStringFilter(Ratings, machine.Ratings))
return false;
// Machine_RebuildTo
if (!PassStringFilter(RebuildTo, machine.RebuildTo))
return false;
// Machine_RelatedTo
if (!PassStringFilter(RelatedTo, machine.RelatedTo))
return false;
// Machine_RomOf
if (!PassStringFilter(RomOf, machine.RomOf))
return false;
// Machine_Rotation
if (!PassStringFilter(Rotation, machine.Rotation))
return false;
// Machine_Runnable
if (Runnable.MatchesPositive(Core.Runnable.NULL, machine.Runnable) == false)
return false;
if (Runnable.MatchesNegative(Core.Runnable.NULL, machine.Runnable) == true)
return false;
// Machine_SampleOf
if (!PassStringFilter(SampleOf, machine.SampleOf))
return false;
// Machine_Score
if (!PassStringFilter(Score, machine.Score))
return false;
// Machine_SourceFile
if (!PassStringFilter(SourceFile, machine.SourceFile))
return false;
// Machine_Status
if (!PassStringFilter(Status, machine.Status))
return false;
// Machine_Subgenre
if (!PassStringFilter(Subgenre, machine.Subgenre))
return false;
// Machine_Supported
if (Supported.MatchesPositive(Core.Supported.NULL, machine.Supported) == false)
return false;
if (Supported.MatchesNegative(Core.Supported.NULL, machine.Supported) == true)
return false;
// Machine_System
if (!PassStringFilter(System, machine.System))
return false;
// Machine_TitleID
if (!PassStringFilter(TitleID, machine.TitleID))
return false;
// Machine_Type
if (Type.MatchesPositive(0x0, machine.MachineType) == false)
return false;
if (Type.MatchesNegative(0x0, machine.MachineType) == true)
return false;
// Machine_Year
if (!PassStringFilter(Year, machine.Year))
return false;
return true;
}
#endregion
}
}

View File

@@ -1,87 +0,0 @@
using System.Collections.Generic;
using SabreTools.DatItems;
using SabreTools.DatItems.Formats;
using Xunit;
namespace SabreTools.Test.Filtering
{
public class FilteringTests
{
[Fact]
public void PassesFiltersDatItemFilterPass()
{
// Setup filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(new List<string> { "item.name:foo" });
// Setup DatItem
var datItem = CreateDatItem();
// Run filters
bool actual = filter.PassesAllFilters(datItem);
Assert.True(actual);
}
[Fact]
public void PassesFiltersDatItemFilterFail()
{
// Setup filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(new List<string> { "item.name:bar" });
// Setup DatItem
var datItem = CreateDatItem();
// Run filters
bool actual = filter.PassesAllFilters(datItem);
Assert.False(actual);
}
[Fact]
public void PassesFiltersMachineFilterPass()
{
// Setup filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(new List<string> { "machine.name:bar" });
// Setup DatItem
var datItem = CreateDatItem();
// Run filters
bool actual = filter.PassesAllFilters(datItem);
Assert.True(actual);
}
[Fact]
public void PassesFiltersMachineFilterFail()
{
// Setup filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(new List<string> { "machine.name:foo" });
// Setup DatItem
var datItem = CreateDatItem();
// Run filters
bool actual = filter.PassesAllFilters(datItem);
Assert.False(actual);
}
/// <summary>
/// Generate a consistent DatItem for testing
/// </summary>
private static DatItem CreateDatItem()
{
return new Rom
{
Name = "foo",
Machine = new Machine
{
Name = "bar",
Description = "bar",
}
};
}
}
}

View File

@@ -94,77 +94,5 @@ namespace SabreTools.Test.Filtering
Assert.Empty(remover.MachineFieldNames); Assert.Empty(remover.MachineFieldNames);
Assert.Single(remover.ItemFieldNames); Assert.Single(remover.ItemFieldNames);
} }
[Fact]
public void PopulateFilterNullListTest()
{
// Setup the list
List<string>? filters = null;
// Setup the filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(filters);
// Check the filters
Assert.NotNull(filter.MachineFilter);
Assert.NotNull(filter.DatItemFilter);
}
[Fact]
public void PopulateFilterEmptyListTest()
{
// Setup the list
List<string> filters = [];
// Setup the filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(filters);
// Check the filters
Assert.NotNull(filter.MachineFilter);
Assert.NotNull(filter.DatItemFilter);
}
[Fact]
public void PopulateFilterMachineFieldTest()
{
// Setup the list
List<string> filters =
[
"machine.name:foo",
"!machine.name:bar",
];
// Setup the filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(filters);
// Check the filters
Assert.NotNull(filter.MachineFilter);
Assert.NotNull(filter.DatItemFilter);
Assert.Contains("foo", filter.MachineFilter.Name.PositiveSet);
Assert.Contains("bar", filter.MachineFilter.Name.NegativeSet);
}
[Fact]
public void PopulateFilterDatItemFieldTest()
{
// Setup the list
List<string> filters =
[
"item.name:foo",
"!item.name:bar"
];
// Setup the filter
var filter = new SabreTools.Filtering.Filter();
filter.PopulateFiltersFromList(filters);
// Check the filters
Assert.NotNull(filter.MachineFilter);
Assert.NotNull(filter.DatItemFilter);
Assert.Contains("foo", filter.DatItemFilter.Name.PositiveSet);
Assert.Contains("bar", filter.DatItemFilter.Name.NegativeSet);
}
} }
} }

View File

@@ -139,7 +139,7 @@ Reset the internal state: reset();";
private abstract class BatchCommand private abstract class BatchCommand
{ {
public string Name { get; private set; } public string Name { get; private set; }
public List<string> Arguments { get; private set; } = new List<string>(); public List<string> Arguments { get; private set; } = [];
/// <summary> /// <summary>
/// Default constructor for setting arguments /// Default constructor for setting arguments
@@ -153,7 +153,7 @@ Reset the internal state: reset();";
/// Create a command based on parsing a line /// Create a command based on parsing a line
/// </summary> /// </summary>
/// <param name="line">Current line to parse into a command</param> /// <param name="line">Current line to parse into a command</param>
public static BatchCommand Create(string line) public static BatchCommand? Create(string line)
{ {
// Empty lines don't count // Empty lines don't count
if (string.IsNullOrEmpty(line)) if (string.IsNullOrEmpty(line))
@@ -207,7 +207,7 @@ Reset the internal state: reset();";
/// <summary> /// <summary>
/// Validate that a set of arguments are sufficient for a given command /// Validate that a set of arguments are sufficient for a given command
/// </summary> /// </summary>
public abstract (bool, string) ValidateArguments(); public abstract (bool, string?) ValidateArguments();
/// <summary> /// <summary>
/// Process a batch file state with the current command /// Process a batch file state with the current command
@@ -370,7 +370,7 @@ Reset the internal state: reset();";
} }
/// <inheritdoc/> /// <inheritdoc/>
public override (bool, string) ValidateArguments() public override (bool, string?) ValidateArguments()
{ {
if (Arguments.Count < 2 || Arguments.Count > 4) if (Arguments.Count < 2 || Arguments.Count > 4)
{ {
@@ -415,29 +415,24 @@ Reset the internal state: reset();";
public override void Process(BatchState batchState) public override void Process(BatchState batchState)
{ {
// Read in the individual arguments // Read in the individual arguments
MachineField filterMachineField = Arguments[0].AsMachineField(); string filterField = Arguments[0];
DatItemField filterDatItemField = Arguments[0].AsDatItemField();
string filterValue = Arguments[1]; string filterValue = Arguments[1];
bool? filterRemove = false; bool? filterRemove = false;
if (Arguments.Count >= 3) if (Arguments.Count >= 3)
filterRemove = Arguments[2].AsYesNo(); filterRemove = Arguments[2].AsYesNo();
// TODO: Add back this functionality
bool? filterPerMachine = false; bool? filterPerMachine = false;
if (Arguments.Count >= 4) if (Arguments.Count >= 4)
filterPerMachine = Arguments[3].AsYesNo(); filterPerMachine = Arguments[3].AsYesNo();
// Create filter to run filters from // Build the filter statement
Filtering.Filter filter = new() string filterString = $"{filterField}{(filterRemove == true ? "!" : string.Empty)}:{filterValue}";
{
MachineFilter = new MachineFilter { HasFilters = true },
DatItemFilter = new DatItemFilter { HasFilters = true },
};
// Set the possible filters // Create filter to run filters from
filter.MachineFilter.SetFilter(filterMachineField, filterValue, filterRemove.Value); var filter = new Filter.FilterRunner([filterString]);
filter.DatItemFilter.SetFilter(filterDatItemField, filterValue, filterRemove.Value);
// Apply the filters blindly // Apply the filters blindly
filter.ApplyFilters(batchState.DatFile, filterPerMachine.Value); batchState.DatFile.ExecuteFilters(filter);
// Cleanup after the filter // Cleanup after the filter
// TODO: We might not want to remove immediately // TODO: We might not want to remove immediately