From f8688161fa958f31c1a234e8b7d765c473ee46fe Mon Sep 17 00:00:00 2001 From: Helen Zhang Date: Wed, 2 Apr 2025 11:06:42 -0700 Subject: [PATCH 1/5] Fix serialization --- .../Metadata/PluginMetadata.cs | 6 ++--- .../PluginIdentity.cs | 2 +- .../PluginVersionJsonConverter.cs | 8 ++++++- .../Serialization/SemanticVersionConverter.cs | 5 ++++ .../Serialization/SerializationUtils.cs | 23 ++----------------- .../Manifest/PluginIdentityManifest.cs | 1 - .../Program.cs | 4 ++++ 7 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs index 2ba15e168..711c00799 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs @@ -1,12 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Microsoft.Performance.SDK; +using NuGet.Versioning; using System; using System.Collections.Generic; using System.Text.Json.Serialization; -using Microsoft.Performance.SDK; -using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; -using NuGet.Versioning; namespace Microsoft.Performance.Toolkit.Plugins.Core.Metadata { @@ -87,7 +86,6 @@ public PluginMetadata( /// /// Gets the version of the performance SDK which this plugin depends upon. /// - [JsonConverter(typeof(SemanticVersionJsonConverter))] public SemanticVersion SdkVersion { get; } /// diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs index 590f8aa2d..8dd53b01a 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs @@ -36,7 +36,7 @@ public PluginIdentity(string id, PluginVersion version) } /// - /// Gets the identifer of this plugin. + /// Gets the identifier of this plugin. /// public string Id { get; } diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs index ee63a5b8d..8a988f175 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs @@ -7,13 +7,19 @@ namespace Microsoft.Performance.Toolkit.Plugins.Core.Serialization { + /// + /// Converts a to and from JSON. + /// public class PluginVersionJsonConverter : JsonConverter { + /// public override PluginVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { + { var versionString = reader.GetString(); return versionString is null ? null : PluginVersion.Parse(versionString); } + + /// public override void Write(Utf8JsonWriter writer, PluginVersion value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SemanticVersionConverter.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SemanticVersionConverter.cs index 81402f99f..7eee49a14 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SemanticVersionConverter.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SemanticVersionConverter.cs @@ -8,14 +8,19 @@ namespace Microsoft.Performance.Toolkit.Plugins.Core.Serialization { + /// + /// Converts a to and from JSON. + /// public class SemanticVersionJsonConverter : JsonConverter { + /// public override SemanticVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var versionString = reader.GetString(); return versionString is null ? null : SemanticVersion.Parse(versionString); } + /// public override void Write(Utf8JsonWriter writer, SemanticVersion value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SerializationUtils.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SerializationUtils.cs index 81dfe12f4..ae9f6d476 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SerializationUtils.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/SerializationUtils.cs @@ -54,28 +54,9 @@ public static ISerializer GetJsonSerializer(JsonSerializerOptions serializ Converters = { new JsonStringEnumConverter(), - new VersionStringConverter(), + new PluginVersionJsonConverter(), + new SemanticVersionJsonConverter(), } }; - - internal class VersionStringConverter - : JsonConverter - { - public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - { - string stringValue = reader.GetString(); - return new Version(stringValue); - } - - throw new JsonException(); - } - - public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToString()); - } - } } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs index a0e87ae72..9de2b3775 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs @@ -37,7 +37,6 @@ public PluginIdentityManifest( /// /// Gets or sets the version of this plugin. /// - [JsonConverter(typeof(PluginVersionJsonConverter))] public PluginVersion Version { get; } } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs index 40ba0ec27..446c151d6 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs @@ -51,6 +51,10 @@ private static PluginsCli CreatPluginsCli() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new PluginVersionJsonConverter(), + } })) .AddSingleton>(SerializationUtils.GetJsonSerializerWithDefaultOptions()) .AddSingleton>(SerializationUtils.GetJsonSerializerWithDefaultOptions()) From 333ec01a78e700329cd7e17730942bb871f6dbee Mon Sep 17 00:00:00 2001 From: Helen Zhang Date: Wed, 2 Apr 2025 11:09:32 -0700 Subject: [PATCH 2/5] Remove white space --- .../Serialization/PluginVersionJsonConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs index 8a988f175..3cc7f68cd 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Serialization/PluginVersionJsonConverter.cs @@ -14,7 +14,7 @@ public class PluginVersionJsonConverter : JsonConverter { /// public override PluginVersion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { + { var versionString = reader.GetString(); return versionString is null ? null : PluginVersion.Parse(versionString); } From efbc635de1f5c159d5ec65a466b3d28036bd12c1 Mon Sep 17 00:00:00 2001 From: Helen Zhang Date: Wed, 2 Apr 2025 12:14:26 -0700 Subject: [PATCH 3/5] Fix namespace ordering --- .../Metadata/PluginMetadata.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs index 711c00799..20076b8dc 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/Metadata/PluginMetadata.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Microsoft.Performance.SDK; -using NuGet.Versioning; using System; using System.Collections.Generic; using System.Text.Json.Serialization; +using Microsoft.Performance.SDK; +using NuGet.Versioning; namespace Microsoft.Performance.Toolkit.Plugins.Core.Metadata { From efb7b1062aedcc7217d85e7b661b15d02cc911f2 Mon Sep 17 00:00:00 2001 From: Helen Zhang Date: Wed, 2 Apr 2025 17:27:43 -0700 Subject: [PATCH 4/5] Add tests --- ...formance.Toolkit.Plugins.Core.Tests.csproj | 1 + .../PluginMetadataSerializationTests.cs | 55 +++++++++++++++++++ .../EnumerableExtensions.cs | 2 +- .../PluginIdentity.cs | 4 +- ...rformance.Toolkit.Plugins.Cli.Tests.csproj | 27 +++++++++ .../PluginManifestSerializationTests.cs | 39 +++++++++++++ .../Manifest/PluginIdentityManifest.cs | 53 +++++++++++++++++- .../Manifest/PluginManifest.cs | 52 ++++++++++++++++++ .../Manifest/PluginOwnerInfoManifest.cs | 55 +++++++++++++++++++ .../Program.cs | 24 ++++---- src/SDK.sln | 15 +++++ 11 files changed, 311 insertions(+), 16 deletions(-) create mode 100644 src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs create mode 100644 src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj create mode 100644 src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/Microsoft.Performance.Toolkit.Plugins.Core.Tests.csproj b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/Microsoft.Performance.Toolkit.Plugins.Core.Tests.csproj index b5bf69a1d..01bb259e8 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/Microsoft.Performance.Toolkit.Plugins.Core.Tests.csproj +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/Microsoft.Performance.Toolkit.Plugins.Core.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs new file mode 100644 index 000000000..daeffd17c --- /dev/null +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs @@ -0,0 +1,55 @@ +using AutoFixture; +using Microsoft.Performance.Toolkit.Plugins.Core.Metadata; +using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Fixture = AutoFixture.Fixture; + +namespace Microsoft.Performance.Toolkit.Plugins.Core.Tests; + +[TestClass] +public sealed class PluginMetadataSerializationTests +{ + private Fixture? fixture = null; + + [TestInitialize] + public void Setup() + { + this.fixture = new Fixture(); + } + + [TestMethod] + public void PluginMetadata_Serialization_RoundTrip() + { + ISerializer metadataSerializer = SerializationUtils.GetJsonSerializerWithDefaultOptions(); + + PluginMetadata metadata = this.fixture!.Create(); + + using var stream = new MemoryStream(); + metadataSerializer.Serialize(stream, metadata); + + stream.Position = 0; + + PluginMetadata deserializedMetadata = metadataSerializer.Deserialize(stream); + + Assert.IsNotNull(deserializedMetadata); + Assert.IsTrue(metadata.Equals(deserializedMetadata)); + } + + [TestMethod] + public void PluginContentsMetadata_Serialization_RoundTrip() + { + ISerializer contentsMetadataSerializer = SerializationUtils.GetJsonSerializerWithDefaultOptions(); + + PluginContentsMetadata contentsMetadata = this.fixture!.Create(); + + using var stream = new MemoryStream(); + contentsMetadataSerializer.Serialize(stream, contentsMetadata); + + stream.Position = 0; + + PluginContentsMetadata deserializedContentsMetadata = contentsMetadataSerializer.Deserialize(stream); + + Assert.IsNotNull(deserializedContentsMetadata); + Assert.IsTrue(contentsMetadata.Equals(deserializedContentsMetadata)); + } +} diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/EnumerableExtensions.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/EnumerableExtensions.cs index 94782dbf0..6eed906fa 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/EnumerableExtensions.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/EnumerableExtensions.cs @@ -11,7 +11,7 @@ namespace Microsoft.Performance.Toolkit.Plugins.Core /// /// Provides extension methods for . /// - internal static class EnumerableExtensions + public static class EnumerableExtensions { /// /// Determines whether two sequences are equal by comparing their elements by using the default equality comparer for their type. diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs index 8dd53b01a..8f87255de 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs @@ -84,8 +84,8 @@ public static bool Equals(PluginIdentity a, PluginIdentity b) public override int GetHashCode() { return HashCodeUtils.CombineHashCodeValues( - this.Id.GetHashCode(), - this.Version.GetHashCode()); + this.Id?.GetHashCode() ?? 0, + this.Version?.GetHashCode() ?? 0); } /// diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj new file mode 100644 index 000000000..adfd955bf --- /dev/null +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs new file mode 100644 index 000000000..26c0ae504 --- /dev/null +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AutoFixture; +using Microsoft.Performance.Toolkit.Plugins.Cli.Manifest; +using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; +using Fixture = AutoFixture.Fixture; + +namespace Microsoft.Performance.Toolkit.Plugins.Cli.Tests; + +[TestClass] +public sealed class PluginManifestSerializationTest +{ + private Fixture? fixture = null; + + [TestInitialize] + public void Setup() + { + this.fixture = new Fixture(); + } + + [TestMethod] + public void PluginManifest_Serialization_RoundTrip() + { + ISerializer manifestSerializer = SerializationUtils.GetJsonSerializer(Program.PluginManifestSerializerDefaultOptions); + + PluginManifest pluginManifest = this.fixture.Create(); + + using var stream = new MemoryStream(); + manifestSerializer.Serialize(stream, pluginManifest); + + stream.Position = 0; + + PluginManifest deserializedPluginManifest = manifestSerializer.Deserialize(stream); + + Assert.IsNotNull(deserializedPluginManifest); + Assert.IsTrue(pluginManifest.Equals(deserializedPluginManifest)); + } +} diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs index 9de2b3775..522f6e707 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Microsoft.Performance.SDK; using Microsoft.Performance.Toolkit.Plugins.Core; -using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; -using System.Text.Json.Serialization; namespace Microsoft.Performance.Toolkit.Plugins.Cli.Manifest { @@ -11,6 +10,7 @@ namespace Microsoft.Performance.Toolkit.Plugins.Cli.Manifest /// Represents the identity of a plugin in a manifest. /// public sealed class PluginIdentityManifest + : IEquatable { /// /// Initializes a new instance of the @@ -38,5 +38,54 @@ public PluginIdentityManifest( /// Gets or sets the version of this plugin. /// public PluginVersion Version { get; } + + /// + public override bool Equals(object? obj) + { + return Equals(obj as PluginIdentityManifest); + } + + /// + public bool Equals(PluginIdentityManifest? other) + { + return Equals(this, other); + } + + /// + /// Determines whether the specified instances are considered equal. + /// + /// + /// The first plugin identity to compare. + /// + /// + /// The second plugin identity to compare. + /// + /// + /// true if a and b are considered equal; false otherwise. + /// If a or b is null, the method returns false. + /// + public static bool Equals(PluginIdentityManifest? a, PluginIdentityManifest? b) + { + if (ReferenceEquals(a, b)) + { + return true; + } + + if (a is null || b is null) + { + return false; + } + + return string.Equals(a.Id, b.Id, StringComparison.Ordinal) && + PluginVersion.Equals(a.Version, b.Version); + } + + /// + public override int GetHashCode() + { + return HashCodeUtils.CombineHashCodeValues( + this.Id?.GetHashCode() ?? 0, + this.Version?.GetHashCode() ?? 0); + } } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginManifest.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginManifest.cs index 975d3c54d..9f8c8777b 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginManifest.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginManifest.cs @@ -1,12 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Microsoft.Performance.Toolkit.Plugins.Core; +using Microsoft.Performance.SDK; +using System.Text.Json.Serialization; + namespace Microsoft.Performance.Toolkit.Plugins.Cli.Manifest { /// /// Represents the manifest for a plugin. /// public sealed class PluginManifest + : IEquatable { /// /// Initializes a new instance of the s @@ -26,6 +31,7 @@ public sealed class PluginManifest /// /// The URL of the project that owns this plugin. /// + [JsonConstructor] public PluginManifest( PluginIdentityManifest identity, string displayName, @@ -65,5 +71,51 @@ public PluginManifest( /// Gets the URL of the project that owns this plugin. /// public Uri ProjectUrl { get; } + + /// + public override bool Equals(object? obj) + { + return Equals(obj as PluginManifest); + } + + /// + public bool Equals(PluginManifest? other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return this.Identity.Equals(other.Identity) + && this.DisplayName == other.DisplayName + && this.Description == other.Description + && this.Owners.EnumerableEqual(other.Owners) + && this.ProjectUrl == other.ProjectUrl; + } + + /// + public override int GetHashCode() + { + int result = HashCodeUtils.CombineHashCodeValues( + this.Identity?.GetHashCode() ?? 0, + this.DisplayName?.GetHashCode() ?? 0, + this.Description?.GetHashCode() ?? 0, + this.ProjectUrl?.GetHashCode() ?? 0); + + if (this.Owners != null) + { + foreach (PluginOwnerInfoManifest owner in this.Owners) + { + result = HashCodeUtils.CombineHashCodeValues(result, owner?.GetHashCode() ?? 0); + } + } + + return result; + } } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginOwnerInfoManifest.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginOwnerInfoManifest.cs index 48b6815e1..e7642dca3 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginOwnerInfoManifest.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginOwnerInfoManifest.cs @@ -1,12 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Microsoft.Performance.SDK; +using Microsoft.Performance.Toolkit.Plugins.Core; + namespace Microsoft.Performance.Toolkit.Plugins.Cli.Manifest { /// /// Contains information about the plugin owner in the manifest. /// public sealed class PluginOwnerInfoManifest + : IEquatable { /// /// Initializes a new instance of the @@ -54,5 +58,56 @@ public PluginOwnerInfoManifest( /// Gets the phone numbers of the owner, if any. /// public IEnumerable PhoneNumbers { get; } + + /// + public override bool Equals(object? obj) + { + return Equals(obj as PluginOwnerInfoManifest); + } + + /// + public bool Equals(PluginOwnerInfoManifest? other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return string.Equals(this.Name, other.Name, StringComparison.Ordinal) + && string.Equals(this.Address, other.Address, StringComparison.Ordinal) + && this.EmailAddresses.EnumerableEqual(other.EmailAddresses, StringComparer.Ordinal) + && this.PhoneNumbers.EnumerableEqual(other.PhoneNumbers, StringComparer.Ordinal); + } + + /// + public override int GetHashCode() + { + int result = HashCodeUtils.CombineHashCodeValues( + this.Name?.GetHashCode() ?? 0, + this.Address?.GetHashCode() ?? 0); + + if (this.PhoneNumbers != null) + { + foreach (string phone in this.PhoneNumbers) + { + HashCodeUtils.CombineHashCodeValues(result, phone?.GetHashCode() ?? 0); + } + } + + if (this.EmailAddresses != null) + { + foreach (string email in this.EmailAddresses) + { + HashCodeUtils.CombineHashCodeValues(result, email?.GetHashCode() ?? 0); + } + } + + return result; + } } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs index 446c151d6..96a575ba9 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Program.cs @@ -33,10 +33,20 @@ public sealed class Program /// public static int Main(string[] args) { - return CreatPluginsCli().Run(args); + return CreatePluginsCli().Run(args); } - private static PluginsCli CreatPluginsCli() + public static readonly JsonSerializerOptions PluginManifestSerializerDefaultOptions = new() + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new PluginVersionJsonConverter(), + } + }; + + private static PluginsCli CreatePluginsCli() { ServiceProvider serviceProvider = new ServiceCollection() .AddLogging(x => x.AddConsole()) @@ -47,15 +57,7 @@ private static PluginsCli CreatPluginsCli() .AddSingleton, MetadataGenOptionsValidator>() .AddSingleton() .AddSingleton() - .AddSingleton>(SerializationUtils.GetJsonSerializer(new JsonSerializerOptions - { - WriteIndented = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - Converters = - { - new PluginVersionJsonConverter(), - } - })) + .AddSingleton>(SerializationUtils.GetJsonSerializer(PluginManifestSerializerDefaultOptions)) .AddSingleton>(SerializationUtils.GetJsonSerializerWithDefaultOptions()) .AddSingleton>(SerializationUtils.GetJsonSerializerWithDefaultOptions()) .AddSingleton() diff --git a/src/SDK.sln b/src/SDK.sln index d11fb79bb..52dfcf69e 100644 --- a/src/SDK.sln +++ b/src/SDK.sln @@ -51,6 +51,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution version.json = version.json EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Performance.Toolkit.Plugins.Cli.Tests", "PluginsSystem\Tools\Microsoft.Performance.Toolkit.Plugins.Cli.Tests\Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj", "{025EB03D-028A-401F-AFA8-731FCF90DD8A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -265,6 +267,18 @@ Global {B010E944-C96D-4152-8CA6-38E5D53070E1}.Release|x64.Build.0 = Release|Any CPU {B010E944-C96D-4152-8CA6-38E5D53070E1}.Release|x86.ActiveCfg = Release|Any CPU {B010E944-C96D-4152-8CA6-38E5D53070E1}.Release|x86.Build.0 = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|x64.ActiveCfg = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|x64.Build.0 = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|x86.ActiveCfg = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Debug|x86.Build.0 = Debug|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|Any CPU.Build.0 = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|x64.ActiveCfg = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|x64.Build.0 = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|x86.ActiveCfg = Release|Any CPU + {025EB03D-028A-401F-AFA8-731FCF90DD8A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -277,6 +291,7 @@ Global {86E14EA1-084E-4C21-AA14-AAAC83992D86} = {F5125921-DE2A-43BC-89C6-8584E2F23867} {487C7320-8CCF-45BC-9622-1B55B5194259} = {86E14EA1-084E-4C21-AA14-AAAC83992D86} {B010E944-C96D-4152-8CA6-38E5D53070E1} = {AB9CEC9E-61E6-4FDC-912B-6848C3CD4066} + {025EB03D-028A-401F-AFA8-731FCF90DD8A} = {86E14EA1-084E-4C21-AA14-AAAC83992D86} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C9B73E61-5E48-45BD-B144-AFEFF5E44A52} From bac00933634422daacb5f4fc006acff30ac245a0 Mon Sep 17 00:00:00 2001 From: Helen Zhang Date: Thu, 3 Apr 2025 15:06:59 -0700 Subject: [PATCH 5/5] Address comments --- .../PluginMetadataSerializationTests.cs | 33 +++---------------- .../SerializationTestsHelper.cs | 28 ++++++++++++++++ .../PluginIdentity.cs | 4 +-- ...rformance.Toolkit.Plugins.Cli.Tests.csproj | 1 + .../PluginManifestSerializationTests.cs | 17 ++-------- .../Manifest/PluginIdentityManifest.cs | 7 ++-- 6 files changed, 43 insertions(+), 47 deletions(-) create mode 100644 src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/SerializationTestsHelper.cs diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs index daeffd17c..644768a26 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/PluginMetadataSerializationTests.cs @@ -1,6 +1,7 @@ -using AutoFixture; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using Microsoft.Performance.Toolkit.Plugins.Core.Metadata; -using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; using Fixture = AutoFixture.Fixture; @@ -20,36 +21,12 @@ public void Setup() [TestMethod] public void PluginMetadata_Serialization_RoundTrip() { - ISerializer metadataSerializer = SerializationUtils.GetJsonSerializerWithDefaultOptions(); - - PluginMetadata metadata = this.fixture!.Create(); - - using var stream = new MemoryStream(); - metadataSerializer.Serialize(stream, metadata); - - stream.Position = 0; - - PluginMetadata deserializedMetadata = metadataSerializer.Deserialize(stream); - - Assert.IsNotNull(deserializedMetadata); - Assert.IsTrue(metadata.Equals(deserializedMetadata)); + SerializationTestsHelper.RunSerializationTest(this.fixture!); } [TestMethod] public void PluginContentsMetadata_Serialization_RoundTrip() { - ISerializer contentsMetadataSerializer = SerializationUtils.GetJsonSerializerWithDefaultOptions(); - - PluginContentsMetadata contentsMetadata = this.fixture!.Create(); - - using var stream = new MemoryStream(); - contentsMetadataSerializer.Serialize(stream, contentsMetadata); - - stream.Position = 0; - - PluginContentsMetadata deserializedContentsMetadata = contentsMetadataSerializer.Deserialize(stream); - - Assert.IsNotNull(deserializedContentsMetadata); - Assert.IsTrue(contentsMetadata.Equals(deserializedContentsMetadata)); + SerializationTestsHelper.RunSerializationTest(this.fixture!); } } diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/SerializationTestsHelper.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/SerializationTestsHelper.cs new file mode 100644 index 000000000..3013c5e17 --- /dev/null +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core.Tests/SerializationTestsHelper.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AutoFixture; +using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.Performance.Toolkit.Plugins.Core.Tests; + +public class SerializationTestsHelper +{ + public static void RunSerializationTest(Fixture fixture) where T : class + { + ISerializer serializer = SerializationUtils.GetJsonSerializerWithDefaultOptions(); + + T original = fixture.Create(); + + using var stream = new MemoryStream(); + serializer.Serialize(stream, original); + + stream.Position = 0; + + T deserialized = serializer.Deserialize(stream); + + Assert.IsNotNull(deserialized); + Assert.IsTrue(original.Equals(deserialized)); + } +} diff --git a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs index 8f87255de..8dd53b01a 100644 --- a/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs +++ b/src/PluginsSystem/Microsoft.Performance.Toolkit.Plugins.Core/PluginIdentity.cs @@ -84,8 +84,8 @@ public static bool Equals(PluginIdentity a, PluginIdentity b) public override int GetHashCode() { return HashCodeUtils.CombineHashCodeValues( - this.Id?.GetHashCode() ?? 0, - this.Version?.GetHashCode() ?? 0); + this.Id.GetHashCode(), + this.Version.GetHashCode()); } /// diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj index adfd955bf..4b292333b 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/Microsoft.Performance.Toolkit.Plugins.Cli.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs index 26c0ae504..d8d21a445 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli.Tests/PluginManifestSerializationTests.cs @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using AutoFixture; using Microsoft.Performance.Toolkit.Plugins.Cli.Manifest; -using Microsoft.Performance.Toolkit.Plugins.Core.Serialization; +using Microsoft.Performance.Toolkit.Plugins.Core.Tests; using Fixture = AutoFixture.Fixture; namespace Microsoft.Performance.Toolkit.Plugins.Cli.Tests; @@ -22,18 +21,6 @@ public void Setup() [TestMethod] public void PluginManifest_Serialization_RoundTrip() { - ISerializer manifestSerializer = SerializationUtils.GetJsonSerializer(Program.PluginManifestSerializerDefaultOptions); - - PluginManifest pluginManifest = this.fixture.Create(); - - using var stream = new MemoryStream(); - manifestSerializer.Serialize(stream, pluginManifest); - - stream.Position = 0; - - PluginManifest deserializedPluginManifest = manifestSerializer.Deserialize(stream); - - Assert.IsNotNull(deserializedPluginManifest); - Assert.IsTrue(pluginManifest.Equals(deserializedPluginManifest)); + SerializationTestsHelper.RunSerializationTest(this.fixture!); } } diff --git a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs index 522f6e707..7dd0b51be 100644 --- a/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs +++ b/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginIdentityManifest.cs @@ -25,6 +25,9 @@ public PluginIdentityManifest( string id, PluginVersion version) { + Guard.NotNull(id, nameof(id)); + Guard.NotNull(version, nameof(version)); + this.Id = id; this.Version = version; } @@ -84,8 +87,8 @@ public static bool Equals(PluginIdentityManifest? a, PluginIdentityManifest? b) public override int GetHashCode() { return HashCodeUtils.CombineHashCodeValues( - this.Id?.GetHashCode() ?? 0, - this.Version?.GetHashCode() ?? 0); + this.Id.GetHashCode(), + this.Version.GetHashCode()); } } }