mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Add tests for Core; fix found issues
This commit is contained in:
@@ -74,9 +74,14 @@ namespace SabreTools.Core
|
||||
if (disk == null)
|
||||
return null;
|
||||
|
||||
// Append a suffix to the name
|
||||
string? name = disk.ReadString(Disk.NameKey);
|
||||
if (name != null)
|
||||
name += ".chd";
|
||||
|
||||
return new Rom
|
||||
{
|
||||
[Rom.NameKey] = disk.ReadString(Disk.NameKey) + ".chd",
|
||||
[Rom.NameKey] = name,
|
||||
[Rom.MergeKey] = disk.ReadString(Disk.MergeKey),
|
||||
[Rom.RegionKey] = disk.ReadString(Disk.RegionKey),
|
||||
[Rom.StatusKey] = disk.ReadString(Disk.StatusKey),
|
||||
@@ -95,9 +100,14 @@ namespace SabreTools.Core
|
||||
if (media == null)
|
||||
return null;
|
||||
|
||||
// Append a suffix to the name
|
||||
string? name = media.ReadString(Media.NameKey);
|
||||
if (name != null)
|
||||
name += ".aaruf";
|
||||
|
||||
return new Rom
|
||||
{
|
||||
[Rom.NameKey] = media.ReadString(Media.NameKey) + ".aaruf",
|
||||
[Rom.NameKey] = name,
|
||||
[Rom.MD5Key] = media.ReadString(Media.MD5Key),
|
||||
[Rom.SHA1Key] = media.ReadString(Media.SHA1Key),
|
||||
[Rom.SHA256Key] = media.ReadString(Media.SHA256Key),
|
||||
@@ -179,8 +189,18 @@ namespace SabreTools.Core
|
||||
break;
|
||||
|
||||
default:
|
||||
if (kvp.Value != other[kvp.Key])
|
||||
// Handle cases where a null is involved
|
||||
if (kvp.Value == null && other[kvp.Key] == null)
|
||||
return true;
|
||||
else if (kvp.Value == null && other[kvp.Key] != null)
|
||||
return false;
|
||||
else if (kvp.Value != null && other[kvp.Key] == null)
|
||||
return false;
|
||||
|
||||
// Try to rely on type hashes
|
||||
else if (kvp.Value!.GetHashCode() != other[kvp.Key]!.GetHashCode())
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -257,6 +277,8 @@ namespace SabreTools.Core
|
||||
// If we have a file that has no known size, rely on the hashes only
|
||||
if (selfSize == null && self.HashMatch(other))
|
||||
return true;
|
||||
else if (otherSize == null && self.HashMatch(other))
|
||||
return true;
|
||||
|
||||
// If we get a partial match
|
||||
if (selfSize == otherSize && self.HashMatch(other))
|
||||
@@ -714,11 +736,8 @@ namespace SabreTools.Core
|
||||
/// <summary>
|
||||
/// Get unique duplicate suffix on name collision
|
||||
/// </summary>
|
||||
private static string GetDuplicateSuffix(this Disk? self)
|
||||
private static string GetDuplicateSuffix(this Disk self)
|
||||
{
|
||||
if (self == null)
|
||||
return string.Empty;
|
||||
|
||||
string? md5 = self.ReadString(Disk.MD5Key);
|
||||
if (!string.IsNullOrEmpty(md5))
|
||||
return $"_{md5}";
|
||||
@@ -733,11 +752,8 @@ namespace SabreTools.Core
|
||||
/// <summary>
|
||||
/// Get unique duplicate suffix on name collision
|
||||
/// </summary>
|
||||
private static string GetDuplicateSuffix(this Media? self)
|
||||
private static string GetDuplicateSuffix(this Media self)
|
||||
{
|
||||
if (self == null)
|
||||
return string.Empty;
|
||||
|
||||
string? md5 = self.ReadString(Media.MD5Key);
|
||||
if (!string.IsNullOrEmpty(md5))
|
||||
return $"_{md5}";
|
||||
@@ -760,11 +776,8 @@ namespace SabreTools.Core
|
||||
/// <summary>
|
||||
/// Get unique duplicate suffix on name collision
|
||||
/// </summary>
|
||||
private static string GetDuplicateSuffix(this Rom? self)
|
||||
private static string GetDuplicateSuffix(this Rom self)
|
||||
{
|
||||
if (self == null)
|
||||
return string.Empty;
|
||||
|
||||
string? crc = self.ReadString(Rom.CRCKey);
|
||||
if (!string.IsNullOrEmpty(crc))
|
||||
return $"_{crc}";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Logging;
|
||||
using SabreTools.IO.Readers;
|
||||
|
||||
@@ -12,7 +13,6 @@ namespace SabreTools.Core.Filter
|
||||
/// <summary>
|
||||
/// Item type and field to update with INI information
|
||||
/// </summary>
|
||||
/// <remarks>Formatted like "ItemName.FieldName"</remarks>
|
||||
public readonly FilterKey Key;
|
||||
|
||||
/// <summary>
|
||||
@@ -24,17 +24,17 @@ namespace SabreTools.Core.Filter
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ExtraIniItem(string key, string ini)
|
||||
public ExtraIniItem(string key, string iniPath)
|
||||
{
|
||||
Key = new FilterKey(key);
|
||||
if (!PopulateFromFile(ini))
|
||||
if (!PopulateFromFile(iniPath))
|
||||
Mappings.Clear();
|
||||
}
|
||||
|
||||
public ExtraIniItem(string itemName, string fieldName, string ini)
|
||||
public ExtraIniItem(string itemName, string fieldName, string iniPath)
|
||||
{
|
||||
Key = new FilterKey(itemName, fieldName);
|
||||
if (!PopulateFromFile(ini))
|
||||
if (!PopulateFromFile(iniPath))
|
||||
Mappings.Clear();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace SabreTools.Core.Filter
|
||||
/// <summary>
|
||||
/// Populate the dictionary from an INI file
|
||||
/// </summary>
|
||||
/// <param name="ini">Path to INI file to populate from</param>
|
||||
/// <param name="iniPath">Path to INI file to populate from</param>
|
||||
/// <remarks>
|
||||
/// The INI file format that is supported here is not exactly the same
|
||||
/// as a traditional one. This expects a MAME extras format, which usually
|
||||
@@ -54,10 +54,16 @@ namespace SabreTools.Core.Filter
|
||||
/// the value is boolean. If there's another section name, then that is set
|
||||
/// as the value instead.
|
||||
/// </remarks>
|
||||
private bool PopulateFromFile(string ini)
|
||||
private bool PopulateFromFile(string iniPath)
|
||||
{
|
||||
// Prepare all intenral variables
|
||||
IniReader ir = new(ini) { ValidateRows = false };
|
||||
// Validate the path
|
||||
if (iniPath.Length == 0)
|
||||
return false;
|
||||
else if (!File.Exists(iniPath))
|
||||
return false;
|
||||
|
||||
// Prepare all internal variables
|
||||
var ir = new IniReader(iniPath) { ValidateRows = false };
|
||||
bool foundRootFolder = false;
|
||||
|
||||
// If we got a null reader, just return
|
||||
@@ -107,7 +113,7 @@ namespace SabreTools.Core.Filter
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerImpl.Warning(ex, $"Exception found while parsing '{ini}'");
|
||||
LoggerImpl.Warning(ex, $"Exception found while parsing '{iniPath}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,11 @@ namespace SabreTools.Core.Filter
|
||||
itemName = string.Empty; fieldName = string.Empty;
|
||||
|
||||
// If we don't have a filter ID, we can't do anything
|
||||
if (itemFieldString == null)
|
||||
if (string.IsNullOrEmpty(itemFieldString))
|
||||
return false;
|
||||
|
||||
// If we only have one part, we can't do anything
|
||||
string[] splitFilter = itemFieldString.Split('.');
|
||||
string[] splitFilter = itemFieldString!.Split('.');
|
||||
if (splitFilter.Length != 2)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace SabreTools.Core.Filter
|
||||
/// </summary>
|
||||
public readonly Operation Operation;
|
||||
|
||||
public FilterObject(string filterString)
|
||||
public FilterObject(string? filterString)
|
||||
{
|
||||
if (!SplitFilterString(filterString, out var keyItem, out Operation operation, out var value))
|
||||
throw new ArgumentOutOfRangeException(nameof(filterString));
|
||||
throw new ArgumentException(nameof(filterString));
|
||||
|
||||
Key = new FilterKey(keyItem);
|
||||
Value = value;
|
||||
@@ -57,7 +57,6 @@ namespace SabreTools.Core.Filter
|
||||
/// </summary>
|
||||
public bool Matches(DictionaryBase dictionaryBase)
|
||||
{
|
||||
// TODO: Add validation of dictionary base type from the key values
|
||||
return Operation switch
|
||||
{
|
||||
Operation.Equals => MatchesEqual(dictionaryBase),
|
||||
@@ -77,16 +76,16 @@ namespace SabreTools.Core.Filter
|
||||
{
|
||||
// If the key doesn't exist, we count it as null
|
||||
if (!dictionaryBase.ContainsKey(Key.FieldName))
|
||||
return Value == null;
|
||||
return string.IsNullOrEmpty(Value);
|
||||
|
||||
// If the value in the dictionary is null
|
||||
string? checkValue = dictionaryBase.ReadString(Key.FieldName);
|
||||
if (checkValue == null)
|
||||
return Value == null;
|
||||
return string.IsNullOrEmpty(Value);
|
||||
|
||||
// If we have both a potentally boolean check and value
|
||||
bool? checkValueBool = ConvertToBoolean(checkValue);
|
||||
bool? matchValueBool = ConvertToBoolean(Value);
|
||||
bool? checkValueBool = checkValue.AsYesNo();
|
||||
bool? matchValueBool = Value.AsYesNo();
|
||||
if (checkValueBool != null && matchValueBool != null)
|
||||
return checkValueBool == matchValueBool;
|
||||
|
||||
@@ -120,16 +119,16 @@ namespace SabreTools.Core.Filter
|
||||
{
|
||||
// If the key doesn't exist, we count it as null
|
||||
if (!dictionaryBase.ContainsKey(Key.FieldName))
|
||||
return Value != null;
|
||||
return !string.IsNullOrEmpty(Value);
|
||||
|
||||
// If the value in the dictionary is null
|
||||
string? checkValue = dictionaryBase.ReadString(Key.FieldName);
|
||||
if (checkValue == null)
|
||||
return Value == null;
|
||||
return !string.IsNullOrEmpty(Value);
|
||||
|
||||
// If we have both a potentally boolean check and value
|
||||
bool? checkValueBool = ConvertToBoolean(checkValue);
|
||||
bool? matchValueBool = ConvertToBoolean(Value);
|
||||
bool? checkValueBool = checkValue.AsYesNo();
|
||||
bool? matchValueBool = Value.AsYesNo();
|
||||
if (checkValueBool != null && matchValueBool != null)
|
||||
return checkValueBool != matchValueBool;
|
||||
|
||||
@@ -309,19 +308,11 @@ namespace SabreTools.Core.Filter
|
||||
return false;
|
||||
|
||||
// If we find a special character, try parsing as regex
|
||||
#if NETFRAMEWORK
|
||||
if (value.Contains("^")
|
||||
|| value.Contains("$")
|
||||
|| value.Contains("*")
|
||||
|| value.Contains("?")
|
||||
|| value.Contains("+"))
|
||||
#else
|
||||
if (value.Contains('^')
|
||||
|| value.Contains('$')
|
||||
|| value.Contains('*')
|
||||
|| value.Contains('?')
|
||||
|| value.Contains('+'))
|
||||
#endif
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -337,23 +328,6 @@ namespace SabreTools.Core.Filter
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to a Boolean
|
||||
/// </summary>
|
||||
private bool? ConvertToBoolean(string? value)
|
||||
{
|
||||
// If we don't have a valid string, we can't do anything
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return null;
|
||||
|
||||
return value!.ToLowerInvariant() switch
|
||||
{
|
||||
"true" or "yes" => true,
|
||||
"false" or "no" => false,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Derive an operation from the input string, if possible
|
||||
/// </summary>
|
||||
@@ -388,11 +362,11 @@ namespace SabreTools.Core.Filter
|
||||
// Set default values
|
||||
key = null; operation = Operation.NONE; value = null;
|
||||
|
||||
if (filterString == null)
|
||||
if (string.IsNullOrEmpty(filterString))
|
||||
return false;
|
||||
|
||||
// Trim quotations, if necessary
|
||||
if (filterString.StartsWith("\""))
|
||||
if (filterString!.StartsWith("\""))
|
||||
filterString = filterString.Substring(1, filterString.Length - 2);
|
||||
|
||||
// Split the string using regex
|
||||
@@ -402,7 +376,10 @@ namespace SabreTools.Core.Filter
|
||||
|
||||
key = match.Groups["itemField"].Value;
|
||||
operation = GetOperation(match.Groups["operation"].Value);
|
||||
value = match.Groups["value"].Value;
|
||||
|
||||
// Only non-zero length values are counted as non-null
|
||||
if (value?.Length > 0)
|
||||
value = match.Groups["value"].Value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="SabreTools.Test" />
|
||||
<InternalsVisibleTo Include="SabreTools.Core.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Support for old .NET versions -->
|
||||
|
||||
@@ -14,9 +14,11 @@ namespace SabreTools.Core.Tools
|
||||
private readonly static long GigaByte = (long)Math.Pow(KiloByte, 3);
|
||||
private readonly static long TeraByte = (long)Math.Pow(KiloByte, 4);
|
||||
private readonly static long PetaByte = (long)Math.Pow(KiloByte, 5);
|
||||
private readonly static long ExaByte = (long)Math.Pow(KiloByte, 6);
|
||||
private readonly static long ZettaByte = (long)Math.Pow(KiloByte, 7);
|
||||
private readonly static long YottaByte = (long)Math.Pow(KiloByte, 8);
|
||||
|
||||
// The following are too big to be represented in Int64
|
||||
// private readonly static long ExaByte = (long)Math.Pow(KiloByte, 6);
|
||||
// private readonly static long ZettaByte = (long)Math.Pow(KiloByte, 7);
|
||||
// private readonly static long YottaByte = (long)Math.Pow(KiloByte, 8);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -27,9 +29,11 @@ namespace SabreTools.Core.Tools
|
||||
private readonly static long GibiByte = (long)Math.Pow(KibiByte, 3);
|
||||
private readonly static long TibiByte = (long)Math.Pow(KibiByte, 4);
|
||||
private readonly static long PibiByte = (long)Math.Pow(KibiByte, 5);
|
||||
private readonly static long ExiByte = (long)Math.Pow(KibiByte, 6);
|
||||
private readonly static long ZittiByte = (long)Math.Pow(KibiByte, 7);
|
||||
private readonly static long YittiByte = (long)Math.Pow(KibiByte, 8);
|
||||
|
||||
// The following are too big to be represented in Int64
|
||||
// private readonly static long ExiByte = (long)Math.Pow(KibiByte, 6);
|
||||
// private readonly static long ZittiByte = (long)Math.Pow(KibiByte, 7);
|
||||
// private readonly static long YittiByte = (long)Math.Pow(KibiByte, 8);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -108,18 +112,20 @@ namespace SabreTools.Core.Tools
|
||||
multiplier = PetaByte;
|
||||
else if (numeric.EndsWith("pi") || numeric.EndsWith("pib"))
|
||||
multiplier = PibiByte;
|
||||
else if (numeric.EndsWith("e") || numeric.EndsWith("eb"))
|
||||
multiplier = ExaByte;
|
||||
else if (numeric.EndsWith("ei") || numeric.EndsWith("eib"))
|
||||
multiplier = ExiByte;
|
||||
else if (numeric.EndsWith("z") || numeric.EndsWith("zb"))
|
||||
multiplier = ZettaByte;
|
||||
else if (numeric.EndsWith("zi") || numeric.EndsWith("zib"))
|
||||
multiplier = ZittiByte;
|
||||
else if (numeric.EndsWith("y") || numeric.EndsWith("yb"))
|
||||
multiplier = YottaByte;
|
||||
else if (numeric.EndsWith("yi") || numeric.EndsWith("yib"))
|
||||
multiplier = YittiByte;
|
||||
|
||||
// The following are too big to be represented in Int64
|
||||
// else if (numeric.EndsWith("e") || numeric.EndsWith("eb"))
|
||||
// multiplier = ExaByte;
|
||||
// else if (numeric.EndsWith("ei") || numeric.EndsWith("eib"))
|
||||
// multiplier = ExiByte;
|
||||
// else if (numeric.EndsWith("z") || numeric.EndsWith("zb"))
|
||||
// multiplier = ZettaByte;
|
||||
// else if (numeric.EndsWith("zi") || numeric.EndsWith("zib"))
|
||||
// multiplier = ZittiByte;
|
||||
// else if (numeric.EndsWith("y") || numeric.EndsWith("yb"))
|
||||
// multiplier = YottaByte;
|
||||
// else if (numeric.EndsWith("yi") || numeric.EndsWith("yib"))
|
||||
// multiplier = YittiByte;
|
||||
|
||||
return multiplier;
|
||||
}
|
||||
@@ -138,9 +144,18 @@ namespace SabreTools.Core.Tools
|
||||
if (value.StartsWith("0x"))
|
||||
value = value.Substring(2);
|
||||
|
||||
// If we have a negative value
|
||||
if (value.StartsWith("-"))
|
||||
value = value.Substring(1);
|
||||
|
||||
// If the value has a multiplier
|
||||
if (DetermineMultiplier(value) > 1)
|
||||
value = value.TrimEnd(['k', 'm', 'g', 't', 'p', 'e', 'z', 'y', 'i', 'b', ' ']);
|
||||
|
||||
// If the value is empty after trimming
|
||||
if (value.Length == 0)
|
||||
return false;
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
return value.All(c => char.IsAsciiHexDigit(c) || c == '.' || c == ',');
|
||||
#else
|
||||
|
||||
@@ -80,8 +80,14 @@ namespace SabreTools.Core.Tools
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all unicode-specific chars from a string
|
||||
/// Remove all Unicode-specific chars from a string
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// "Unicode characters" here means any characters outside of the
|
||||
/// Extended ASCII (0x00 to 0xFF) set. This is just a simple
|
||||
/// way of filtering out characters that won't work on all
|
||||
/// supported platforms.
|
||||
/// </remarks>
|
||||
public static string RemoveUnicodeCharacters(string? input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
@@ -151,9 +157,9 @@ namespace SabreTools.Core.Tools
|
||||
private static string? NormalizeHashData(string? hash, int expectedLength)
|
||||
{
|
||||
// If we have a known blank hash, return blank
|
||||
if (string.IsNullOrEmpty(hash))
|
||||
if (hash == null)
|
||||
return null;
|
||||
else if (hash == "-" || hash == "_")
|
||||
else if (hash == string.Empty || hash == "-" || hash == "_")
|
||||
return string.Empty;
|
||||
|
||||
// Check to see if it's a "hex" hash
|
||||
|
||||
Reference in New Issue
Block a user