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
///