diff --git a/SabreTools.Core.Test/ModelBackedItemTests.cs b/SabreTools.Core.Test/ModelBackedItemTests.cs index 6f5317dc..861f1a8f 100644 --- a/SabreTools.Core.Test/ModelBackedItemTests.cs +++ b/SabreTools.Core.Test/ModelBackedItemTests.cs @@ -18,7 +18,142 @@ namespace SabreTools.Core.Test /// /// Testing implementation of ModelBackedItem /// - private class TestModelBackedItem : ModelBackedItem { } + private class TestModelBackedItem : ModelBackedItem + { + #region Comparision Methods + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not TestModelBackedItem otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not TestModelBackedItem otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + #endregion + } + + /// + /// Alternate testing implementation of ModelBackedItem + /// + private class TestModelAltBackedItem : ModelBackedItem + { + #region Comparision Methods + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not TestModelAltBackedItem otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not TestModelAltBackedItem otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + #endregion + } + + #endregion + + #region Equals + + [Fact] + public void Equals_NullOther_False() + { + ModelBackedItem self = new TestModelBackedItem(); + ModelBackedItem? other = null; + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_MismatchedType_False() + { + ModelBackedItem self = new TestModelBackedItem(); + ModelBackedItem? other = new TestModelAltBackedItem(); + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_MismatchedTypeAlt_False() + { + ModelBackedItem self = new TestModelAltBackedItem(); + ModelBackedItem? other = new TestModelBackedItem(); + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_DifferentModels_False() + { + ModelBackedItem self = new TestModelBackedItem(); + self.SetFieldValue(TestDictionaryBase.NameKey, "self"); + + ModelBackedItem? other = new TestModelBackedItem(); + other.SetFieldValue(TestDictionaryBase.NameKey, "other"); + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_EqualModels_True() + { + ModelBackedItem self = new TestModelBackedItem(); + self.SetFieldValue(TestDictionaryBase.NameKey, "name"); + + ModelBackedItem? other = new TestModelBackedItem(); + other.SetFieldValue(TestDictionaryBase.NameKey, "name"); + + bool actual = self.Equals(other); + Assert.True(actual); + } #endregion diff --git a/SabreTools.Core/DictionaryBaseExtensions.cs b/SabreTools.Core/DictionaryBaseExtensions.cs index 9607b0c8..e2232018 100644 --- a/SabreTools.Core/DictionaryBaseExtensions.cs +++ b/SabreTools.Core/DictionaryBaseExtensions.cs @@ -163,6 +163,11 @@ namespace SabreTools.Core return false; break; + case (ModelBackedItem selfMbi, ModelBackedItem otherMbi): + if (!selfMbi.Equals(otherMbi)) + return false; + break; + case (DictionaryBase selfDb, DictionaryBase otherDb): if (!selfDb.Equals(otherDb)) return false; diff --git a/SabreTools.Core/ModelBackedItem.cs b/SabreTools.Core/ModelBackedItem.cs index bdd0580b..55564d79 100644 --- a/SabreTools.Core/ModelBackedItem.cs +++ b/SabreTools.Core/ModelBackedItem.cs @@ -8,7 +8,20 @@ namespace SabreTools.Core /// /// Represents an item that's backed by a DictionaryBase item /// - public abstract class ModelBackedItem where T : Models.Metadata.DictionaryBase + public abstract class ModelBackedItem : IEquatable + { + #region Comparision Methods + + /// + public abstract bool Equals(ModelBackedItem? other); + + #endregion + } + + /// + /// Represents an item that's backed by a DictionaryBase item + /// + public abstract class ModelBackedItem : ModelBackedItem, IEquatable> where T : Models.Metadata.DictionaryBase { /// /// Internal model wrapped by this DatItem @@ -150,6 +163,13 @@ namespace SabreTools.Core #endregion + #region Comparision Methods + + /// + public abstract bool Equals(ModelBackedItem? other); + + #endregion + #region Manipulation /// diff --git a/SabreTools.DatFiles/DatHeader.cs b/SabreTools.DatFiles/DatHeader.cs index e4f904e5..8d2f8cdc 100644 --- a/SabreTools.DatFiles/DatHeader.cs +++ b/SabreTools.DatFiles/DatHeader.cs @@ -370,6 +370,40 @@ namespace SabreTools.DatFiles #endregion + #region Comparision Methods + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatHeader otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatHeader otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + #endregion + #region Manipulation /// diff --git a/SabreTools.DatItems.Test/DatItemTests.cs b/SabreTools.DatItems.Test/DatItemTests.cs index 5a7e5959..1c000a01 100644 --- a/SabreTools.DatItems.Test/DatItemTests.cs +++ b/SabreTools.DatItems.Test/DatItemTests.cs @@ -5,6 +5,28 @@ namespace SabreTools.DatItems.Test { public class DatItemTests { + #region Private Testing Classes + + /// + /// Testing implementation of Models.Metadata.DatItem + /// + private class TestDatItemModel : Models.Metadata.DatItem + { + public const string NameKey = "__NAME__"; + } + + /// + /// Testing implementation of DatItem + /// + private class TestDatItem : DatItem + { + protected override string? NameKey => TestDatItemModel.NameKey; + + protected override ItemType ItemType => ItemType.Blank; + } + + #endregion + #region CopyMachineInformation [Fact] @@ -186,7 +208,61 @@ namespace SabreTools.DatItems.Test #region Equals - // TODO: Implement Equals tests + [Fact] + public void Equals_Null_False() + { + DatItem self = new TestDatItem(); + DatItem? other = null; + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_MismatchedType_False() + { + DatItem self = new TestDatItem(); + DatItem? other = new Rom(); + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_DefaultInternal_True() + { + DatItem self = new TestDatItem(); + DatItem? other = new TestDatItem(); + + bool actual = self.Equals(other); + Assert.True(actual); + } + + [Fact] + public void Equals_MismatchedInternal_False() + { + DatItem self = new TestDatItem(); + self.SetName("self"); + + DatItem? other = new TestDatItem(); + other.SetName("other"); + + bool actual = self.Equals(other); + Assert.False(actual); + } + + [Fact] + public void Equals_EqualInternal_True() + { + DatItem self = new TestDatItem(); + self.SetName("name"); + + DatItem? other = new TestDatItem(); + other.SetName("name"); + + bool actual = self.Equals(other); + Assert.True(actual); + } #endregion diff --git a/SabreTools.DatItems/DatItem.cs b/SabreTools.DatItems/DatItem.cs index dd14365a..f865320e 100644 --- a/SabreTools.DatItems/DatItem.cs +++ b/SabreTools.DatItems/DatItem.cs @@ -181,8 +181,16 @@ namespace SabreTools.DatItems /// True if the items are duplicates, false otherwise public virtual bool Equals(DatItem? other) { + // If the other item is null + if (other == null) + return false; + + // Get the types for comparison + ItemType selfType = GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue(); + ItemType otherType = other.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue(); + // If we don't have a matched type, return false - if (GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue() != other?.GetStringFieldValue(Models.Metadata.DatItem.TypeKey).AsEnumValue()) + if (selfType != otherType) return false; // Compare the internal models @@ -564,6 +572,36 @@ namespace SabreTools.DatItems return string.Compare(selfName, otherName, StringComparison.Ordinal); } + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return _internal.Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return _internal.Equals(otherItem); + } + /// /// Determine if an item is a duplicate using partial matching logic /// diff --git a/SabreTools.DatItems/Formats/Blank.cs b/SabreTools.DatItems/Formats/Blank.cs index 43f553e2..3fdbc0e6 100644 --- a/SabreTools.DatItems/Formats/Blank.cs +++ b/SabreTools.DatItems/Formats/Blank.cs @@ -1,5 +1,6 @@ using System.Xml.Serialization; using Newtonsoft.Json; +using SabreTools.Core; using SabreTools.Core.Tools; namespace SabreTools.DatItems.Formats @@ -47,6 +48,36 @@ namespace SabreTools.DatItems.Formats #region Comparision Methods + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + /// public override bool Equals(DatItem? other) { diff --git a/SabreTools.DatItems/Formats/File.cs b/SabreTools.DatItems/Formats/File.cs index b288a56f..1c6768c8 100644 --- a/SabreTools.DatItems/Formats/File.cs +++ b/SabreTools.DatItems/Formats/File.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Xml.Serialization; using Newtonsoft.Json; +using SabreTools.Core; using SabreTools.Core.Tools; using SabreTools.Hashing; using SabreTools.IO.Extensions; @@ -154,6 +155,36 @@ namespace SabreTools.DatItems.Formats #region Comparision Methods + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + /// public override bool Equals(DatItem? other) { diff --git a/SabreTools.DatItems/Formats/ReleaseDetails.cs b/SabreTools.DatItems/Formats/ReleaseDetails.cs index 7b19d40d..c1177b50 100644 --- a/SabreTools.DatItems/Formats/ReleaseDetails.cs +++ b/SabreTools.DatItems/Formats/ReleaseDetails.cs @@ -1,5 +1,6 @@ using System.Xml.Serialization; using Newtonsoft.Json; +using SabreTools.Core; using SabreTools.Core.Tools; // TODO: Add item mappings for all fields @@ -157,6 +158,36 @@ namespace SabreTools.DatItems.Formats #region Comparision Methods + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + /// public override bool Equals(DatItem? other) { diff --git a/SabreTools.DatItems/Formats/Serials.cs b/SabreTools.DatItems/Formats/Serials.cs index 65ec412b..83baa0b7 100644 --- a/SabreTools.DatItems/Formats/Serials.cs +++ b/SabreTools.DatItems/Formats/Serials.cs @@ -1,5 +1,6 @@ using System.Xml.Serialization; using Newtonsoft.Json; +using SabreTools.Core; using SabreTools.Core.Tools; // TODO: Add item mappings for all fields @@ -149,6 +150,36 @@ namespace SabreTools.DatItems.Formats #region Comparision Methods + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + /// public override bool Equals(DatItem? other) { diff --git a/SabreTools.DatItems/Formats/SourceDetails.cs b/SabreTools.DatItems/Formats/SourceDetails.cs index 3af65a9e..241e63bb 100644 --- a/SabreTools.DatItems/Formats/SourceDetails.cs +++ b/SabreTools.DatItems/Formats/SourceDetails.cs @@ -1,5 +1,6 @@ using System.Xml.Serialization; using Newtonsoft.Json; +using SabreTools.Core; using SabreTools.Core.Tools; // TODO: Add item mappings for all fields @@ -192,6 +193,36 @@ namespace SabreTools.DatItems.Formats #region Comparision Methods + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not DatItem otherItem) + return false; + + // Compare internal models + return Equals(otherItem); + } + /// public override bool Equals(DatItem? other) { diff --git a/SabreTools.DatItems/Machine.cs b/SabreTools.DatItems/Machine.cs index c30cd6fd..1b4f8d74 100644 --- a/SabreTools.DatItems/Machine.cs +++ b/SabreTools.DatItems/Machine.cs @@ -82,6 +82,40 @@ namespace SabreTools.DatItems #endregion + #region Comparision Methods + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not Machine otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + /// + public override bool Equals(ModelBackedItem? other) + { + // If other is null + if (other == null) + return false; + + // If the type is mismatched + if (other is not Machine otherItem) + return false; + + // Compare internal models + return _internal.EqualTo(otherItem._internal); + } + + #endregion + #region Manipulation ///