From 2c9fa293d73b2b6c1c24638b7f0c8c75033621ba Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 12:12:23 +0100 Subject: [PATCH 1/8] Fix hashcode --- .../Classification/DataClassificationSet.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs index 6a041e49524..70b4f7a0cfb 100644 --- a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs +++ b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs @@ -83,7 +83,16 @@ public DataClassificationSet Union(DataClassificationSet other) /// Gets a hash code for the current object instance. /// /// The hash code value. - public override int GetHashCode() => _classifications.GetHashCode(); + public override int GetHashCode() + { + int hash = 0; + foreach (var item in _classifications) + { + hash ^= item.GetHashCode(); + } + + return hash; + } /// /// Compares an object with the current instance to see if they contain the same classifications. From 443e430eeafcd2d5ba9ef13842331a4e74982b0b Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 16:58:03 +0100 Subject: [PATCH 2/8] Fix tests --- test/Generators/Microsoft.Gen.Logging/Generated/Utils.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/Utils.cs b/test/Generators/Microsoft.Gen.Logging/Generated/Utils.cs index abbb3225b8b..f90a504d31e 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/Utils.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/Utils.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Compliance.Classification; using Microsoft.Extensions.Compliance.Redaction; using Microsoft.Extensions.Compliance.Testing; using Microsoft.Extensions.DependencyInjection; @@ -82,7 +83,7 @@ public static TestLogger GetLogger() { builder.SetRedactor(new PublicDataAttribute().Classification); builder.SetRedactor(new PrivateDataAttribute().Classification); - builder.SetRedactor(new PrivateDataAttribute().Classification, new PublicDataAttribute().Classification); + builder.SetRedactor(new DataClassificationSet(new PrivateDataAttribute().Classification, new PublicDataAttribute().Classification)); builder.SetFallbackRedactor(); }); From 3b043ea92f8f389880d048e1145cdb87ff4b52f6 Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 17:00:51 +0100 Subject: [PATCH 3/8] Add HashCode test --- .../Classification/DataClassificationSetTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs b/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs index 37b91bc9c75..e57806a8459 100644 --- a/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs +++ b/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs @@ -30,4 +30,19 @@ public static void Basic() Assert.False(dc1.Equals(null)); #pragma warning restore CA1508 // Avoid dead conditional code } + + [Fact] + public static void TestHashCodes() + { + var dc1 = new DataClassificationSet(FakeTaxonomy.PublicData); + var dc2 = new DataClassificationSet(new[] { FakeTaxonomy.PublicData }); + var dc3 = new DataClassificationSet(new List { FakeTaxonomy.PublicData }); + var dc4 = (DataClassificationSet)FakeTaxonomy.PublicData; + var dc5 = DataClassificationSet.FromDataClassification(FakeTaxonomy.PublicData); + + Assert.Equal(dc1.GetHashCode(), dc2.GetHashCode()); + Assert.Equal(dc1.GetHashCode(), dc3.GetHashCode()); + Assert.Equal(dc1.GetHashCode(), dc4.GetHashCode()); + Assert.Equal(dc1.GetHashCode(), dc5.GetHashCode()); + } } From 14b49bd034aeea2dfafa414276230f0db8ec0f17 Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 17:02:46 +0100 Subject: [PATCH 4/8] Add inequality assertion for completeness --- .../Classification/DataClassificationSetTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs b/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs index e57806a8459..921139049a0 100644 --- a/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs +++ b/test/Libraries/Microsoft.Extensions.Compliance.Abstractions.Tests/Classification/DataClassificationSetTests.cs @@ -44,5 +44,8 @@ public static void TestHashCodes() Assert.Equal(dc1.GetHashCode(), dc3.GetHashCode()); Assert.Equal(dc1.GetHashCode(), dc4.GetHashCode()); Assert.Equal(dc1.GetHashCode(), dc5.GetHashCode()); + + var dc6 = dc1.Union(FakeTaxonomy.PrivateData); + Assert.NotEqual(dc1, dc6); } } From d22a1fe4083911508a56f029656a4ec4c6e48cfb Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 18:24:04 +0100 Subject: [PATCH 5/8] Add RedactorProviderTest with HashCode considerations --- .../RedactorProviderTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs b/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs index 550058c7901..b9e61a024ae 100644 --- a/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs @@ -3,6 +3,7 @@ using System; using Microsoft.Extensions.Compliance.Classification; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.Extensions.Compliance.Redaction.Test; @@ -46,6 +47,46 @@ public void RedactorProvider_Returns_Redactor_For_Data_Classifications() Assert.Equal(typeof(ErasingRedactor), r3.GetType()); } + [Fact] + public void RedactorProvider_Returns_Redactor_For_Logically_Same_Data_Classification() + { + var dc1 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification")); + var dc2 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification2")); + var dc3 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification3")); + var dc4 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification4")); + var dc5 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification5")); + var dc6 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification6")); + var dc7 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification7")); + var dc8 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification8")); + + var dc9 = new DataClassification("DummyTaxonomy", "Classification9"); + + var dc1LogicalCopy = new DataClassificationSet(new[] { new DataClassification("DummyTaxonomy", "Classification") }); + + var redactorProvider = new ServiceCollection() + .AddRedaction(redaction => + { + redaction.SetRedactor(dc1); + redaction.SetRedactor(dc2); + redaction.SetRedactor(dc3); + redaction.SetRedactor(dc4); + redaction.SetRedactor(dc5); + redaction.SetRedactor(dc6); + redaction.SetRedactor(dc7); + redaction.SetRedactor(dc8); + }) + .BuildServiceProvider() + .GetRequiredService(); + + var r1 = redactorProvider.GetRedactor(dc1); + var r2 = redactorProvider.GetRedactor(dc1LogicalCopy); + var r3 = redactorProvider.GetRedactor(dc9); + + Assert.Equal(typeof(NullRedactor), r1.GetType()); + Assert.Equal(typeof(NullRedactor), r2.GetType()); + Assert.Equal(typeof(ErasingRedactor), r3.GetType()); + } + [Fact] public void RedactorProvider_Throws_On_Ctor_When_Options_Come_As_Null() { From d793d7f3663a9033d6be9f2148ec4aeed8546a28 Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Fri, 9 Feb 2024 18:24:55 +0100 Subject: [PATCH 6/8] Better test name --- .../RedactorProviderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs b/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs index b9e61a024ae..0a7c97f34f1 100644 --- a/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Compliance.Redaction.Tests/RedactorProviderTests.cs @@ -48,7 +48,7 @@ public void RedactorProvider_Returns_Redactor_For_Data_Classifications() } [Fact] - public void RedactorProvider_Returns_Redactor_For_Logically_Same_Data_Classification() + public void RedactorProvider_Returns_Same_Redactor_For_Logically_Same_Data_Classification() { var dc1 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification")); var dc2 = new DataClassificationSet(new DataClassification("DummyTaxonomy", "Classification2")); From 02731c4f85c6d08f02825ce616c3eee5f04aae90 Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Sun, 11 Feb 2024 18:51:00 +0100 Subject: [PATCH 7/8] Add hashcode caching --- .../Classification/DataClassificationSet.cs | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs index 70b4f7a0cfb..ca258d35d6e 100644 --- a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs +++ b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs @@ -15,6 +15,7 @@ namespace Microsoft.Extensions.Compliance.Classification; public sealed class DataClassificationSet : IEquatable { private readonly HashSet _classifications = []; + private readonly int _cachedHashCode; /// /// Initializes a new instance of the class. @@ -23,6 +24,7 @@ public sealed class DataClassificationSet : IEquatable public DataClassificationSet(DataClassification classification) { _ = _classifications.Add(classification); + _cachedHashCode = ComputeHashCode(); } /// @@ -33,6 +35,7 @@ public DataClassificationSet(IEnumerable classifications) { _ = Throw.IfNull(classifications); _classifications.UnionWith(classifications); + _cachedHashCode = ComputeHashCode(); } /// @@ -43,6 +46,7 @@ public DataClassificationSet(params DataClassification[] classifications) { _ = Throw.IfNull(classifications); _classifications.UnionWith(classifications); + _cachedHashCode = ComputeHashCode(); } /// @@ -73,26 +77,17 @@ public DataClassificationSet Union(DataClassificationSet other) { _ = Throw.IfNull(other); - var result = new DataClassificationSet(other._classifications); - result._classifications.UnionWith(_classifications); + var combinedClassifications = new HashSet(_classifications); + combinedClassifications.UnionWith(other._classifications); - return result; + return new DataClassificationSet(combinedClassifications); } /// /// Gets a hash code for the current object instance. /// /// The hash code value. - public override int GetHashCode() - { - int hash = 0; - foreach (var item in _classifications) - { - hash ^= item.GetHashCode(); - } - - return hash; - } + public override int GetHashCode() => _cachedHashCode; /// /// Compares an object with the current instance to see if they contain the same classifications. @@ -140,4 +135,28 @@ public override string ToString() return result; } + + /// + /// Computes the hash code for the current object instance. + /// + /// The computed hash code. + private int ComputeHashCode() + { +#if NETFRAMEWORK + int hash = 0; + foreach (var item in _classifications) + { + hash ^= item.GetHashCode(); + } + return hash; +#else + var hash = default(HashCode); + foreach (var item in _classifications) + { + hash.Add(item); + } + + return hash.ToHashCode(); +#endif + } } From d75035c311d8e02bf2654026751dd6aabfb6f58e Mon Sep 17 00:00:00 2001 From: Damian Horna Date: Sun, 11 Feb 2024 19:01:36 +0100 Subject: [PATCH 8/8] Fix warning --- .../Classification/DataClassificationSet.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs index ca258d35d6e..3fb3ce652c9 100644 --- a/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs +++ b/src/Libraries/Microsoft.Extensions.Compliance.Abstractions/Classification/DataClassificationSet.cs @@ -148,6 +148,7 @@ private int ComputeHashCode() { hash ^= item.GetHashCode(); } + return hash; #else var hash = default(HashCode);