From f5e2d8a11c26e6d15e9919e4d84ef85f4da33181 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 4 Jan 2025 19:47:39 -0500 Subject: [PATCH] Add tests for Core; fix found issues --- .../DictionaryBaseExtensionsTests.cs | 1871 +++++++++++++++++ .../Filter/ExtraIniItemTests.cs | 40 + .../Filter/FieldManipulatorTests.cs | 192 ++ SabreTools.Core.Test/Filter/FilterKeyTests.cs | 82 + .../Filter/FilterObjectTests.cs | 471 +++++ .../Filter/FilterRunnerTests.cs | 220 ++ .../SabreTools.Core.Test.csproj | 41 + SabreTools.Core.Test/TestData/extra.ini | 12 + .../Tools}/ConvertersTests.cs | 26 +- .../Tools/DateTimeHelperTests.cs | 65 + .../Tools/NumberHelperTests.cs | 106 + SabreTools.Core.Test/Tools/TextHelperTests.cs | 186 ++ SabreTools.Core.Test/Tools/UtilitiesTests.cs | 105 + SabreTools.Core/DictionaryBaseExtensions.cs | 43 +- SabreTools.Core/Filter/ExtraIniItem.cs | 26 +- SabreTools.Core/Filter/FilterKey.cs | 4 +- SabreTools.Core/Filter/FilterObject.cs | 55 +- SabreTools.Core/SabreTools.Core.csproj | 2 +- SabreTools.Core/Tools/NumberHelper.cs | 51 +- SabreTools.Core/Tools/TextHelper.cs | 12 +- SabreTools.Test/Core/UtilitiesTests.cs | 54 - SabreTools.Test/Filter/FilteringTests.cs | 82 - SabreTools.Test/Filter/PopulationTests.cs | 68 - SabreTools.sln | 10 + 24 files changed, 3531 insertions(+), 293 deletions(-) create mode 100644 SabreTools.Core.Test/DictionaryBaseExtensionsTests.cs create mode 100644 SabreTools.Core.Test/Filter/ExtraIniItemTests.cs create mode 100644 SabreTools.Core.Test/Filter/FieldManipulatorTests.cs create mode 100644 SabreTools.Core.Test/Filter/FilterKeyTests.cs create mode 100644 SabreTools.Core.Test/Filter/FilterObjectTests.cs create mode 100644 SabreTools.Core.Test/Filter/FilterRunnerTests.cs create mode 100644 SabreTools.Core.Test/SabreTools.Core.Test.csproj create mode 100644 SabreTools.Core.Test/TestData/extra.ini rename {SabreTools.Test/Core => SabreTools.Core.Test/Tools}/ConvertersTests.cs (97%) create mode 100644 SabreTools.Core.Test/Tools/DateTimeHelperTests.cs create mode 100644 SabreTools.Core.Test/Tools/NumberHelperTests.cs create mode 100644 SabreTools.Core.Test/Tools/TextHelperTests.cs create mode 100644 SabreTools.Core.Test/Tools/UtilitiesTests.cs delete mode 100644 SabreTools.Test/Core/UtilitiesTests.cs delete mode 100644 SabreTools.Test/Filter/FilteringTests.cs delete mode 100644 SabreTools.Test/Filter/PopulationTests.cs diff --git a/SabreTools.Core.Test/DictionaryBaseExtensionsTests.cs b/SabreTools.Core.Test/DictionaryBaseExtensionsTests.cs new file mode 100644 index 00000000..96daf827 --- /dev/null +++ b/SabreTools.Core.Test/DictionaryBaseExtensionsTests.cs @@ -0,0 +1,1871 @@ +using SabreTools.Hashing; +using SabreTools.Models.Metadata; +using Xunit; + +namespace SabreTools.Core.Test +{ + public class DictionaryBaseExtensionsTests + { + #region Clone + + // TODO: Figure out how to test Clone + + #endregion + + #region ConvertToRom + + [Fact] + public void ConvertToRom_Null_Null() + { + DictionaryBase? self = null; + Rom? actual = self.ConvertToRom(); + Assert.Null(actual); + } + + [Fact] + public void ConvertToRom_EmptyDisk_EmptyRom() + { + DictionaryBase? self = new Disk(); + Rom? actual = self.ConvertToRom(); + + Assert.NotNull(actual); + Assert.Equal(8, actual.Count); + Assert.Equal(ItemType.Rom, actual["_type"]); + Assert.Null(actual[Rom.NameKey]); + Assert.Null(actual[Rom.MergeKey]); + Assert.Null(actual[Rom.RegionKey]); + Assert.Null(actual[Rom.StatusKey]); + Assert.Null(actual[Rom.OptionalKey]); + Assert.Null(actual[Rom.MD5Key]); + Assert.Null(actual[Rom.SHA1Key]); + } + + [Fact] + public void ConvertToRom_FilledDisk_FilledRom() + { + DictionaryBase? self = new Disk + { + [Disk.NameKey] = "XXXXXX", + [Disk.MergeKey] = "XXXXXX", + [Disk.RegionKey] = "XXXXXX", + [Disk.StatusKey] = "XXXXXX", + [Disk.OptionalKey] = "XXXXXX", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + Rom? actual = self.ConvertToRom(); + + Assert.NotNull(actual); + Assert.Equal(8, actual.Count); + Assert.Equal(ItemType.Rom, actual["_type"]); + Assert.Equal("XXXXXX.chd", actual[Rom.NameKey]); + Assert.Equal("XXXXXX", actual[Rom.MergeKey]); + Assert.Equal("XXXXXX", actual[Rom.RegionKey]); + Assert.Equal("XXXXXX", actual[Rom.StatusKey]); + Assert.Equal("XXXXXX", actual[Rom.OptionalKey]); + Assert.Equal("XXXXXX", actual[Rom.MD5Key]); + Assert.Equal("XXXXXX", actual[Rom.SHA1Key]); + } + + [Fact] + public void ConvertToRom_EmptyMedia_EmptyRom() + { + DictionaryBase? self = new Media(); + Rom? actual = self.ConvertToRom(); + + Assert.NotNull(actual); + Assert.Equal(6, actual.Count); + Assert.Equal(ItemType.Rom, actual["_type"]); + Assert.Null(actual[Rom.NameKey]); + Assert.Null(actual[Rom.MD5Key]); + Assert.Null(actual[Rom.SHA1Key]); + Assert.Null(actual[Rom.SHA256Key]); + Assert.Null(actual[Rom.SpamSumKey]); + } + + [Fact] + public void ConvertToRom_FilledMedia_FilledRom() + { + DictionaryBase? self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + Rom? actual = self.ConvertToRom(); + + Assert.NotNull(actual); + Assert.Equal(6, actual.Count); + Assert.Equal(ItemType.Rom, actual["_type"]); + Assert.Equal("XXXXXX.aaruf", actual[Rom.NameKey]); + Assert.Equal("XXXXXX", actual[Rom.MD5Key]); + Assert.Equal("XXXXXX", actual[Rom.SHA1Key]); + Assert.Equal("XXXXXX", actual[Rom.SHA256Key]); + Assert.Equal("XXXXXX", actual[Rom.SpamSumKey]); + } + + [Fact] + public void ConvertToRom_Other_Null() + { + DictionaryBase? self = new Sample(); + Rom? actual = self.ConvertToRom(); + Assert.Null(actual); + } + + #endregion + + #region EqualTo + + [Fact] + public void EqualTo_MismatchedTypes_False() + { + DictionaryBase self = new Disk(); + DictionaryBase other = new Rom(); + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Disk_Nodumps_True() + { + DictionaryBase self = new Disk + { + [Disk.StatusKey] = "nodump", + [Disk.NameKey] = "XXXXXX", + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = string.Empty, + }; + DictionaryBase other = new Disk + { + [Disk.StatusKey] = "NODUMP", + [Disk.NameKey] = "XXXXXX", + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = string.Empty, + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Disk_Mismatch_False() + { + DictionaryBase self = new Disk + { + [Disk.NameKey] = "XXXXXX", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = string.Empty, + }; + DictionaryBase other = new Disk + { + [Disk.NameKey] = "XXXXXX", + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Disk_PartialMD5_True() + { + DictionaryBase self = new Disk + { + [Disk.NameKey] = "XXXXXX1", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = string.Empty, + }; + DictionaryBase other = new Disk + { + [Disk.NameKey] = "XXXXXX2", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Disk_PartialSHA1_True() + { + DictionaryBase self = new Disk + { + [Disk.NameKey] = "XXXXXX1", + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = "XXXXXX", + }; + DictionaryBase other = new Disk + { + [Disk.NameKey] = "XXXXXX2", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Disk_FullMatch_True() + { + DictionaryBase self = new Disk + { + [Disk.NameKey] = "XXXXXX1", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + DictionaryBase other = new Disk + { + [Disk.NameKey] = "XXXXXX2", + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Media_Mismatch_False() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Media_PartialMD5_True() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Media_PartialSHA1_True() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Media_PartialSHA256_True() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Media_PartialSpamSum_True() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Media_FullMatch_True() + { + DictionaryBase self = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Media + { + [Media.NameKey] = "XXXXXX", + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_Nodumps_True() + { + DictionaryBase self = new Rom + { + [Rom.StatusKey] = "nodump", + [Rom.NameKey] = "XXXXXX", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.StatusKey] = "NODUMP", + [Rom.NameKey] = "XXXXXX", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_Mismatch_False() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Rom_NoSelfSize_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_NoOtherSize_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialCRC_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialMD5_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialSHA1_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialSHA256_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialSHA384_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialSHA512_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = string.Empty, + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_PartialSpamSum_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Rom_FullMatch_True() + { + DictionaryBase self = new Rom + { + [Rom.NameKey] = "XXXXXX1", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + DictionaryBase other = new Rom + { + [Rom.NameKey] = "XXXXXX2", + [Rom.SizeKey] = 12345, + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Other_BothEmpty_True() + { + DictionaryBase self = new Sample(); + DictionaryBase other = new Sample(); + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + [Fact] + public void EqualTo_Other_MismatchedCount_False() + { + DictionaryBase self = new Sample + { + ["KEY1"] = "XXXXXX", + }; + DictionaryBase other = new Sample + { + ["KEY1"] = "XXXXXX", + ["KEY2"] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Other_MismatchedKeys_False() + { + DictionaryBase self = new Sample + { + ["KEY1"] = "XXXXXX", + }; + DictionaryBase other = new Sample + { + ["KEY2"] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Other_MismatchedValues_False() + { + DictionaryBase self = new Sample + { + ["KEY1"] = "XXXXXX", + }; + DictionaryBase other = new Sample + { + ["KEY1"] = "ZZZZZZ", + }; + + bool actual = self.EqualTo(other); + Assert.False(actual); + } + + [Fact] + public void EqualTo_Other_Matching_True() + { + DictionaryBase self = new Sample + { + ["KEY1"] = "XXXXXX", + }; + DictionaryBase other = new Sample + { + ["KEY1"] = "XXXXXX", + }; + + bool actual = self.EqualTo(other); + Assert.True(actual); + } + + #endregion + + #region HashMatch + + [Fact] + public void HashMatch_Disk_Mismatch_False() + { + Disk self = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = string.Empty, + }; + Disk other = new Disk + { + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.False(actual); + } + + [Fact] + public void HashMatch_Disk_PartialMD5_True() + { + Disk self = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = string.Empty, + }; + Disk other = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Disk_PartialSHA1_True() + { + Disk self = new Disk + { + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = "XXXXXX", + }; + Disk other = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Disk_FullMatch_True() + { + Disk self = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + Disk other = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Media_Mismatch_False() + { + Media self = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = string.Empty, + }; + Media other = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.False(actual); + } + + [Fact] + public void HashMatch_Media_PartialMD5_True() + { + Media self = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + Media other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Media_PartialSHA1_True() + { + Media self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + Media other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Media_PartialSHA256_True() + { + Media self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = string.Empty, + }; + Media other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Media_PartialSpamSum_True() + { + Media self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = "XXXXXX", + }; + Media other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Media_FullMatch_True() + { + Media self = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + Media other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_Mismatch_False() + { + Rom self = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = "XXXXXX", + }; + Rom other = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HashMatch(other); + Assert.False(actual); + } + + [Fact] + public void HashMatch_Rom_PartialCRC_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialMD5_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialSHA1_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialSHA256_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialSHA384_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialSHA512_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = string.Empty, + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_PartialSpamSum_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = "XXXXXX", + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + [Fact] + public void HashMatch_Rom_FullMatch_True() + { + Rom self = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + Rom other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HashMatch(other); + Assert.True(actual); + } + + #endregion + + #region HasZeroHash + + [Fact] + public void HasZeroHash_Disk_NoHash_True() + { + DictionaryBase self = new Disk(); + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Disk_NonZeroHash_False() + { + DictionaryBase self = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + bool actual = self.HasZeroHash(); + Assert.False(actual); + } + + [Fact] + public void HasZeroHash_Disk_ZeroMD5_True() + { + DictionaryBase self = new Disk + { + [Disk.MD5Key] = ZeroHash.MD5Str, + [Disk.SHA1Key] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Disk_ZeroSHA1_True() + { + DictionaryBase self = new Disk + { + [Disk.MD5Key] = string.Empty, + [Disk.SHA1Key] = ZeroHash.SHA1Str, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Disk_ZeroAll_True() + { + DictionaryBase self = new Disk + { + [Disk.MD5Key] = ZeroHash.MD5Str, + [Disk.SHA1Key] = ZeroHash.SHA1Str, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_NoHash_True() + { + DictionaryBase self = new Media(); + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_NonZeroHash_False() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HasZeroHash(); + Assert.False(actual); + } + + [Fact] + public void HasZeroHash_Media_ZeroMD5_True() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = ZeroHash.MD5Str, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_ZeroSHA1_True() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = ZeroHash.SHA1Str, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_ZeroSHA256_True() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = ZeroHash.SHA256Str, + [Media.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_ZeroSpamSum_True() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = string.Empty, + [Media.SHA1Key] = string.Empty, + [Media.SHA256Key] = string.Empty, + [Media.SpamSumKey] = ZeroHash.SpamSumStr, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Media_ZeroAll_True() + { + DictionaryBase self = new Media + { + [Media.MD5Key] = ZeroHash.MD5Str, + [Media.SHA1Key] = ZeroHash.SHA1Str, + [Media.SHA256Key] = ZeroHash.SHA256Str, + [Media.SpamSumKey] = ZeroHash.SpamSumStr, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_NoHash_True() + { + DictionaryBase self = new Rom(); + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_NonZeroHash_False() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + bool actual = self.HasZeroHash(); + Assert.False(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroCRC_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = ZeroHash.CRC32Str, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroMD5_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = ZeroHash.MD5Str, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroSHA1_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = ZeroHash.SHA1Str, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroSHA256_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = ZeroHash.SHA256Str, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroSHA384_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = ZeroHash.SHA384Str, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroSHA512_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = ZeroHash.SHA512Str, + [Rom.SpamSumKey] = string.Empty, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroSpamSum_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = string.Empty, + [Rom.MD5Key] = string.Empty, + [Rom.SHA1Key] = string.Empty, + [Rom.SHA256Key] = string.Empty, + [Rom.SHA384Key] = string.Empty, + [Rom.SHA512Key] = string.Empty, + [Rom.SpamSumKey] = ZeroHash.SpamSumStr, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Rom_ZeroAll_True() + { + DictionaryBase self = new Rom + { + [Rom.CRCKey] = ZeroHash.CRC32Str, + [Rom.MD5Key] = ZeroHash.MD5Str, + [Rom.SHA1Key] = ZeroHash.SHA1Str, + [Rom.SHA256Key] = ZeroHash.SHA256Str, + [Rom.SHA384Key] = ZeroHash.SHA384Str, + [Rom.SHA512Key] = ZeroHash.SHA512Str, + [Rom.SpamSumKey] = ZeroHash.SpamSumStr, + }; + + bool actual = self.HasZeroHash(); + Assert.True(actual); + } + + [Fact] + public void HasZeroHash_Other_False() + { + DictionaryBase self = new Sample(); + bool actual = self.HasZeroHash(); + Assert.False(actual); + } + + #endregion + + #region FillMissingHashes + + [Fact] + public void FillMissingHashes_Disk_BothEmpty() + { + DictionaryBase self = new Disk(); + DictionaryBase other = new Disk(); + + self.FillMissingHashes(other); + Assert.Single(self); + } + + [Fact] + public void FillMissingHashes_Disk_AllMissing() + { + DictionaryBase self = new Disk(); + DictionaryBase other = new Disk + { + [Disk.MD5Key] = "XXXXXX", + [Disk.SHA1Key] = "XXXXXX", + }; + + self.FillMissingHashes(other); + } + + [Fact] + public void FillMissingHashes_Media_BothEmpty() + { + DictionaryBase self = new Media(); + DictionaryBase other = new Media(); + self.FillMissingHashes(other); + Assert.Single(self); + } + + [Fact] + public void FillMissingHashes_Media_AllMissing() + { + DictionaryBase self = new Media(); + DictionaryBase other = new Media + { + [Media.MD5Key] = "XXXXXX", + [Media.SHA1Key] = "XXXXXX", + [Media.SHA256Key] = "XXXXXX", + [Media.SpamSumKey] = "XXXXXX", + }; + + self.FillMissingHashes(other); + } + + [Fact] + public void FillMissingHashes_Rom_BothEmpty() + { + DictionaryBase self = new Rom(); + DictionaryBase other = new Rom(); + self.FillMissingHashes(other); + Assert.Single(self); + } + + [Fact] + public void FillMissingHashes_Rom_AllMissing() + { + DictionaryBase self = new Rom(); + DictionaryBase other = new Rom + { + [Rom.CRCKey] = "XXXXXX", + [Rom.MD5Key] = "XXXXXX", + [Rom.SHA1Key] = "XXXXXX", + [Rom.SHA256Key] = "XXXXXX", + [Rom.SHA384Key] = "XXXXXX", + [Rom.SHA512Key] = "XXXXXX", + [Rom.SpamSumKey] = "XXXXXX", + }; + + self.FillMissingHashes(other); + } + + #endregion + + #region GetDuplicateSuffix + + [Fact] + public void GetDuplicateSuffix_Disk_NoHash_Generic() + { + DictionaryBase self = new Disk(); + string actual = self.GetDuplicateSuffix(); + Assert.Equal("_1", actual); + } + + [Fact] + public void GetDuplicateSuffix_Disk_MD5() + { + string hash = "XXXXXX"; + DictionaryBase self = new Disk { [Disk.MD5Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Disk_SHA1() + { + string hash = "XXXXXX"; + DictionaryBase self = new Disk { [Disk.SHA1Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Media_NoHash_Generic() + { + DictionaryBase self = new Media(); + string actual = self.GetDuplicateSuffix(); + Assert.Equal("_1", actual); + } + + [Fact] + public void GetDuplicateSuffix_Media_MD5() + { + string hash = "XXXXXX"; + DictionaryBase self = new Media { [Media.MD5Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Media_SHA1() + { + string hash = "XXXXXX"; + DictionaryBase self = new Media { [Media.SHA1Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Media_SHA256() + { + string hash = "XXXXXX"; + DictionaryBase self = new Media { [Media.SHA256Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Media_SpamSum() + { + string hash = "XXXXXX"; + DictionaryBase self = new Media { [Media.SpamSumKey] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_NoHash_Generic() + { + DictionaryBase self = new Rom(); + string actual = self.GetDuplicateSuffix(); + Assert.Equal("_1", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_CRC() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.CRCKey] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_MD5() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.MD5Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_SHA1() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.SHA1Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_SHA256() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.SHA256Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_SHA384() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.SHA384Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_SHA512() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.SHA512Key] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Rom_SpamSum() + { + string hash = "XXXXXX"; + DictionaryBase self = new Rom { [Rom.SpamSumKey] = hash }; + string actual = self.GetDuplicateSuffix(); + Assert.Equal($"_{hash}", actual); + } + + [Fact] + public void GetDuplicateSuffix_Other_Generic() + { + DictionaryBase self = new Sample(); + string actual = self.GetDuplicateSuffix(); + Assert.Equal("_1", actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Filter/ExtraIniItemTests.cs b/SabreTools.Core.Test/Filter/ExtraIniItemTests.cs new file mode 100644 index 00000000..609e79b6 --- /dev/null +++ b/SabreTools.Core.Test/Filter/ExtraIniItemTests.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.IO; +using SabreTools.Core.Filter; +using Xunit; + +namespace SabreTools.Core.Test.Filter +{ + public class ExtraIniItemTests + { + [Fact] + public void Constructor_EmptyPath_NoMappings() + { + string iniPath = string.Empty; + ExtraIniItem extraIniItem = new ExtraIniItem("Sample.Name", iniPath); + Assert.Empty(extraIniItem.Mappings); + } + + [Fact] + public void Constructor_InvalidPath_NoMappings() + { + string iniPath = "INVALID"; + ExtraIniItem extraIniItem = new ExtraIniItem("Sample.Name", iniPath); + Assert.Empty(extraIniItem.Mappings); + } + + [Fact] + public void Constructor_ValidPath_Mappings() + { + string iniPath = Path.Combine(Environment.CurrentDirectory, "TestData", "extra.ini"); + ExtraIniItem extraIniItem = new ExtraIniItem("Sample.Name", iniPath); + + Dictionary mappings = extraIniItem.Mappings; + Assert.NotEmpty(mappings); + Assert.Equal("true", mappings["useBool"]); + Assert.Equal("Value", mappings["useValue"]); + Assert.Equal("Other", mappings["useOther"]); + } + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Filter/FieldManipulatorTests.cs b/SabreTools.Core.Test/Filter/FieldManipulatorTests.cs new file mode 100644 index 00000000..e7351bbd --- /dev/null +++ b/SabreTools.Core.Test/Filter/FieldManipulatorTests.cs @@ -0,0 +1,192 @@ +using SabreTools.Core.Filter; +using SabreTools.Models.Metadata; +using Xunit; + +namespace SabreTools.Core.Test.Filter +{ + public class FieldManipulatorTests + { + #region RemoveField + + [Fact] + public void RemoveField_NullItem_False() + { + DictionaryBase? dictionaryBase = null; + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.RemoveField(dictionaryBase, fieldName); + Assert.False(actual); + } + + [Fact] + public void RemoveField_NullFieldName_False() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = null; + bool actual = FieldManipulator.RemoveField(dictionaryBase, fieldName); + Assert.False(actual); + } + + [Fact] + public void RemoveField_EmptyFieldName_False() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = string.Empty; + bool actual = FieldManipulator.RemoveField(dictionaryBase, fieldName); + Assert.False(actual); + } + + [Fact] + public void RemoveField_MissingKey_True() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.RemoveField(dictionaryBase, fieldName); + Assert.True(actual); + Assert.DoesNotContain(fieldName, dictionaryBase.Keys); + } + + [Fact] + public void RemoveField_ValidKey_True() + { + DictionaryBase? dictionaryBase = new Sample { [Sample.NameKey] = "value" }; + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.RemoveField(dictionaryBase, fieldName); + Assert.True(actual); + Assert.DoesNotContain(fieldName, dictionaryBase.Keys); + } + + #endregion + + #region ReplaceField + + [Fact] + public void ReplaceField_NullFrom_False() + { + DictionaryBase? from = null; + DictionaryBase? to = new Sample(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_NullTo_False() + { + DictionaryBase? from = null; + DictionaryBase? to = new Sample(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_NullFieldName_False() + { + DictionaryBase? from = new Sample(); + DictionaryBase? to = new Sample(); + string? fieldName = null; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_EmptyFieldName_False() + { + DictionaryBase? from = new Sample(); + DictionaryBase? to = new Sample(); + string? fieldName = string.Empty; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_MismatchedTypes_False() + { + DictionaryBase? from = new Sample(); + DictionaryBase? to = new Rom(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_MissingKey_False() + { + DictionaryBase? from = new Sample(); + DictionaryBase? to = new Sample(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.False(actual); + } + + [Fact] + public void ReplaceField_ValidKey_True() + { + DictionaryBase? from = new Sample { [Sample.NameKey] = "value" }; + DictionaryBase? to = new Sample(); + string? fieldName = Sample.NameKey; + bool actual = FieldManipulator.ReplaceField(from, to, fieldName); + Assert.True(actual); + Assert.Contains(fieldName, to.Keys); + Assert.Equal("value", to[Sample.NameKey]); + } + + #endregion + + #region SetField + + [Fact] + public void SetField_NullItem_False() + { + DictionaryBase? dictionaryBase = null; + string? fieldName = Sample.NameKey; + object value = "value"; + bool actual = FieldManipulator.SetField(dictionaryBase, fieldName, value); + Assert.False(actual); + } + + [Fact] + public void SetField_NullFieldName_False() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = null; + object value = "value"; + bool actual = FieldManipulator.SetField(dictionaryBase, fieldName, value); + Assert.False(actual); + } + + [Fact] + public void SetField_EmptyFieldName_False() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = string.Empty; + object value = "value"; + bool actual = FieldManipulator.SetField(dictionaryBase, fieldName, value); + Assert.False(actual); + } + + [Fact] + public void SetField_MissingKey_False() + { + DictionaryBase? dictionaryBase = new Sample(); + string? fieldName = Rom.SHA1Key; + object value = "value"; + bool actual = FieldManipulator.SetField(dictionaryBase, fieldName, value); + Assert.False(actual); + } + + [Fact] + public void SetField_ValidKey_True() + { + DictionaryBase? dictionaryBase = new Sample { [Sample.NameKey] = "old" }; + string? fieldName = Sample.NameKey; + object value = "value"; + bool actual = FieldManipulator.SetField(dictionaryBase, fieldName, value); + Assert.True(actual); + Assert.Contains(fieldName, dictionaryBase.Keys); + Assert.Equal(value, dictionaryBase[fieldName]); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Filter/FilterKeyTests.cs b/SabreTools.Core.Test/Filter/FilterKeyTests.cs new file mode 100644 index 00000000..7758495a --- /dev/null +++ b/SabreTools.Core.Test/Filter/FilterKeyTests.cs @@ -0,0 +1,82 @@ +using System; +using SabreTools.Core.Filter; +using Xunit; + +namespace SabreTools.Core.Test.Filter +{ + public class FilterKeyTests + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("ItemName")] + [InlineData("ItemName.FieldName.Extra")] + [InlineData("InvalidItemName.FieldName")] + [InlineData("DatItem.InvalidFieldName")] + [InlineData("Item.InvalidFieldName")] + [InlineData("Sample.InvalidFieldName")] + public void Constructor_InvalidKey_Throws(string? key) + { + Assert.Throws(() => new FilterKey(key)); + } + + [Theory] + [InlineData("header.name", "header", "name")] + [InlineData("HEADER.NAME", "header", "name")] + [InlineData("game.name", "machine", "name")] + [InlineData("GAME.NAME", "machine", "name")] + [InlineData("machine.name", "machine", "name")] + [InlineData("MACHINE.NAME", "machine", "name")] + [InlineData("resource.name", "machine", "name")] + [InlineData("RESOURCE.NAME", "machine", "name")] + [InlineData("set.name", "machine", "name")] + [InlineData("SET.NAME", "machine", "name")] + [InlineData("datitem.name", "item", "name")] + [InlineData("DATITEM.NAME", "item", "name")] + [InlineData("item.name", "item", "name")] + [InlineData("ITEM.NAME", "item", "name")] + [InlineData("sample.name", "sample", "name")] + [InlineData("SAMPLE.NAME", "sample", "name")] + public void Constructor_ValidKey_Sets(string? key, string expectedItemName, string expectedFieldName) + { + FilterKey filterKey = new FilterKey(key); + Assert.Equal(expectedItemName, filterKey.ItemName); + Assert.Equal(expectedFieldName, filterKey.FieldName); + } + + [Theory] + [InlineData("", "FieldName")] + [InlineData("ItemName", "")] + [InlineData("DatItem", "InvalidFieldName")] + [InlineData("Item", "InvalidFieldName")] + [InlineData("Sample", "InvalidFieldName")] + public void Constructor_InvalidNames_Throws(string itemName, string fieldName) + { + Assert.Throws(() => new FilterKey(itemName, fieldName)); + } + + [Theory] + [InlineData("header", "name", "header", "name")] + [InlineData("HEADER", "NAME", "header", "name")] + [InlineData("game", "name", "machine", "name")] + [InlineData("GAME", "NAME", "machine", "name")] + [InlineData("machine", "name", "machine", "name")] + [InlineData("MACHINE", "NAME", "machine", "name")] + [InlineData("resource", "name", "machine", "name")] + [InlineData("RESOURCE", "NAME", "machine", "name")] + [InlineData("set", "name", "machine", "name")] + [InlineData("SET", "NAME", "machine", "name")] + [InlineData("datitem", "name", "item", "name")] + [InlineData("DATITEM", "NAME", "item", "name")] + [InlineData("item", "name", "item", "name")] + [InlineData("ITEM", "NAME", "item", "name")] + [InlineData("sample", "name", "sample", "name")] + [InlineData("SAMPLE", "NAME", "sample", "name")] + public void Constructor_ValidNames_Sets(string itemName, string fieldName, string expectedItemName, string expectedFieldName) + { + FilterKey filterKey = new FilterKey(itemName, fieldName); + Assert.Equal(expectedItemName, filterKey.ItemName); + Assert.Equal(expectedFieldName, filterKey.FieldName); + } + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Filter/FilterObjectTests.cs b/SabreTools.Core.Test/Filter/FilterObjectTests.cs new file mode 100644 index 00000000..920f8cd2 --- /dev/null +++ b/SabreTools.Core.Test/Filter/FilterObjectTests.cs @@ -0,0 +1,471 @@ +using System; +using SabreTools.Core.Filter; +using SabreTools.Models.Metadata; +using Xunit; + +namespace SabreTools.Core.Test.Filter +{ + public class FilterObjectTests + { + #region Constructor + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("Sample.Name")] + [InlineData("Sample.Name++")] + public void Constructor_InvalidKey_Throws(string? filterString) + { + Assert.Throws(() => new FilterObject(filterString)); + } + + [Theory] + [InlineData("Sample.Name=XXXXXX", Operation.Equals)] + [InlineData("Sample.Name==XXXXXX", Operation.Equals)] + [InlineData("Sample.Name:XXXXXX", Operation.Equals)] + [InlineData("Sample.Name::XXXXXX", Operation.Equals)] + [InlineData("Sample.Name!XXXXXX", Operation.NotEquals)] + [InlineData("Sample.Name!=XXXXXX", Operation.NotEquals)] + [InlineData("Sample.Name!:XXXXXX", Operation.NotEquals)] + [InlineData("Sample.Name>XXXXXX", Operation.GreaterThan)] + [InlineData("Sample.Name>=XXXXXX", Operation.GreaterThanOrEqual)] + [InlineData("Sample.NameXXXXXX", Operation.NONE)] + [InlineData("Sample.Name=XXXXXX", Operation.NONE)] + [InlineData("Sample.Name>", Operation.GreaterThan)] + [InlineData("Sample.Name", "XXXXXX", ">=", Operation.GreaterThanOrEqual)] + [InlineData("Sample.Name", "XXXXXX", "<", Operation.LessThan)] + [InlineData("Sample.Name", "XXXXXX", "<=", Operation.LessThanOrEqual)] + [InlineData("Sample.Name", "XXXXXX", "@@", Operation.NONE)] + [InlineData("Sample.Name", "XXXXXX", ":!", Operation.NONE)] + [InlineData("Sample.Name", "XXXXXX", "=>", Operation.NONE)] + [InlineData("Sample.Name", "XXXXXX", "=<", Operation.NONE)] + public void Constructor_TripleString(string itemField, string? value, string? operation, Operation expected) + { + FilterObject filterObject = new FilterObject(itemField, value, operation); + Assert.Equal(expected, filterObject.Operation); + } + + #endregion + + #region MatchesEqual + + [Fact] + public void MatchesEqual_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12345" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.345" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesEqual_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.Equals); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + #endregion + + #region MatchesNotEqual + + [Fact] + public void MatchesNotEqual_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12345" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.345" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesNotEqual_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.NotEquals); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + #endregion + + #region MatchesGreaterThan + + [Fact] + public void MatchesGreaterThan_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThan_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThan_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThan_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12346" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesGreaterThan_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.346" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesGreaterThan_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThan_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.GreaterThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + #endregion + + #region MatchesGreaterThanOrEqual + + [Fact] + public void MatchesGreaterThanOrEqual_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12346" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.346" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesGreaterThanOrEqual_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.GreaterThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + #endregion + + #region MatchesLessThan + + [Fact] + public void MatchesLessThan_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThan_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThan_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThan_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12344" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesLessThan_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.344" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesLessThan_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThan_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.LessThan); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + #endregion + + #region MatchesLessThanOrEqual + + [Fact] + public void MatchesLessThanOrEqual_NoKey() + { + Sample sample = new Sample(); + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_NoValue() + { + Sample sample = new Sample { [Sample.NameKey] = null }; + FilterObject filterObject = new FilterObject("Sample.Name", null, Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_BoolValue() + { + Sample sample = new Sample { [Sample.NameKey] = "true" }; + FilterObject filterObject = new FilterObject("Sample.Name", "yes", Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_Int64Value() + { + Sample sample = new Sample { [Sample.NameKey] = "12344" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12345", Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_DoubleValue() + { + Sample sample = new Sample { [Sample.NameKey] = "12.344" }; + FilterObject filterObject = new FilterObject("Sample.Name", "12.345", Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.True(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_RegexValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "^XXXXXX$", Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + [Fact] + public void MatchesLessThanOrEqual_StringValue() + { + Sample sample = new Sample { [Sample.NameKey] = "XXXXXX" }; + FilterObject filterObject = new FilterObject("Sample.Name", "XXXXXX", Operation.LessThanOrEqual); + bool actual = filterObject.Matches(sample); + Assert.False(actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Filter/FilterRunnerTests.cs b/SabreTools.Core.Test/Filter/FilterRunnerTests.cs new file mode 100644 index 00000000..90af13ff --- /dev/null +++ b/SabreTools.Core.Test/Filter/FilterRunnerTests.cs @@ -0,0 +1,220 @@ +using SabreTools.Core.Filter; +using SabreTools.Models.Metadata; +using Xunit; + +namespace SabreTools.Core.Test.Filter +{ + public class FilterRunnerTests + { + private static readonly FilterRunner _filterRunner; + + static FilterRunnerTests() + { + FilterObject[] filters = + [ + new FilterObject("header.author", "auth", Operation.Equals), + new FilterObject("machine.description", "desc", Operation.Equals), + new FilterObject("item.name", "name", Operation.Equals), + new FilterObject("rom.crc", "crc", Operation.Equals), + ]; + + _filterRunner = new FilterRunner(filters); + } + + #region Header + + [Fact] + public void Header_Missing_False() + { + Header header = new Header(); + bool actual = _filterRunner.Run(header); + Assert.False(actual); + } + + [Fact] + public void Header_Null_False() + { + Header header = new Header { [Header.AuthorKey] = null }; + bool actual = _filterRunner.Run(header); + Assert.False(actual); + } + + [Fact] + public void Header_Empty_False() + { + Header header = new Header { [Header.AuthorKey] = "" }; + bool actual = _filterRunner.Run(header); + Assert.False(actual); + } + + [Fact] + public void Header_Incorrect_False() + { + Header header = new Header { [Header.AuthorKey] = "NO_MATCH" }; + bool actual = _filterRunner.Run(header); + Assert.False(actual); + } + + [Fact] + public void Header_Correct_True() + { + Header header = new Header { [Header.AuthorKey] = "auth" }; + bool actual = _filterRunner.Run(header); + Assert.True(actual); + } + + #endregion + + #region Machine + + [Fact] + public void Machine_Missing_False() + { + Machine machine = new Machine(); + bool actual = _filterRunner.Run(machine); + Assert.False(actual); + } + + [Fact] + public void Machine_Null_False() + { + Machine machine = new Machine { [Machine.DescriptionKey] = null }; + bool actual = _filterRunner.Run(machine); + Assert.False(actual); + } + + [Fact] + public void Machine_Empty_False() + { + Machine machine = new Machine { [Machine.DescriptionKey] = "" }; + bool actual = _filterRunner.Run(machine); + Assert.False(actual); + } + + [Fact] + public void Machine_Incorrect_False() + { + Machine machine = new Machine { [Machine.DescriptionKey] = "NO_MATCH" }; + bool actual = _filterRunner.Run(machine); + Assert.False(actual); + } + + [Fact] + public void Machine_Correct_True() + { + Machine machine = new Machine { [Machine.DescriptionKey] = "desc" }; + bool actual = _filterRunner.Run(machine); + Assert.True(actual); + } + + #endregion + + #region DatItem (General) + + [Fact] + public void DatItem_Missing_False() + { + DatItem datItem = new Sample(); + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void DatItem_Null_False() + { + DatItem datItem = new Sample { [Sample.NameKey] = null }; + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void DatItem_Empty_False() + { + DatItem datItem = new Sample { [Sample.NameKey] = "" }; + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void DatItem_Incorrect_False() + { + DatItem datItem = new Sample { [Sample.NameKey] = "NO_MATCH" }; + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void DatItem_Correct_True() + { + DatItem datItem = new Sample { [Sample.NameKey] = "name" }; + bool actual = _filterRunner.Run(datItem); + Assert.True(actual); + } + + #endregion + + #region DatItem (Specific) + + [Fact] + public void Rom_Missing_False() + { + DatItem datItem = new Rom(); + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void Rom_Null_False() + { + DatItem datItem = new Rom + { + [Rom.NameKey] = "name", + [Rom.CRCKey] = null, + }; + + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void Rom_Empty_False() + { + DatItem datItem = new Rom + { + [Rom.NameKey] = "name", + [Rom.CRCKey] = "", + }; + + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void Rom_Incorrect_False() + { + DatItem datItem = new Rom + { + [Rom.NameKey] = "name", + [Rom.CRCKey] = "NO_MATCH", + }; + + bool actual = _filterRunner.Run(datItem); + Assert.False(actual); + } + + [Fact] + public void Rom_Correct_True() + { + DatItem datItem = new Rom + { + [Rom.NameKey] = "name", + [Rom.CRCKey] = "crc", + }; + + bool actual = _filterRunner.Run(datItem); + Assert.True(actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/SabreTools.Core.Test.csproj b/SabreTools.Core.Test/SabreTools.Core.Test.csproj new file mode 100644 index 00000000..d89654b2 --- /dev/null +++ b/SabreTools.Core.Test/SabreTools.Core.Test.csproj @@ -0,0 +1,41 @@ + + + + net6.0;net8.0;net9.0 + false + latest + enable + + + + + + + + + + + + + + + Always + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + \ No newline at end of file diff --git a/SabreTools.Core.Test/TestData/extra.ini b/SabreTools.Core.Test/TestData/extra.ini new file mode 100644 index 00000000..2fe31da3 --- /dev/null +++ b/SabreTools.Core.Test/TestData/extra.ini @@ -0,0 +1,12 @@ +[FOLDER_SETTINGS] +RootFolderIcon mame +SubFolderIcon folder + +[ROOT_FOLDER] +useBool + +[Value] +useValue + +[Other] +useOther diff --git a/SabreTools.Test/Core/ConvertersTests.cs b/SabreTools.Core.Test/Tools/ConvertersTests.cs similarity index 97% rename from SabreTools.Test/Core/ConvertersTests.cs rename to SabreTools.Core.Test/Tools/ConvertersTests.cs index e0954d77..97006bc2 100644 --- a/SabreTools.Test/Core/ConvertersTests.cs +++ b/SabreTools.Core.Test/Tools/ConvertersTests.cs @@ -3,8 +3,9 @@ using SabreTools.DatFiles; using SabreTools.DatItems; using Xunit; -namespace SabreTools.Test.Core +namespace SabreTools.Core.Test.Tools { + // TODO: Remove reliance on anything but SabreTools.Core public class ConvertersTests { #region String to Enum @@ -357,6 +358,19 @@ namespace SabreTools.Test.Core Assert.Equal(expected, actual); } + [Theory] + [InlineData(null, null)] + [InlineData("INVALID", null)] + [InlineData("yes", true)] + [InlineData("True", true)] + [InlineData("no", false)] + [InlineData("False", false)] + public void AsYesNoTest(string? field, bool? expected) + { + bool? actual = field.AsYesNo(); + Assert.Equal(expected, actual); + } + #endregion #region Enum to String @@ -708,6 +722,16 @@ namespace SabreTools.Test.Core Assert.Equal(expected, actual); } + [Theory] + [InlineData(null, null)] + [InlineData(true, "yes")] + [InlineData(false, "no")] + public void FromYesNo(bool? field, string? expected) + { + string? actual = field.FromYesNo(); + Assert.Equal(expected, actual); + } + #endregion #region Generators diff --git a/SabreTools.Core.Test/Tools/DateTimeHelperTests.cs b/SabreTools.Core.Test/Tools/DateTimeHelperTests.cs new file mode 100644 index 00000000..f26f4b99 --- /dev/null +++ b/SabreTools.Core.Test/Tools/DateTimeHelperTests.cs @@ -0,0 +1,65 @@ +using System; +using SabreTools.Core.Tools; +using Xunit; + +namespace SabreTools.Core.Test.Tools +{ + public class DateTimeHelperTests + { + #region ConvertToMsDosTimeFormat + + [Fact] + public void ConvertToMsDosTimeFormat_MinSupported() + { + long expected = 2162688; + DateTime dateTime = new DateTime(1980, 01, 01, 00, 00, 00, 00); + long actual = DateTimeHelper.ConvertToMsDosTimeFormat(dateTime); + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertToMsDosTimeFormat_Y2K() + { + long expected = 673251328; + DateTime dateTime = new DateTime(2000, 01, 01, 00, 00, 00, 00); + long actual = DateTimeHelper.ConvertToMsDosTimeFormat(dateTime); + Assert.Equal(expected, actual); + } + + #endregion + + #region ConvertFromMsDosTimeFormat + + [Fact] + public void ConvertFromMsDosTimeFormat_MinSupported() + { + uint msDosDateTime = 2162688; + DateTime actual = DateTimeHelper.ConvertFromMsDosTimeFormat(msDosDateTime); + + Assert.Equal(1980, actual.Year); + Assert.Equal(01, actual.Month); + Assert.Equal(01, actual.Day); + Assert.Equal(00, actual.Hour); + Assert.Equal(00, actual.Minute); + Assert.Equal(00, actual.Second); + Assert.Equal(000, actual.Millisecond); + } + + [Fact] + public void ConvertFromMsDosTimeFormat_Y2K() + { + uint msDosDateTime = 673251328; + DateTime actual = DateTimeHelper.ConvertFromMsDosTimeFormat(msDosDateTime); + + Assert.Equal(2000, actual.Year); + Assert.Equal(01, actual.Month); + Assert.Equal(01, actual.Day); + Assert.Equal(00, actual.Hour); + Assert.Equal(00, actual.Minute); + Assert.Equal(00, actual.Second); + Assert.Equal(000, actual.Millisecond); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Tools/NumberHelperTests.cs b/SabreTools.Core.Test/Tools/NumberHelperTests.cs new file mode 100644 index 00000000..07ea1dcf --- /dev/null +++ b/SabreTools.Core.Test/Tools/NumberHelperTests.cs @@ -0,0 +1,106 @@ +using System; +using SabreTools.Core.Tools; +using Xunit; + +namespace SabreTools.Core.Test.Tools +{ + public class NumberHelperTests + { + #region ConvertToDouble + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("INVALID")] + public void ConvertToDoubleTest_NullExpected(string? numeric) + { + double? actual = NumberHelper.ConvertToDouble(numeric); + Assert.Null(actual); + } + + [Theory] + [InlineData("0", 0f)] + [InlineData("100", 100f)] + [InlineData("-100", -100f)] + [InlineData("3.14", 3.14f)] + [InlineData("-3.14", -3.14f)] + public void ConvertToDoubleTest_NumericExpected(string? numeric, double expected) + { + double? actual = NumberHelper.ConvertToDouble(numeric); + Assert.NotNull(actual); + double variance = Math.Abs(expected - actual.Value); + Assert.True(variance < 0.1f); + } + + #endregion + + #region ConvertToInt64 + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("INVALID")] + [InlineData("0b0001")] + [InlineData("0o765")] + [InlineData("01h")] + public void ConvertToInt64_NullExpected(string? numeric) + { + long? actual = NumberHelper.ConvertToInt64(numeric); + Assert.Null(actual); + } + + [Theory] + [InlineData("0", 0)] + [InlineData(" 0 ", 0)] + [InlineData("100", 100)] + [InlineData("-100", -100)] + [InlineData("0x01", 1)] + [InlineData("1k", 1_000)] + [InlineData("1ki", 1_024)] + [InlineData("1m", 1_000_000)] + [InlineData("1mi", 1_048_576)] + [InlineData("1g", 1_000_000_000)] + [InlineData("1gi", 1_073_741_824)] + [InlineData("1t", 1_000_000_000_000)] + [InlineData("1ti", 1_099_511_627_776)] + [InlineData("1p", 1_000_000_000_000_000)] + [InlineData("1pi", 1_125_899_906_842_624)] + // [InlineData("1e", 1_000_000_000_000_000_000)] + // [InlineData("1ei", 1_152_921_504_606_846_976)] + // [InlineData("1z", 1_000_000_000_000_000_000_000)] + // [InlineData("1zi", 1_180_591_620_717_411_303_424)] + // [InlineData("1y", 1_000_000_000_000_000_000_000_000)] + // [InlineData("1yi", 1_208_925_819_614_629_174_706_176)] + public void ConvertToInt64_NumericExpected(string? numeric, long expected) + { + long? actual = NumberHelper.ConvertToInt64(numeric); + Assert.NotNull(actual); + Assert.Equal(expected, actual); + } + + #endregion + + #region IsNumeric + + [Theory] + [InlineData(null, false)] + [InlineData("", false)] + [InlineData("0x", false)] + [InlineData("0", true)] + [InlineData("100", true)] + [InlineData("-100", true)] + [InlineData("3.14", true)] + [InlineData("-3.14", true)] + [InlineData("1,000", true)] + [InlineData("-1,000", true)] + [InlineData("1k", true)] + [InlineData("1ki", true)] + public void IsNumericTest(string? value, bool expected) + { + bool actual = NumberHelper.IsNumeric(value); + Assert.Equal(expected, actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Tools/TextHelperTests.cs b/SabreTools.Core.Test/Tools/TextHelperTests.cs new file mode 100644 index 00000000..f41680a3 --- /dev/null +++ b/SabreTools.Core.Test/Tools/TextHelperTests.cs @@ -0,0 +1,186 @@ +using SabreTools.Core.Tools; +using Xunit; + +namespace SabreTools.Core.Test.Tools +{ + public class TextHelperTests + { + #region NormalizeCharacters + + // TODO: Write tests for NormalizeCharacters + + #endregion + + #region NormalizeCRC32 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "00001234")] + [InlineData("0x1234", "00001234")] + [InlineData("1234ABCDE", "")] + [InlineData("0x1234ABCDE", "")] + [InlineData("1234ABCD", "1234abcd")] + [InlineData("0x1234ABCD", "1234abcd")] + [InlineData("abcdefgh", "")] + [InlineData("0xabcdefgh", "")] + public void NormalizeCRC32Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeCRC32(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region NormalizeMD5 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "00000000000000000000000000001234")] + [InlineData("0x1234", "00000000000000000000000000001234")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd")] + [InlineData("abcdefghabcdefghabcdefghabcdefgh", "")] + [InlineData("0xabcdefghabcdefghabcdefghabcdefgh", "")] + public void NormalizeMD5Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeMD5(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region NormalizeSHA1 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "0000000000000000000000000000000000001234")] + [InlineData("0x1234", "0000000000000000000000000000000000001234")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("abcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + [InlineData("0xabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + public void NormalizeSHA1Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeSHA1(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region NormalizeSHA256 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "0000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("0x1234", "0000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + [InlineData("0xabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + public void NormalizeSHA256Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeSHA256(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region NormalizeSHA384 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("0x1234", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + [InlineData("0xabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + public void NormalizeSHA384Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeSHA384(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region NormalizeSHA512 + + [Theory] + [InlineData(null, null)] + [InlineData("", "")] + [InlineData("-", "")] + [InlineData("_", "")] + [InlineData("0x", "")] + [InlineData("1234", "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("0x1234", "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCDE", "")] + [InlineData("1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("0x1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234ABCD", "1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd")] + [InlineData("abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + [InlineData("0xabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh", "")] + public void NormalizeSHA512Test(string? hash, string? expected) + { + string? actual = TextHelper.NormalizeSHA512(hash); + Assert.Equal(expected, actual); + } + + #endregion + + #region RemovePathUnsafeCharacters + + [Theory] + [InlineData(null, "")] + [InlineData("", "")] + [InlineData("\0", "")] + public void RemovePathUnsafeCharactersTest(string? input, string expected) + { + string? actual = TextHelper.RemovePathUnsafeCharacters(input); + Assert.Equal(expected, actual); + } + + #endregion + + #region RemoveUnicodeCharacters + + [Theory] + [InlineData(null, "")] + [InlineData("", "")] + [InlineData("Ā", "")] + public void RemoveUnicodeCharactersTest(string? input, string expected) + { + string? actual = TextHelper.RemoveUnicodeCharacters(input); + Assert.Equal(expected, actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core.Test/Tools/UtilitiesTests.cs b/SabreTools.Core.Test/Tools/UtilitiesTests.cs new file mode 100644 index 00000000..4c93bd4b --- /dev/null +++ b/SabreTools.Core.Test/Tools/UtilitiesTests.cs @@ -0,0 +1,105 @@ +using SabreTools.Core.Tools; +using Xunit; + +namespace SabreTools.Core.Test.Tools +{ + public class UtilitiesTests + { + #region ConditionalHashEquals + + [Theory] + [InlineData(null, null, true)] + [InlineData(new byte[0], new byte[0], true)] + [InlineData(new byte[] { 0x01 }, new byte[0], true)] + [InlineData(new byte[0], new byte[] { 0x01 }, true)] + [InlineData(new byte[] { 0x01 }, new byte[] { 0x01 }, true)] + [InlineData(new byte[] { 0x01, 0x02 }, new byte[] { 0x01 }, false)] + [InlineData(new byte[] { 0x01 }, new byte[] { 0x01, 0x02 }, false)] + [InlineData(new byte[] { 0x01, 0x02 }, new byte[] { 0x02, 0x01 }, false)] + public void ConditionalHashEquals_Array(byte[]? firstHash, byte[]? secondHash, bool expected) + { + bool actual = Utilities.ConditionalHashEquals(firstHash, secondHash); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(null, null, true)] + [InlineData("", "", true)] + [InlineData("01", "", true)] + [InlineData("", "01", true)] + [InlineData("01", "01", true)] + [InlineData("0102", "01", false)] + [InlineData("01", "0102", false)] + [InlineData("0102", "0201", false)] + public void ConditionalHashEquals_String(string? firstHash, string? secondHash, bool expected) + { + bool actual = Utilities.ConditionalHashEquals(firstHash, secondHash); + Assert.Equal(expected, actual); + } + + #endregion + + #region GetDepotPath + + [Theory] + [InlineData(null, 0, null)] + [InlineData(null, 4, null)] + [InlineData(new byte[] { 0x12, 0x34, 0x56 }, 0, null)] + [InlineData(new byte[] { 0x12, 0x34, 0x56 }, 4, null)] + [InlineData(new byte[] { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }, -1, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + [InlineData(new byte[] { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }, 0, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + [InlineData(new byte[] { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }, 1, "da\\da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + public void GetDepotPath_Array(byte[]? hash, int depth, string? expected) + { + string? actual = Utilities.GetDepotPath(hash, depth); + if (System.IO.Path.DirectorySeparatorChar == '/') + expected = expected?.Replace('\\', '/'); + + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(null, 0, null)] + [InlineData(null, 4, null)] + [InlineData("123456", 0, null)] + [InlineData("123456", 4, null)] + [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", -1, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", 0, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", 1, "da\\da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] + public void GetDepotPath_String(string? hash, int depth, string? expected) + { + string? actual = Utilities.GetDepotPath(hash, depth); + if (System.IO.Path.DirectorySeparatorChar == '/') + expected = expected?.Replace('\\', '/'); + + Assert.Equal(expected, actual); + } + + #endregion + + #region HasValidDatExtension + + [Theory] + [InlineData(null, false)] + [InlineData("", false)] + [InlineData("no-extension", false)] + [InlineData("no-extension.", false)] + [InlineData("invalid.ext", false)] + [InlineData("invalid..ext", false)] + [InlineData("INVALID.EXT", false)] + [InlineData("INVALID..EXT", false)] + [InlineData(".dat", true)] + [InlineData(".DAT", true)] + [InlineData("valid_extension.dat", true)] + [InlineData("valid_extension..dat", true)] + [InlineData("valid_extension.DAT", true)] + [InlineData("valid_extension..DAT", true)] + public void HasValidDatExtensionTest(string? path, bool expected) + { + bool actual = Utilities.HasValidDatExtension(path); + Assert.Equal(expected, actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Core/DictionaryBaseExtensions.cs b/SabreTools.Core/DictionaryBaseExtensions.cs index b9df2cb2..9607b0c8 100644 --- a/SabreTools.Core/DictionaryBaseExtensions.cs +++ b/SabreTools.Core/DictionaryBaseExtensions.cs @@ -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 /// /// Get unique duplicate suffix on name collision /// - 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 /// /// Get unique duplicate suffix on name collision /// - 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 /// /// Get unique duplicate suffix on name collision /// - 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}"; diff --git a/SabreTools.Core/Filter/ExtraIniItem.cs b/SabreTools.Core/Filter/ExtraIniItem.cs index 0aad3d12..2cbc6d67 100644 --- a/SabreTools.Core/Filter/ExtraIniItem.cs +++ b/SabreTools.Core/Filter/ExtraIniItem.cs @@ -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 /// /// Item type and field to update with INI information /// - /// Formatted like "ItemName.FieldName" public readonly FilterKey Key; /// @@ -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 /// /// Populate the dictionary from an INI file /// - /// Path to INI file to populate from + /// Path to INI file to populate from /// /// 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. /// - 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; } diff --git a/SabreTools.Core/Filter/FilterKey.cs b/SabreTools.Core/Filter/FilterKey.cs index 84b68ed2..e7321ee5 100644 --- a/SabreTools.Core/Filter/FilterKey.cs +++ b/SabreTools.Core/Filter/FilterKey.cs @@ -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; diff --git a/SabreTools.Core/Filter/FilterObject.cs b/SabreTools.Core/Filter/FilterObject.cs index 4191bf62..a70ed76b 100644 --- a/SabreTools.Core/Filter/FilterObject.cs +++ b/SabreTools.Core/Filter/FilterObject.cs @@ -26,10 +26,10 @@ namespace SabreTools.Core.Filter /// 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 /// 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; } - /// - /// Convert a string to a Boolean - /// - 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, - }; - } - /// /// Derive an operation from the input string, if possible /// @@ -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; } diff --git a/SabreTools.Core/SabreTools.Core.csproj b/SabreTools.Core/SabreTools.Core.csproj index 4b1b8c27..4c9ba41b 100644 --- a/SabreTools.Core/SabreTools.Core.csproj +++ b/SabreTools.Core/SabreTools.Core.csproj @@ -22,7 +22,7 @@ - + diff --git a/SabreTools.Core/Tools/NumberHelper.cs b/SabreTools.Core/Tools/NumberHelper.cs index 3637fe13..c9675bda 100644 --- a/SabreTools.Core/Tools/NumberHelper.cs +++ b/SabreTools.Core/Tools/NumberHelper.cs @@ -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 diff --git a/SabreTools.Core/Tools/TextHelper.cs b/SabreTools.Core/Tools/TextHelper.cs index 5dadd54d..66088173 100644 --- a/SabreTools.Core/Tools/TextHelper.cs +++ b/SabreTools.Core/Tools/TextHelper.cs @@ -80,8 +80,14 @@ namespace SabreTools.Core.Tools } /// - /// Remove all unicode-specific chars from a string + /// Remove all Unicode-specific chars from a string /// + /// + /// "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. + /// 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 diff --git a/SabreTools.Test/Core/UtilitiesTests.cs b/SabreTools.Test/Core/UtilitiesTests.cs deleted file mode 100644 index d70cba7c..00000000 --- a/SabreTools.Test/Core/UtilitiesTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -using SabreTools.Core.Tools; -using Xunit; - -namespace SabreTools.Test.Core -{ - public class UtiltiesTests - { - [Theory] - [InlineData(null, null)] - [InlineData("null", null)] - [InlineData("0b00001", null)] - [InlineData("12345", 12345L)] - [InlineData("00000000012345", 12345L)] - [InlineData("10h", null)] - [InlineData("0x10", 16L)] - [InlineData(" 12345 ", 12345L)] - public void CleanLongTest(string? input, long? expected) - { - long? actual = NumberHelper.ConvertToInt64(input); - Assert.Equal(expected, actual); - } - - [Theory] - [InlineData(null, 0, null)] - [InlineData(null, 4, null)] - [InlineData("123456", 0, null)] - [InlineData("123456", 4, null)] - [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", -1, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] - [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", 0, "da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] - [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", 1, "da\\da39a3ee5e6b4b0d3255bfef95601890afd80709.gz")] - public void GetDepotPathTest(string? hash, int depth, string? expected) - { - string? actual = Utilities.GetDepotPath(hash, depth); - if (System.IO.Path.DirectorySeparatorChar == '/') - expected = expected?.Replace('\\', '/'); - - Assert.Equal(expected, actual); - } - - [Theory] - [InlineData(null, false)] - [InlineData("", false)] - [InlineData("no-extension", false)] - [InlineData("invalid.ext", false)] - [InlineData("INVALID.EXT", false)] - [InlineData("valid_extension.dat", true)] - [InlineData("valid_extension.DAT", true)] - public void HasValidDatExtensionTest(string? path, bool expected) - { - bool actual = Utilities.HasValidDatExtension(path); - Assert.Equal(expected, actual); - } - } -} \ No newline at end of file diff --git a/SabreTools.Test/Filter/FilteringTests.cs b/SabreTools.Test/Filter/FilteringTests.cs deleted file mode 100644 index 0b32b1ce..00000000 --- a/SabreTools.Test/Filter/FilteringTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -using SabreTools.Core.Filter; -using SabreTools.DatItems; -using SabreTools.DatItems.Formats; -using Xunit; - -namespace SabreTools.Test.Filter -{ - public class FilteringTests - { - [Fact] - public void PassesFiltersDatItemFilterPass() - { - // Setup filter - var filter = new FilterRunner(["rom.name:foo", "item.name:foo"]); - - // Setup DatItem - var datItem = CreateDatItem(); - - // Run filters - bool actual = datItem.PassesFilter(filter); - Assert.True(actual); - } - - [Fact] - public void PassesFiltersDatItemFilterFail() - { - // Setup filter - var filter = new FilterRunner(["rom.name:bar", "item.name:bar"]); - - // Setup DatItem - var datItem = CreateDatItem(); - - // Run filters - bool actual = datItem.PassesFilter(filter); - Assert.False(actual); - } - - [Fact] - public void PassesFiltersMachineFilterPass() - { - // Setup filter - var filter = new FilterRunner(["machine.name:bar"]); - - // Setup DatItem - var datItem = CreateDatItem(); - - // Run filters - bool actual = datItem.PassesFilter(filter); - Assert.True(actual); - } - - [Fact] - public void PassesFiltersMachineFilterFail() - { - // Setup filter - var filter = new FilterRunner(["machine.name:foo"]); - - // Setup DatItem - var datItem = CreateDatItem(); - - // Run filters - bool actual = datItem.PassesFilter(filter); - Assert.False(actual); - } - - /// - /// Generate a consistent DatItem for testing - /// - private static DatItem CreateDatItem() - { - var machine = new Machine(); - machine.SetFieldValue(Models.Metadata.Machine.NameKey, "bar"); - machine.SetFieldValue(Models.Metadata.Machine.DescriptionKey, "bar"); - - var rom = new Rom(); - rom.SetName("foo"); - rom.SetFieldValue(DatItem.MachineKey, machine); - - return rom; - } - } -} \ No newline at end of file diff --git a/SabreTools.Test/Filter/PopulationTests.cs b/SabreTools.Test/Filter/PopulationTests.cs deleted file mode 100644 index 1a4aea5a..00000000 --- a/SabreTools.Test/Filter/PopulationTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using SabreTools.Core.Filter; -using Xunit; - -namespace SabreTools.Test.Filter -{ - public class PopulationTests - { - [Fact] - public void PopulateFilterRunnerEmptyListTest() - { - // Setup the list - string[]? filters = []; - - // Setup the filter runner - var filterRunner = new FilterRunner(filters); - - // Check the filters - Assert.NotNull(filterRunner.Filters); - } - - [Fact] - public void PopulateFilterMachineFieldTest() - { - // Setup the list - string[] filters = - [ - "machine.name:foo", - "machine.name!:bar", - ]; - - // Setup the filter - var filter = new FilterRunner(filters); - - // Check the filters - Assert.Equal("machine.name", filter.Filters[0].Key.ToString()); - Assert.Equal("foo", filter.Filters[0].Value); - Assert.Equal(Operation.Equals, filter.Filters[0].Operation); - - Assert.Equal("machine.name", filter.Filters[1].Key.ToString()); - Assert.Equal("bar", filter.Filters[1].Value); - Assert.Equal(Operation.NotEquals, filter.Filters[1].Operation); - } - - [Fact] - public void PopulateFilterDatItemFieldTest() - { - // Setup the list - string[] filters = - [ - "rom.name:foo", - "datitem.name!:bar" - ]; - - // Setup the filter - var filter = new FilterRunner(filters); - - // Check the filters - Assert.Equal("rom.name", filter.Filters[0].Key.ToString()); - Assert.Equal("foo", filter.Filters[0].Value); - Assert.Equal(Operation.Equals, filter.Filters[0].Operation); - - Assert.Equal("item.name", filter.Filters[1].Key.ToString()); - Assert.Equal("bar", filter.Filters[1].Value); - Assert.Equal(Operation.NotEquals, filter.Filters[1].Operation); - } - } -} \ No newline at end of file diff --git a/SabreTools.sln b/SabreTools.sln index d25102e5..5b7d60a2 100644 --- a/SabreTools.sln +++ b/SabreTools.sln @@ -28,6 +28,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SabreTools.Reports", "Sabre EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SabreTools.Test", "SabreTools.Test\SabreTools.Test.csproj", "{5B4E67D5-F4DA-4750-8FE2-04D08E343791}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Core.Test", "SabreTools.Core.Test\SabreTools.Core.Test.csproj", "{33CF1613-2190-4987-8BE3-73AF196327D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -108,6 +110,14 @@ Global {5B4E67D5-F4DA-4750-8FE2-04D08E343791}.Release|Any CPU.Build.0 = Release|Any CPU {5B4E67D5-F4DA-4750-8FE2-04D08E343791}.Release|x64.ActiveCfg = Release|Any CPU {5B4E67D5-F4DA-4750-8FE2-04D08E343791}.Release|x64.Build.0 = Release|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Debug|x64.Build.0 = Debug|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Release|Any CPU.Build.0 = Release|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Release|x64.ActiveCfg = Release|Any CPU + {33CF1613-2190-4987-8BE3-73AF196327D3}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE