From a674f478aa07328818f8831f99cf998c51d88b62 Mon Sep 17 00:00:00 2001 From: Shweta Patil Date: Fri, 5 Oct 2018 16:34:43 -0700 Subject: [PATCH 1/5] Added comparison logic for - OpenApiInfo - OpenApiContact - OpenApiLicense - OpenApiExternalDocs - OpenApiSecurityRequirements - OpenApiTag --- .../Services/OpenApiComparerBase.cs | 147 ++++ .../Services/OpenApiComparerFactory.cs | 17 +- .../Services/OpenApiComponentsComparer.cs | 8 +- .../Services/OpenApiContactComparer.cs | 54 ++ .../Services/OpenApiDocumentComparer.cs | 33 +- .../Services/OpenApiExternalDocsComparer.cs | 48 ++ .../Services/OpenApiInfoComparer.cs | 71 ++ .../Services/OpenApiLicenseComparer.cs | 51 ++ .../Services/OpenApiOAuthFlowComparer.cs | 55 ++ .../Services/OpenApiOAuthFlowsComparer.cs | 73 ++ .../Services/OpenApiOperationComparer.cs | 25 +- .../Services/OpenApiOrderedListComparer.cs | 90 +++ .../Services/OpenApiParameterComparer.cs | 3 +- .../Services/OpenApiRequestBodyComparer.cs | 30 +- .../Services/OpenApiSchemaComparer.cs | 8 +- .../OpenApiSecurityRequirementComparer.cs | 96 +++ .../Services/OpenApiSecuritySchemeComparer.cs | 79 ++ .../Services/OpenApiTagComparer.cs | 55 ++ .../Services/OpenApiComparerTestCases.cs | 721 ++++++++++++++++++ .../Services/OpenApiInfoComparerTests.cs | 297 ++++++++ ...OpenApiSecurityRequirementComparerTests.cs | 293 +++++++ .../OpenApiSecuritySchemeComparerTests.cs | 308 ++++++++ .../Services/OpenApiTagComparerTests.cs | 304 ++++++++ 23 files changed, 2824 insertions(+), 42 deletions(-) create mode 100644 src/Microsoft.OpenApi/Services/OpenApiContactComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiExternalDocsComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiInfoComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiLicenseComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiOAuthFlowComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiOAuthFlowsComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiOrderedListComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiTagComparer.cs create mode 100644 test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs create mode 100644 test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs create mode 100644 test/Microsoft.OpenApi.Tests/Services/OpenApiSecuritySchemeComparerTests.cs create mode 100644 test/Microsoft.OpenApi.Tests/Services/OpenApiTagComparerTests.cs diff --git a/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs b/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs index d08b5e644..4f1e8158d 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs @@ -2,6 +2,8 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -46,6 +48,32 @@ internal void Compare(string source, string target, ComparisonContext comparison } } + /// + /// Compares two Uri object. + /// + /// The source. + /// The target. + /// The context under which to compare the objects. + internal void Compare(Uri source, Uri target, ComparisonContext comparisonContext) + { + if (source == null && target == null) + { + return; + } + + if (source != target) + { + comparisonContext.AddOpenApiDifference(new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = source, + TargetValue = target, + Pointer = comparisonContext.PathString + }); + } + } + /// /// Compares two boolean object. /// @@ -138,6 +166,125 @@ internal void Compare(Enum source, Enum target, ComparisonContext compari } } + /// + /// Compares object. + /// + /// The source. + /// The target. + /// The context under which to compare the objects. + internal void Compare( + OpenApiReference sourceReference, + OpenApiReference targetReference, + ComparisonContext comparisonContext) + { + if (sourceReference == null && targetReference == null) + { + return; + } + + if (sourceReference == null || targetReference == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceReference, + TargetValue = targetReference, + OpenApiComparedElementType = typeof(OpenApiReference), + Pointer = comparisonContext.PathString + }); + + return; + } + + if (sourceReference.Id != targetReference.Id || sourceReference.Type != targetReference.Type) + { + WalkAndAddOpenApiDifference( + comparisonContext, + OpenApiConstants.DollarRef, + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceReference, + TargetValue = targetReference, + OpenApiComparedElementType = typeof(OpenApiReference) + }); + + return; + } + + var source = (TReference) comparisonContext.SourceDocument.ResolveReference( + sourceReference); + + var target = (TReference) comparisonContext.TargetDocument.ResolveReference( + targetReference); + + comparisonContext + .GetComparer() + .Compare(source, target, comparisonContext); + } + + /// + /// Compares where TKey is and TValue is + /// . + /// + /// The source. + /// The target. + /// The context under which to compare the objects. + internal void Compare(IDictionary source, IDictionary target, + ComparisonContext comparisonContext) + { + if (source == null && target == null) + { + return; + } + + if (source == null || target == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = source, + TargetValue = target, + OpenApiComparedElementType = typeof(IDictionary), + Pointer = comparisonContext.PathString + }); + + return; + } + + var newKeysInTarget = target.Keys.Except(source.Keys).ToList(); + + foreach (var newKeyInTarget in newKeysInTarget) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + TargetValue = new KeyValuePair( + newKeyInTarget, + target[newKeyInTarget]), + OpenApiComparedElementType = typeof(KeyValuePair) + }); + } + + var removedKeysFromSource = source.Keys.Except(target.Keys).ToList(); + + foreach (var removedKeyFromSource in removedKeysFromSource) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + TargetValue = new KeyValuePair( + removedKeyFromSource, + source[removedKeyFromSource]), + OpenApiComparedElementType = typeof(KeyValuePair) + }); + } + } + /// /// Adds a segment to the context path to enable pointing to the current location in the document. /// diff --git a/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs b/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs index e10f0aa5f..e5c9a7da5 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs @@ -33,6 +33,10 @@ public class OpenApiComparerFactory {typeof(IDictionary), new OpenApiDictionaryComparer()}, {typeof(IDictionary), new OpenApiDictionaryComparer()}, {typeof(IDictionary), new OpenApiDictionaryComparer()}, + { + typeof(IDictionary), + new OpenApiDictionaryComparer() + }, {typeof(OpenApiHeader), new OpenApiHeaderComparer()}, {typeof(OpenApiRequestBody), new OpenApiRequestBodyComparer()}, {typeof(OpenApiResponse), new OpenApiResponseComparer()}, @@ -40,7 +44,18 @@ public class OpenApiComparerFactory {typeof(OpenApiEncoding), new OpenApiEncodingComparer()}, {typeof(IList), new OpenApiServersComparer()}, {typeof(OpenApiServer), new OpenApiServerComparer()}, - {typeof(OpenApiServerVariable), new OpenApiServerVariableComparer()} + {typeof(OpenApiServerVariable), new OpenApiServerVariableComparer()}, + {typeof(OpenApiOAuthFlow), new OpenApiOAuthFlowComparer()}, + {typeof(OpenApiOAuthFlows), new OpenApiOAuthFlowsComparer()}, + {typeof(OpenApiSecurityRequirement), new OpenApiSecurityRequirementComparer()}, + {typeof(OpenApiInfo), new OpenApiInfoComparer()}, + {typeof(OpenApiContact), new OpenApiContactComparer()}, + {typeof(OpenApiLicense), new OpenApiLicenseComparer()}, + {typeof(IList), new OpenApiOrderedListComparer()}, + {typeof(IList), new OpenApiOrderedListComparer()}, + {typeof(OpenApiExternalDocs), new OpenApiExternalDocsComparer()}, + {typeof(OpenApiTag), new OpenApiTagComparer()}, + {typeof(OpenApiSecurityScheme), new OpenApiSecuritySchemeComparer()} }; private readonly Dictionary _typeToComparerMap = new Dictionary(); diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs index bdb2ed3e5..23bdc629f 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs @@ -77,8 +77,14 @@ public override void Compare( .GetComparer>() .Compare(sourceComponents.Headers, targetComponents.Headers, comparisonContext)); + WalkAndCompare( + comparisonContext, + OpenApiConstants.SecuritySchemes, + () => comparisonContext + .GetComparer>() + .Compare(sourceComponents.SecuritySchemes, targetComponents.SecuritySchemes, comparisonContext)); + // To Do compare Examples - // To Do compare SecuritySchemes // To Do compare Links // To Do compare Callbacks // To Do compare Extensions diff --git a/src/Microsoft.OpenApi/Services/OpenApiContactComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiContactComparer.cs new file mode 100644 index 000000000..06f65c62c --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiContactComparer.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiContactComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiContact sourceContact, + OpenApiContact targetContact, + ComparisonContext comparisonContext) + { + if (sourceContact == null && targetContact == null) + { + return; + } + + if (sourceContact == null || targetContact == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceContact, + TargetValue = targetContact, + OpenApiComparedElementType = typeof(OpenApiContact), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare(comparisonContext, OpenApiConstants.Name, + () => Compare(sourceContact.Name, targetContact.Name, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Email, + () => Compare(sourceContact.Email, targetContact.Email, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Url, + () => Compare(sourceContact.Url, targetContact.Url, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs index 41e3dc046..5e1c6ecf5 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs @@ -43,11 +43,34 @@ public override void Compare( .GetComparer>() .Compare(sourceDocument.Servers, targetDocument.Servers, comparisonContext)); - // To Do Compare Info - // To Do Compare Security Requirements - // To Do Compare Tags - // To Do Compare External Docs - // To Do Compare Extensions + WalkAndCompare( + comparisonContext, + OpenApiConstants.Info, + () => comparisonContext + .GetComparer() + .Compare(sourceDocument.Info, targetDocument.Info, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Security, + () => comparisonContext + .GetComparer>() + .Compare(sourceDocument.SecurityRequirements, targetDocument.SecurityRequirements, + comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Tags, + () => comparisonContext + .GetComparer>() + .Compare(sourceDocument.Tags, targetDocument.Tags, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.ExternalDocs, + () => comparisonContext + .GetComparer() + .Compare(sourceDocument.ExternalDocs, targetDocument.ExternalDocs, comparisonContext)); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiExternalDocsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiExternalDocsComparer.cs new file mode 100644 index 000000000..31e9d5bcf --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiExternalDocsComparer.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiExternalDocsComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare(OpenApiExternalDocs sourceDocs, OpenApiExternalDocs targetDocs, + ComparisonContext comparisonContext) + { + if (sourceDocs == null && targetDocs == null) + { + return; + } + + if (sourceDocs == null || targetDocs == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceDocs, + TargetValue = targetDocs, + OpenApiComparedElementType = typeof(OpenApiExternalDocs), + Pointer = comparisonContext.PathString + }); + return; + } + + WalkAndCompare(comparisonContext, OpenApiConstants.Description, + () => Compare(sourceDocs.Description, targetDocs.Description, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Url, + () => Compare(sourceDocs.Url, targetDocs.Url, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiInfoComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiInfoComparer.cs new file mode 100644 index 000000000..ec71059dc --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiInfoComparer.cs @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiInfoComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiInfo sourceInfo, + OpenApiInfo targetInfo, + ComparisonContext comparisonContext) + { + if (sourceInfo == null && targetInfo == null) + { + return; + } + + if (sourceInfo == null || targetInfo == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceInfo, + TargetValue = targetInfo, + OpenApiComparedElementType = typeof(OpenApiInfo), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare(comparisonContext, OpenApiConstants.Title, + () => Compare(sourceInfo.Title, targetInfo.Title, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Description, + () => Compare(sourceInfo.Description, targetInfo.Description, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.TermsOfService, + () => Compare(sourceInfo.TermsOfService, targetInfo.TermsOfService, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Version, + () => Compare(sourceInfo.Version, targetInfo.Version, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Contact, + () => comparisonContext + .GetComparer() + .Compare(sourceInfo.Contact, targetInfo.Contact, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.License, + () => comparisonContext + .GetComparer() + .Compare(sourceInfo.License, targetInfo.License, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiLicenseComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiLicenseComparer.cs new file mode 100644 index 000000000..be61db7c8 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiLicenseComparer.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiLicenseComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiLicense sourceLicense, + OpenApiLicense targetLicense, + ComparisonContext comparisonContext) + { + if (sourceLicense == null && targetLicense == null) + { + return; + } + + if (sourceLicense == null || targetLicense == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceLicense, + TargetValue = targetLicense, + OpenApiComparedElementType = typeof(OpenApiLicense), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare(comparisonContext, OpenApiConstants.Name, + () => Compare(sourceLicense.Name, targetLicense.Name, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Url, + () => Compare(sourceLicense.Url, targetLicense.Url, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowComparer.cs new file mode 100644 index 000000000..cfee18a60 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowComparer.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiOAuthFlowComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare(OpenApiOAuthFlow sourceFlow, OpenApiOAuthFlow targetFlow, + ComparisonContext comparisonContext) + { + if (sourceFlow == null && targetFlow == null) + { + return; + } + + if (sourceFlow == null || targetFlow == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceFlow, + TargetValue = targetFlow, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare(comparisonContext, OpenApiConstants.AuthorizationUrl, + () => Compare(sourceFlow.AuthorizationUrl, targetFlow.AuthorizationUrl, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.TokenUrl, + () => Compare(sourceFlow.TokenUrl, targetFlow.TokenUrl, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.RefreshUrl, + () => Compare(sourceFlow.RefreshUrl, targetFlow.RefreshUrl, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Scopes, + () => Compare(sourceFlow.Scopes, targetFlow.Scopes, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowsComparer.cs new file mode 100644 index 000000000..9334bc9b0 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiOAuthFlowsComparer.cs @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiOAuthFlowsComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiOAuthFlows sourceFlows, + OpenApiOAuthFlows targetFlows, + ComparisonContext comparisonContext) + { + if (sourceFlows == null && targetFlows == null) + { + return; + } + + if (sourceFlows == null || targetFlows == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceFlows, + TargetValue = targetFlows, + OpenApiComparedElementType = typeof(OpenApiOAuthFlows), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Implicit, + () => comparisonContext + .GetComparer() + .Compare(sourceFlows.Implicit, targetFlows.Implicit, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Password, + () => comparisonContext + .GetComparer() + .Compare(sourceFlows.Password, targetFlows.Password, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.ClientCredentials, + () => comparisonContext + .GetComparer() + .Compare(sourceFlows.ClientCredentials, targetFlows.ClientCredentials, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.AuthorizationCode, + () => comparisonContext + .GetComparer() + .Compare(sourceFlows.AuthorizationCode, targetFlows.AuthorizationCode, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiOperationComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiOperationComparer.cs index 98879e013..354e36906 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiOperationComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiOperationComparer.cs @@ -69,11 +69,28 @@ public override void Compare( .GetComparer>() .Compare(sourceOperation?.Servers, targetOperation?.Servers, comparisonContext)); + WalkAndCompare( + comparisonContext, + OpenApiConstants.Tags, + () => comparisonContext + .GetComparer>() + .Compare(sourceOperation?.Tags, targetOperation?.Tags, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Security, + () => comparisonContext + .GetComparer>() + .Compare(sourceOperation?.Security, targetOperation?.Security, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.ExternalDocs, + () => comparisonContext + .GetComparer() + .Compare(sourceOperation?.ExternalDocs, targetOperation?.ExternalDocs, comparisonContext)); + // Compare CallBack - // Compare Security Requirements - // Compare Extensions - // Compare External Docs - // Compare Tags } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiOrderedListComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiOrderedListComparer.cs new file mode 100644 index 000000000..405f06e21 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiOrderedListComparer.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using Microsoft.OpenApi.Interfaces; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing where T is . + /// + public class OpenApiOrderedListComparer : OpenApiComparerBase> where T : IOpenApiSerializable + { + /// + /// Executes comparision against based on the order of the list for source and target + /// where T is . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + IList sourceFragment, + IList targetFragment, + ComparisonContext comparisonContext) + { + if (sourceFragment == null && targetFragment == null) + { + return; + } + + if (sourceFragment == null || targetFragment == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceFragment, + TargetValue = sourceFragment, + OpenApiComparedElementType = typeof(IList), + Pointer = comparisonContext.PathString + }); + + return; + } + + for (var i = 0; i < sourceFragment.Count; i++) + { + if (i >= targetFragment.Count) + { + WalkAndAddOpenApiDifference( + comparisonContext, + i.ToString(), + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + SourceValue = sourceFragment[i], + OpenApiComparedElementType = typeof(T) + }); + } + else + { + WalkAndCompare(comparisonContext, + i.ToString(), + () => comparisonContext + .GetComparer() + .Compare(sourceFragment[i], targetFragment[i], comparisonContext)); + } + } + + if (targetFragment.Count <= sourceFragment.Count) + { + return; + } + + // Loop through remaining elements in target that are not in source. + for (var i = sourceFragment.Count; i < targetFragment.Count; i++) + { + WalkAndAddOpenApiDifference( + comparisonContext, + i.ToString(), + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + TargetValue = targetFragment[i], + OpenApiComparedElementType = typeof(T) + }); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs index 53d3e6619..0fdad0dcb 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs @@ -42,6 +42,8 @@ public override void Compare( return; } + Compare(sourceParameter.Reference, targetParameter.Reference, comparisonContext); + WalkAndCompare( comparisonContext, OpenApiConstants.Content, @@ -83,7 +85,6 @@ public override void Compare( .GetComparer() .Compare(sourceParameter.Schema, targetParameter.Schema, comparisonContext)); - // To Do Add compare for reference object // To Do Compare Examples // To Do Compare parameter as IOpenApiExtensible } diff --git a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs index 880c654cf..2c0895343 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs @@ -42,35 +42,7 @@ public override void Compare( return; } - if (sourceRequestBody.Reference != null - && targetRequestBody.Reference != null - && sourceRequestBody.Reference.Id != targetRequestBody.Reference.Id) - { - WalkAndAddOpenApiDifference( - comparisonContext, - OpenApiConstants.DollarRef, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - SourceValue = sourceRequestBody.Reference, - TargetValue = targetRequestBody.Reference, - OpenApiComparedElementType = typeof(OpenApiReference) - }); - - return; - } - - if (sourceRequestBody.Reference != null) - { - sourceRequestBody = (OpenApiRequestBody) comparisonContext.SourceDocument.ResolveReference( - sourceRequestBody.Reference); - } - - if (targetRequestBody.Reference != null) - { - targetRequestBody = (OpenApiRequestBody) comparisonContext.TargetDocument.ResolveReference( - targetRequestBody.Reference); - } + Compare(sourceRequestBody.Reference, targetRequestBody.Reference, comparisonContext); WalkAndCompare(comparisonContext, OpenApiConstants.Description, () => Compare(sourceRequestBody.Description, targetRequestBody.Description, comparisonContext)); diff --git a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs index e320854fd..be86cab01 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs @@ -202,9 +202,15 @@ public override void Compare( }); } + WalkAndCompare( + comparisonContext, + OpenApiConstants.ExternalDocs, + () => comparisonContext + .GetComparer() + .Compare(sourceSchema?.ExternalDocs, sourceSchema?.ExternalDocs, comparisonContext)); + // To Do Compare schema.AllOf // To Do Compare schema.AnyOf - // To Do compare external Docs // To Do compare schema as IOpenApiExtensible comparisonContext.SourceSchemaLoop.Pop(); diff --git a/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs new file mode 100644 index 000000000..1cc20fa7a --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiSecurityRequirementComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiSecurityRequirement sourceSecurityRequirement, + OpenApiSecurityRequirement targetSecurityRequirement, + ComparisonContext comparisonContext) + { + if (sourceSecurityRequirement == null && targetSecurityRequirement == null) + { + return; + } + + if (sourceSecurityRequirement == null || targetSecurityRequirement == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceSecurityRequirement, + TargetValue = targetSecurityRequirement, + OpenApiComparedElementType = typeof(OpenApiSecurityRequirement), + Pointer = comparisonContext.PathString + }); + + return; + } + + var newSecuritySchemesInTarget = targetSecurityRequirement.Keys + .Where(targetReq => sourceSecurityRequirement.Keys.All( + sourceReq => sourceReq.Reference.Id != targetReq.Reference.Id)).ToList(); + + foreach (var newSecuritySchemeInTarget in newSecuritySchemesInTarget) + { + WalkAndAddOpenApiDifference( + comparisonContext, + newSecuritySchemeInTarget.Reference.Id, + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + TargetValue = new KeyValuePair>( + newSecuritySchemeInTarget, + targetSecurityRequirement[newSecuritySchemeInTarget]), + OpenApiComparedElementType = typeof(KeyValuePair>) + }); + } + + foreach (var sourceSecurityScheme in sourceSecurityRequirement.Keys) + { + var targetSecurityScheme = + targetSecurityRequirement.Keys.FirstOrDefault( + i => i.Reference.Id == sourceSecurityScheme.Reference.Id); + + if (targetSecurityScheme == null) + { + WalkAndAddOpenApiDifference( + comparisonContext, + sourceSecurityScheme.Reference.Id, + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + SourceValue = new KeyValuePair>( + sourceSecurityScheme, + sourceSecurityRequirement[sourceSecurityScheme]), + OpenApiComparedElementType = typeof(KeyValuePair>) + }); + } + else + { + WalkAndCompare(comparisonContext, + sourceSecurityScheme.Reference.Id, + () => comparisonContext + .GetComparer() + .Compare(sourceSecurityScheme, targetSecurityScheme, comparisonContext)); + } + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs new file mode 100644 index 000000000..42251769c --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiSecuritySchemeComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiSecurityScheme sourcecSecurityScheme, + OpenApiSecurityScheme targetSecurityScheme, + ComparisonContext comparisonContext) + { + if (sourcecSecurityScheme == null && targetSecurityScheme == null) + { + return; + } + + if (sourcecSecurityScheme == null || targetSecurityScheme == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourcecSecurityScheme, + TargetValue = targetSecurityScheme, + OpenApiComparedElementType = typeof(OpenApiSecurityScheme), + Pointer = comparisonContext.PathString + }); + + return; + } + + Compare(sourcecSecurityScheme.Reference, targetSecurityScheme.Reference, + comparisonContext); + + WalkAndCompare(comparisonContext, OpenApiConstants.Description, + () => Compare(sourcecSecurityScheme.Description, targetSecurityScheme.Description, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Type, + () => Compare(sourcecSecurityScheme.Type, targetSecurityScheme.Type, + comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Name, + () => Compare(sourcecSecurityScheme.Name, targetSecurityScheme.Name, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.In, + () => Compare(sourcecSecurityScheme.In, targetSecurityScheme.In, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Scheme, + () => Compare(sourcecSecurityScheme.Scheme, targetSecurityScheme.Scheme, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.BearerFormat, + () => Compare(sourcecSecurityScheme.BearerFormat, targetSecurityScheme.BearerFormat, + comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.OpenIdConnectUrl, + () => Compare(sourcecSecurityScheme.OpenIdConnectUrl, targetSecurityScheme.OpenIdConnectUrl, + comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Flows, + () => comparisonContext + .GetComparer() + .Compare(sourcecSecurityScheme.Flows, targetSecurityScheme.Flows, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiTagComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiTagComparer.cs new file mode 100644 index 000000000..6290f38f3 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiTagComparer.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiTagComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare(OpenApiTag sourceTag, OpenApiTag targetTag, ComparisonContext comparisonContext) + { + if (sourceTag == null && targetTag == null) + { + return; + } + + if (sourceTag == null || targetTag == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceTag, + TargetValue = targetTag, + OpenApiComparedElementType = typeof(OpenApiTag), + Pointer = comparisonContext.PathString + }); + + return; + } + + WalkAndCompare( + comparisonContext, + OpenApiConstants.ExternalDocs, + () => comparisonContext + .GetComparer() + .Compare(sourceTag.ExternalDocs, targetTag.ExternalDocs, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Description, + () => Compare(sourceTag.Description, targetTag.Description, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Name, + () => Compare(sourceTag.Name, targetTag.Name, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs index 7728a7932..89508813a 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs @@ -1326,6 +1326,727 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( } } }; + + // Differences in tags and security requirements + yield return new object[] + { + "Differences in tags and security requirements", + new OpenApiDocument + { + Paths = new OpenApiPaths + { + { + "/test", new OpenApiPathItem + { + Summary = "test", + Description = "test", + Operations = new Dictionary + { + { + OperationType.Get, new OpenApiOperation + { + RequestBody = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/xml"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + Responses = new OpenApiResponses + { + { + "200", + new OpenApiResponse + { + Description = "An updated complex object array response", + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "array", + Items = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + } + } + } + }, + Security = new List + { + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + } + ] = new List() + } + } + } + } + } + } + } + }, + Tags = new List + { + new OpenApiTag + { + Description = "test description", + Name = "Tag1", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description", + Url = new Uri("http://localhost/doc") + } + }, + new OpenApiTag + { + Description = "test description", + Name = "Tag2", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description", + Url = new Uri("http://localhost/doc") + } + } + }, + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property7"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test", + Flows = new OpenApiOAuthFlows + { + Implicit = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/1") + }, + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + } + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme3", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + }, + SecurityRequirements = new List + { + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + } + ] = new List() + }, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme2" + } + } + ] = new List() + }, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme3" + } + } + ] = new List() + } + } + }, + new OpenApiDocument + { + Paths = new OpenApiPaths + { + { + "/test", new OpenApiPathItem + { + Summary = "test", + Description = "test", + Operations = new Dictionary + { + { + OperationType.Get, new OpenApiOperation + { + RequestBody = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/xml"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + Responses = new OpenApiResponses + { + { + "200", + new OpenApiResponse + { + Description = "An updated complex object array response", + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "array", + Items = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + } + } + } + }, + Security = new List + { + new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + }, + new List() + } + }, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme4" + } + } + ] = new List() + } + } + } + } + } + } + } + }, + Tags = new List + { + new OpenApiTag + { + Description = "test description updated", + Name = "Tag1", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description", + Url = new Uri("http://localhost/doc") + } + } + }, + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property7"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test", + Flows = new OpenApiOAuthFlows + { + Implicit = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/3") + }, + ClientCredentials = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + } + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme4", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + }, + SecurityRequirements = new List + { + new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + }, + new List() + }, + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme2" + } + }, + new List() + } + }, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme4" + } + } + ] = new List() + } + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/security/0/scheme2", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(KeyValuePair>), + SourceValue = null, + TargetValue = new KeyValuePair>(new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme2" + } + }, + new List()) + }, + new OpenApiDifference + { + Pointer = "#/security/1/scheme4", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(KeyValuePair>), + SourceValue = null, + TargetValue = new KeyValuePair>(new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme4" + } + }, new List()) + }, + new OpenApiDifference + { + Pointer = + "#/components/securitySchemes/scheme4", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(KeyValuePair), + SourceValue = null, + TargetValue = new KeyValuePair("scheme4", + new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + }) + }, + new OpenApiDifference + { + Pointer = + "#/paths/~1test/get/security/1", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(OpenApiSecurityRequirement), + SourceValue = null, + TargetValue = new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme4" + } + }, + new List() + } + } + }, + new OpenApiDifference + { + Pointer = "#/tags/0/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "test description", + TargetValue = "test description updated" + }, + new OpenApiDifference + { + Pointer = "#/components/securitySchemes/scheme1/flows/implicit/authorizationUrl", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = "http://localhost/1", + TargetValue = "http://localhost/3" + }, + new OpenApiDifference + { + Pointer = "#/paths/~1test/get/security/0/scheme1/flows/implicit/authorizationUrl", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = "http://localhost/1", + TargetValue = "http://localhost/3" + }, + new OpenApiDifference + { + Pointer = "#/security/0/scheme1/flows/implicit/authorizationUrl", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = "http://localhost/1", + TargetValue = "http://localhost/3" + }, + new OpenApiDifference + { + Pointer = + "#/components/securitySchemes/scheme1/flows/clientCredentials", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = null, + TargetValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + }, + new OpenApiDifference + { + Pointer = + "#/paths/~1test/get/security/0/scheme1/flows/clientCredentials", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = null, + TargetValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + }, + new OpenApiDifference + { + Pointer = + "#/security/0/scheme1/flows/clientCredentials", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = null, + TargetValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + }, + new OpenApiDifference + { + Pointer = "#/components/securitySchemes/scheme1/flows/authorizationCode", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/paths/~1test/get/security/0/scheme1/flows/authorizationCode", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/security/0/scheme1/flows/authorizationCode", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = + "#/components/securitySchemes/scheme3", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(KeyValuePair), + SourceValue = new KeyValuePair("scheme3", + new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + }), + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/tags/1", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(OpenApiTag), + SourceValue = new OpenApiTag + { + Description = "test description", + Name = "Tag2", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description", + Url = new Uri("http://localhost/doc") + } + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = + "#/security/2", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(OpenApiSecurityRequirement), + SourceValue = new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme3" + } + } + ] = new List() + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = + "#/security/1/scheme2", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(KeyValuePair>), + SourceValue = new KeyValuePair>(new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme2" + } + }, + new List()), + TargetValue = null + } + } + }; } } } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs new file mode 100644 index 000000000..f72518e61 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs @@ -0,0 +1,297 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.OpenApi.Tests.Services +{ + [Collection("DefaultSettings")] + public class OpenApiInfoComparerTests + { + private readonly ITestOutputHelper _output; + + private readonly OpenApiDocument _sourceDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property7"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + private readonly OpenApiDocument _targetDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + public OpenApiInfoComparerTests(ITestOutputHelper output) + { + _output = output; + } + + public static IEnumerable GetTestCasesForOpenApiInfoComparerShouldSucceed() + { + // Differences in ContentType,Style,Explode and AllowReserved + yield return new object[] + { + "Differences in ContentType,Style,Explode and AllowReserved", + new OpenApiEncoding + { + ContentType = "image/png, image/jpeg", + Style = ParameterStyle.Simple, + Explode = true, + AllowReserved = true + }, + new OpenApiEncoding + { + ContentType = "image/jpeg", + Style = ParameterStyle.Form, + Explode = false, + AllowReserved = false + }, + new List + { + new OpenApiDifference + { + Pointer = "#/contentType", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + TargetValue = "image/jpeg", + SourceValue = "image/png, image/jpeg" + }, + new OpenApiDifference + { + Pointer = "#/style", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(ParameterStyle), + TargetValue = ParameterStyle.Form, + SourceValue = ParameterStyle.Simple + }, + new OpenApiDifference + { + Pointer = "#/explode", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(bool?), + TargetValue = false, + SourceValue = true + }, + new OpenApiDifference + { + Pointer = "#/allowReserved", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(bool?), + TargetValue = false, + SourceValue = true + } + } + }; + } + + [Theory] + [MemberData(nameof(GetTestCasesForOpenApiInfoComparerShouldSucceed))] + public void OpenApiInfoComparerShouldSucceed( + string testCaseName, + OpenApiInfo source, + OpenApiInfo target, + List expectedDifferences) + { + _output.WriteLine(testCaseName); + + var comparisonContext = new ComparisonContext(new OpenApiComparerFactory(), _sourceDocument, + _targetDocument); + var comparer = new OpenApiInfoComparer(); + comparer.Compare(source, target, comparisonContext); + + var differences = comparisonContext.OpenApiDifferences.ToList(); + differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); + + differences.ShouldBeEquivalentTo(expectedDifferences); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs new file mode 100644 index 000000000..a69cb9057 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs @@ -0,0 +1,293 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.OpenApi.Tests.Services +{ + [Collection("DefaultSettings")] + public class OpenApiSecurityRequirementComparerTests + { + private readonly ITestOutputHelper _output; + + private readonly OpenApiDocument _sourceDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme3", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + } + }; + + private readonly OpenApiDocument _targetDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test Updated", + Name = "Test" + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme4", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + } + }; + + public OpenApiSecurityRequirementComparerTests(ITestOutputHelper output) + { + _output = output; + } + + public static IEnumerable GetTestCasesForOpenApiSecurityRequirementComparerShouldSucceed() + { + yield return new object[] + { + "New Removed And updated schemes", + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme1"} + } + ] = new List + { + "scope1", + "scope2", + "scope3" + }, + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme2"} + } + ] = new List + { + "scope4", + "scope5" + }, + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme3"} + } + ] = new List() + }, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme1"} + } + ] = new List + { + "scope1", + "scope2", + "scope3" + }, + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme2"} + } + ] = new List + { + "scope4", + "scope5" + }, + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme4"} + } + ] = new List() + }, + new List + { + new OpenApiDifference + { + Pointer = "#/scheme3", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(KeyValuePair>), + SourceValue = new KeyValuePair>(new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme3"} + }, new List()), + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/scheme4", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(KeyValuePair>), + SourceValue = null, + TargetValue = new KeyValuePair>(new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme4"} + }, new List()) + }, + new OpenApiDifference + { + Pointer = "#/scheme1/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test", + TargetValue = "Test Updated" + } + } + }; + + yield return new object[] + { + "Source and target are null", + null, + null, + new List() + }; + + yield return new object[] + { + "Source is null", + null, + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme1"} + } + ] = new List() + }, + new List + { + new OpenApiDifference + { + Pointer = "#/", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiSecurityRequirement), + SourceValue = null, + TargetValue = new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + } + ] = new List() + } + } + } + }; + + yield return new object[] + { + "Target is null", + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme1"} + } + ] = new List() + }, + null, + new List + { + new OpenApiDifference + { + Pointer = "#/", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiSecurityRequirement), + SourceValue = new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "scheme1" + } + } + ] = new List() + }, + TargetValue = null + } + } + }; + } + + [Theory] + [MemberData(nameof(GetTestCasesForOpenApiSecurityRequirementComparerShouldSucceed))] + public void OpenApiSecurityRequirementComparerShouldSucceed( + string testCaseName, + OpenApiSecurityRequirement source, + OpenApiSecurityRequirement target, + List expectedDifferences) + { + _output.WriteLine(testCaseName); + + var comparisonContext = new ComparisonContext(new OpenApiComparerFactory(), _sourceDocument, + _targetDocument); + var comparer = new OpenApiSecurityRequirementComparer(); + comparer.Compare(source, target, comparisonContext); + + var differences = comparisonContext.OpenApiDifferences.ToList(); + + differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); + + differences.ShouldBeEquivalentTo(expectedDifferences); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiSecuritySchemeComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecuritySchemeComparerTests.cs new file mode 100644 index 000000000..d576845c3 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecuritySchemeComparerTests.cs @@ -0,0 +1,308 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.OpenApi.Tests.Services +{ + [Collection("DefaultSettings")] + public class OpenApiSecuritySchemeComparerTests + { + private readonly ITestOutputHelper _output; + + private readonly OpenApiDocument _sourceDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test", + Flows = new OpenApiOAuthFlows + { + Implicit = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/1") + }, + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + } + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme3", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + } + }; + + private readonly OpenApiDocument _targetDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + SecuritySchemes = new Dictionary + { + { + "scheme1", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test", + Flows = new OpenApiOAuthFlows + { + Implicit = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/3") + }, + ClientCredentials = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + } + } + }, + { + "scheme2", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + }, + { + "scheme4", new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } + } + } + } + }; + + public OpenApiSecuritySchemeComparerTests(ITestOutputHelper output) + { + _output = output; + } + + public static IEnumerable GetTestCasesForOpenApiSecuritySchemeComparerShouldSucceed() + { + yield return new object[] + { + "Updated Type, Description, Name, In, BearerFormat, OpenIdConnectUrl", + new OpenApiSecurityScheme + { + Type = SecuritySchemeType.ApiKey, + Description = "Test Description", + Name = "Test Name", + In = ParameterLocation.Path, + OpenIdConnectUrl = new Uri("http://localhost:1"), + BearerFormat = "Test Format" + }, + new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Description = "Test Description Updated", + Name = "Test Name Updated", + Scheme = "basic" + }, + new List + { + new OpenApiDifference + { + Pointer = "#/type", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(SecuritySchemeType), + SourceValue = SecuritySchemeType.ApiKey, + TargetValue = SecuritySchemeType.Http + }, + new OpenApiDifference + { + Pointer = "#/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test Description", + TargetValue = "Test Description Updated" + }, + new OpenApiDifference + { + Pointer = "#/name", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test Name", + TargetValue = "Test Name Updated" + }, + new OpenApiDifference + { + Pointer = "#/in", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(ParameterLocation), + SourceValue = ParameterLocation.Path, + TargetValue = ParameterLocation.Query + }, + new OpenApiDifference + { + Pointer = "#/bearerFormat", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test Format", + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/openIdConnectUrl", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = new Uri("http://localhost:1"), + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/scheme", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = null, + TargetValue = "basic" + } + } + }; + + yield return new object[] + { + "Difference in reference id", + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "scheme1", + Type = ReferenceType.SecurityScheme + } + }, + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "scheme2", + Type = ReferenceType.SecurityScheme + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/$ref", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiReference), + SourceValue = new OpenApiReference + { + Id = "scheme1", + Type = ReferenceType.SecurityScheme + }, + TargetValue = new OpenApiReference + { + Id = "scheme2", + Type = ReferenceType.SecurityScheme + } + } + } + }; + + yield return new object[] + { + "New, Removed and Updated OAuthFlows", + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "scheme1", + Type = ReferenceType.SecurityScheme + } + }, + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "scheme1", + Type = ReferenceType.SecurityScheme + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/flows/implicit/authorizationUrl", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = new Uri("http://localhost/1"), + TargetValue = new Uri("http://localhost/3") + }, + new OpenApiDifference + { + Pointer = "#/flows/authorizationCode", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/flows/clientCredentials", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiOAuthFlow), + SourceValue = null, + TargetValue = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("http://localhost/2") + } + } + } + }; + } + + [Theory] + [MemberData(nameof(GetTestCasesForOpenApiSecuritySchemeComparerShouldSucceed))] + public void OpenApiSecuritySchemeComparerShouldSucceed( + string testCaseName, + OpenApiSecurityScheme source, + OpenApiSecurityScheme target, + List expectedDifferences) + { + _output.WriteLine(testCaseName); + + var comparisonContext = new ComparisonContext(new OpenApiComparerFactory(), _sourceDocument, + _targetDocument); + var comparer = new OpenApiSecuritySchemeComparer(); + comparer.Compare(source, target, comparisonContext); + + var differences = comparisonContext.OpenApiDifferences.ToList(); + + differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); + + differences.ShouldBeEquivalentTo(expectedDifferences); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiTagComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiTagComparerTests.cs new file mode 100644 index 000000000..ea6be3b0e --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiTagComparerTests.cs @@ -0,0 +1,304 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.OpenApi.Tests.Services +{ + [Collection("DefaultSettings")] + public class OpenApiTagComparerTests + { + private readonly ITestOutputHelper _output; + + private readonly OpenApiDocument _sourceDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property7"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + private readonly OpenApiDocument _targetDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + public OpenApiTagComparerTests(ITestOutputHelper output) + { + _output = output; + } + + public static IEnumerable GetTestCasesForOpenApiTagComparerShouldSucceed() + { + // Differences in name, description and external docs + yield return new object[] + { + "Differences in name, description and external docs", + new OpenApiTag + { + Description = "test description", + Name = "test name", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description", + Url = new Uri("http://localhost/doc") + } + }, + new OpenApiTag + { + Description = "test description updated", + Name = "test name updated", + ExternalDocs = new OpenApiExternalDocs + { + Description = "test description updated", + Url = new Uri("http://localhost/updated") + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "test description", + TargetValue = "test description updated" + }, + new OpenApiDifference + { + Pointer = "#/name", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "test name", + TargetValue = "test name updated" + }, + new OpenApiDifference + { + Pointer = "#/externalDocs/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "test description", + TargetValue = "test description updated" + }, + new OpenApiDifference + { + Pointer = "#/externalDocs/url", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(Uri), + SourceValue = new Uri("http://localhost/doc"), + TargetValue = new Uri("http://localhost/updated") + } + } + }; + } + + [Theory] + [MemberData(nameof(GetTestCasesForOpenApiTagComparerShouldSucceed))] + public void OpenApiTagServerVariableComparerShouldSucceed( + string testCaseName, + OpenApiTag source, + OpenApiTag target, + List expectedDifferences) + { + _output.WriteLine(testCaseName); + + var comparisonContext = new ComparisonContext(new OpenApiComparerFactory(), _sourceDocument, + _targetDocument); + var comparer = new OpenApiTagComparer(); + comparer.Compare(source, target, comparisonContext); + + var differences = comparisonContext.OpenApiDifferences.ToList(); + differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); + + differences.ShouldBeEquivalentTo(expectedDifferences); + } + } +} \ No newline at end of file From f9bdc15aa477a3b7c4ca69feeb30d68ccbc98db1 Mon Sep 17 00:00:00 2001 From: Shweta Patil Date: Wed, 10 Oct 2018 14:33:47 -0700 Subject: [PATCH 2/5] FIx review comments --- .../Services/OpenApiComparerBase.cs | 80 +----- .../Services/OpenApiDictionaryComparer.cs | 10 +- .../Services/OpenApiOperationsComparer.cs | 10 +- .../Services/OpenApiParameterComparer.cs | 3 +- .../Services/OpenApiReferenceComparer.cs | 72 +++++ .../Services/OpenApiRequestBodyComparer.cs | 3 +- .../Services/OpenApiSchemaComparer.cs | 126 +++------ .../OpenApiSecurityRequirementComparer.cs | 12 +- .../Services/OpenApiSecuritySchemeComparer.cs | 5 +- .../Services/OpenApiComparerTestCases.cs | 245 ++++++++---------- .../Services/OpenApiComponentsTests.cs | 101 ++++---- .../Services/OpenApiInfoComparerTests.cs | 54 ++-- .../Services/OpenApiParameterComparerTests.cs | 21 +- .../OpenApiRequestBodyComparerTests.cs | 45 ++-- .../Services/OpenApiResponsesComparerTests.cs | 65 +++-- ...OpenApiSecurityRequirementComparerTests.cs | 28 +- 16 files changed, 398 insertions(+), 482 deletions(-) create mode 100644 src/Microsoft.OpenApi/Services/OpenApiReferenceComparer.cs diff --git a/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs b/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs index 4f1e8158d..1fe80577e 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs @@ -166,64 +166,6 @@ internal void Compare(Enum source, Enum target, ComparisonContext compari } } - /// - /// Compares object. - /// - /// The source. - /// The target. - /// The context under which to compare the objects. - internal void Compare( - OpenApiReference sourceReference, - OpenApiReference targetReference, - ComparisonContext comparisonContext) - { - if (sourceReference == null && targetReference == null) - { - return; - } - - if (sourceReference == null || targetReference == null) - { - comparisonContext.AddOpenApiDifference( - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - SourceValue = sourceReference, - TargetValue = targetReference, - OpenApiComparedElementType = typeof(OpenApiReference), - Pointer = comparisonContext.PathString - }); - - return; - } - - if (sourceReference.Id != targetReference.Id || sourceReference.Type != targetReference.Type) - { - WalkAndAddOpenApiDifference( - comparisonContext, - OpenApiConstants.DollarRef, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - SourceValue = sourceReference, - TargetValue = targetReference, - OpenApiComparedElementType = typeof(OpenApiReference) - }); - - return; - } - - var source = (TReference) comparisonContext.SourceDocument.ResolveReference( - sourceReference); - - var target = (TReference) comparisonContext.TargetDocument.ResolveReference( - targetReference); - - comparisonContext - .GetComparer() - .Compare(source, target, comparisonContext); - } - /// /// Compares where TKey is and TValue is /// . @@ -258,14 +200,14 @@ internal void Compare(IDictionary source, IDictionary( - newKeyInTarget, - target[newKeyInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair) + TargetValue = target[newKeyInTarget], + OpenApiComparedElementType = typeof(string) }); } @@ -273,14 +215,14 @@ internal void Compare(IDictionary source, IDictionary( - removedKeyFromSource, - source[removedKeyFromSource]), - OpenApiComparedElementType = typeof(KeyValuePair) + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + SourceValue = source[removedKeyFromSource], + OpenApiComparedElementType = typeof(string) }); } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiDictionaryComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiDictionaryComparer.cs index 0a82ad0b1..34c797f14 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiDictionaryComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiDictionaryComparer.cs @@ -56,10 +56,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - TargetValue = new KeyValuePair( - newKeyInTarget, - targetFragment[newKeyInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair) + TargetValue = targetFragment[newKeyInTarget], + OpenApiComparedElementType = typeof(T) }); } @@ -80,8 +78,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - SourceValue = source, - OpenApiComparedElementType = typeof(KeyValuePair) + SourceValue = source.Value, + OpenApiComparedElementType = typeof(T) }); } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiOperationsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiOperationsComparer.cs index 0aace1a3e..d64351302 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiOperationsComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiOperationsComparer.cs @@ -56,10 +56,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - TargetValue = new KeyValuePair( - newOperationKeyInTarget, - targetOperations[newOperationKeyInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair) + TargetValue = targetOperations[newOperationKeyInTarget], + OpenApiComparedElementType = typeof(OpenApiOperation) }); } @@ -80,8 +78,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - SourceValue = sourceOperation, - OpenApiComparedElementType = typeof(KeyValuePair) + SourceValue = sourceOperation.Value, + OpenApiComparedElementType = typeof(OpenApiOperation) }); } } diff --git a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs index 0fdad0dcb..ee4df45cf 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs @@ -42,7 +42,8 @@ public override void Compare( return; } - Compare(sourceParameter.Reference, targetParameter.Reference, comparisonContext); + new OpenApiReferenceComparer() + .Compare(sourceParameter.Reference, targetParameter.Reference, comparisonContext); WalkAndCompare( comparisonContext, diff --git a/src/Microsoft.OpenApi/Services/OpenApiReferenceComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiReferenceComparer.cs new file mode 100644 index 000000000..9a819db08 --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiReferenceComparer.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiReferenceComparer : OpenApiComparerBase where T : IOpenApiReferenceable + { + /// + /// Compares object. + /// + /// The source. + /// The target. + /// The context under which to compare the objects. + public override void Compare( + OpenApiReference sourceReference, + OpenApiReference targetReference, + ComparisonContext comparisonContext) + { + if (sourceReference == null && targetReference == null) + { + return; + } + + if (sourceReference == null || targetReference == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceReference, + TargetValue = targetReference, + OpenApiComparedElementType = typeof(OpenApiReference), + Pointer = comparisonContext.PathString + }); + + return; + } + + if (sourceReference.Id != targetReference.Id || sourceReference.Type != targetReference.Type) + { + WalkAndAddOpenApiDifference( + comparisonContext, + OpenApiConstants.DollarRef, + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceReference, + TargetValue = targetReference, + OpenApiComparedElementType = typeof(OpenApiReference) + }); + + return; + } + + var source = (T) comparisonContext.SourceDocument.ResolveReference( + sourceReference); + + var target = (T) comparisonContext.TargetDocument.ResolveReference( + targetReference); + + comparisonContext + .GetComparer() + .Compare(source, target, comparisonContext); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs index 2c0895343..d3ca3fc65 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs @@ -42,7 +42,8 @@ public override void Compare( return; } - Compare(sourceRequestBody.Reference, targetRequestBody.Reference, comparisonContext); + new OpenApiReferenceComparer() + .Compare(sourceRequestBody.Reference, targetRequestBody.Reference, comparisonContext); WalkAndCompare(comparisonContext, OpenApiConstants.Description, () => Compare(sourceRequestBody.Description, targetRequestBody.Description, comparisonContext)); diff --git a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs index be86cab01..5d9561209 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System.Collections.Generic; -using System.Linq; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -52,6 +51,36 @@ public override void Compare( comparisonContext.SourceSchemaLoop.Push(sourceSchema); comparisonContext.TargetSchemaLoop.Push(targetSchema); + if (sourceSchema.Reference != null + && targetSchema.Reference != null + && sourceSchema.Reference.Id != targetSchema.Reference.Id) + { + WalkAndAddOpenApiDifference( + comparisonContext, + OpenApiConstants.DollarRef, + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceSchema.Reference?.Id, + TargetValue = targetSchema.Reference?.Id, + OpenApiComparedElementType = typeof(string) + }); + + return; + } + + if (sourceSchema.Reference != null) + { + sourceSchema = (OpenApiSchema) comparisonContext.SourceDocument.ResolveReference( + sourceSchema.Reference); + } + + if (targetSchema.Reference != null) + { + targetSchema = (OpenApiSchema) comparisonContext.TargetDocument.ResolveReference( + targetSchema.Reference); + } + WalkAndCompare( comparisonContext, OpenApiConstants.Title, @@ -115,99 +144,20 @@ public override void Compare( .Compare(sourceSchema.Items, targetSchema.Items, comparisonContext)); } - if (sourceSchema.Reference != null - && targetSchema.Reference != null - && sourceSchema.Reference.Id != targetSchema.Reference.Id) - { - WalkAndAddOpenApiDifference( - comparisonContext, - OpenApiConstants.DollarRef, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - SourceValue = sourceSchema.Reference?.Id, - TargetValue = targetSchema.Reference?.Id, - OpenApiComparedElementType = typeof(string) - }); - - return; - } - - if (sourceSchema.Reference != null) - { - sourceSchema = (OpenApiSchema) comparisonContext.SourceDocument.ResolveReference( - sourceSchema.Reference); - } - - if (targetSchema.Reference != null) - { - targetSchema = (OpenApiSchema) comparisonContext.TargetDocument.ResolveReference( - targetSchema.Reference); - } - - if (targetSchema.Properties != null) - { - IEnumerable newPropertiesInTarget = sourceSchema.Properties == null - ? targetSchema.Properties.Keys - : targetSchema.Properties.Keys.Except(sourceSchema.Properties.Keys) - .ToList(); - - WalkAndCompare(comparisonContext, OpenApiConstants.Properties, () => - { - foreach (var newPropertyInTarget in newPropertiesInTarget) - { - WalkAndAddOpenApiDifference( - comparisonContext, - newPropertyInTarget, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - TargetValue = new KeyValuePair(newPropertyInTarget, - targetSchema.Properties[newPropertyInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair) - }); - } - }); - } - - if (sourceSchema.Properties != null) - { - WalkAndCompare(comparisonContext, OpenApiConstants.Properties, () => - { - foreach (var sourceSchemaProperty in sourceSchema.Properties) - { - if (targetSchema.Properties.ContainsKey(sourceSchemaProperty.Key)) - { - WalkAndCompare( - comparisonContext, - sourceSchemaProperty.Key, - () => comparisonContext - .GetComparer() - .Compare(sourceSchemaProperty.Value, - targetSchema.Properties[sourceSchemaProperty.Key], comparisonContext)); - } - else - { - WalkAndAddOpenApiDifference( - comparisonContext, - sourceSchemaProperty.Key, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - SourceValue = sourceSchemaProperty, - OpenApiComparedElementType = typeof(KeyValuePair) - }); - } - } - }); - } + WalkAndCompare( + comparisonContext, + OpenApiConstants.Properties, + () => comparisonContext + .GetComparer>() + .Compare(sourceSchema.Properties, + targetSchema.Properties, comparisonContext)); WalkAndCompare( comparisonContext, OpenApiConstants.ExternalDocs, () => comparisonContext .GetComparer() - .Compare(sourceSchema?.ExternalDocs, sourceSchema?.ExternalDocs, comparisonContext)); + .Compare(sourceSchema?.ExternalDocs, targetSchema?.ExternalDocs, comparisonContext)); // To Do Compare schema.AllOf // To Do Compare schema.AnyOf diff --git a/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs index 1cc20fa7a..c9e5422e7 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSecurityRequirementComparer.cs @@ -55,10 +55,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - TargetValue = new KeyValuePair>( - newSecuritySchemeInTarget, - targetSecurityRequirement[newSecuritySchemeInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair>) + TargetValue = targetSecurityRequirement[newSecuritySchemeInTarget], + OpenApiComparedElementType = typeof(IList) }); } @@ -76,10 +74,8 @@ public override void Compare( new OpenApiDifference { OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - SourceValue = new KeyValuePair>( - sourceSecurityScheme, - sourceSecurityRequirement[sourceSecurityScheme]), - OpenApiComparedElementType = typeof(KeyValuePair>) + SourceValue = sourceSecurityRequirement[sourceSecurityScheme], + OpenApiComparedElementType = typeof(IList) }); } else diff --git a/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs index 42251769c..bdee35bf4 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSecuritySchemeComparer.cs @@ -41,8 +41,9 @@ public override void Compare( return; } - Compare(sourcecSecurityScheme.Reference, targetSecurityScheme.Reference, - comparisonContext); + new OpenApiReferenceComparer() + .Compare(sourcecSecurityScheme.Reference, targetSecurityScheme.Reference, + comparisonContext); WalkAndCompare(comparisonContext, OpenApiConstants.Description, () => Compare(sourcecSecurityScheme.Description, targetSecurityScheme.Description, comparisonContext)); diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs index 89508813a..7471440a5 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs @@ -150,21 +150,17 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/paths/~1test/patch", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), SourceValue = null, - TargetValue = - new KeyValuePair(OperationType.Patch, - new OpenApiOperation()) + TargetValue = new OpenApiOperation() }, new OpenApiDifference { Pointer = "#/paths/~1test/post", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), TargetValue = null, - SourceValue = - new KeyValuePair(OperationType.Post, - new OpenApiOperation()) + SourceValue = new OpenApiOperation() } } }; @@ -319,20 +315,17 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/paths/~1test/get", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), TargetValue = null, - SourceValue = - new KeyValuePair(OperationType.Get, new OpenApiOperation()) + SourceValue = new OpenApiOperation() }, new OpenApiDifference { Pointer = "#/paths/~1test/post", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), TargetValue = null, - SourceValue = - new KeyValuePair(OperationType.Post, - new OpenApiOperation()) + SourceValue = new OpenApiOperation() } } }; @@ -383,20 +376,17 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/paths/~1test/get", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), SourceValue = null, - TargetValue = - new KeyValuePair(OperationType.Get, new OpenApiOperation()) + TargetValue = new OpenApiOperation() }, new OpenApiDifference { Pointer = "#/paths/~1test/patch", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiOperation), SourceValue = null, - TargetValue = - new KeyValuePair(OperationType.Patch, - new OpenApiOperation()) + TargetValue = new OpenApiOperation() } } }; @@ -737,24 +727,24 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/paths/~1test/get/parameters/0/schema/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/parameters/0/schema/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -762,49 +752,49 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/paths/~1test/get/parameters/0/schema/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/parameters/0/schema/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -812,25 +802,25 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/components/schemas/schemaObject1/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -838,25 +828,25 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/components/schemas/schemaObject2/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject2/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null } } @@ -1129,24 +1119,24 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/paths/~1test/get/requestBody/content/application~1xml/schema/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/requestBody/content/application~1xml/schema/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -1154,34 +1144,34 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/paths/~1test/get/requestBody/content/application~1xml/schema/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/requestBody/content/application~1xml/schema/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference { Pointer = "#/paths/~1test/get/responses/400", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiResponse), SourceValue = null, - TargetValue = new KeyValuePair("400", new OpenApiResponse + TargetValue = new OpenApiResponse { Description = "An updated complex object array response", Content = @@ -1194,32 +1184,32 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( } } } - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/responses/200/content/application~1json/schema/items/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/responses/200/content/application~1json/schema/items/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -1227,49 +1217,49 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/paths/~1test/get/responses/200/content/application~1json/schema/items/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/paths/~1test/get/responses/200/content/application~1json/schema/items/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -1277,25 +1267,25 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/components/schemas/schemaObject1/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject1/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -1303,25 +1293,25 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/components/schemas/schemaObject2/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/components/schemas/schemaObject2/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null } } @@ -1812,46 +1802,30 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( { Pointer = "#/security/0/scheme2", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair>), + OpenApiComparedElementType = typeof(IList), SourceValue = null, - TargetValue = new KeyValuePair>(new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, - Id = "scheme2" - } - }, - new List()) + TargetValue = new List() }, new OpenApiDifference { Pointer = "#/security/1/scheme4", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair>), + OpenApiComparedElementType = typeof(IList), SourceValue = null, - TargetValue = new KeyValuePair>(new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, - Id = "scheme4" - } - }, new List()) + TargetValue = new List() }, new OpenApiDifference { Pointer = "#/components/securitySchemes/scheme4", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSecurityScheme), SourceValue = null, - TargetValue = new KeyValuePair("scheme4", - new OpenApiSecurityScheme - { - Description = "Test", - Name = "Test" - }) + TargetValue = new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + } }, new OpenApiDifference { @@ -1981,13 +1955,12 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/components/securitySchemes/scheme3", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("scheme3", - new OpenApiSecurityScheme - { - Description = "Test", - Name = "Test" - }), + OpenApiComparedElementType = typeof(OpenApiSecurityScheme), + SourceValue = new OpenApiSecurityScheme + { + Description = "Test", + Name = "Test" + }, TargetValue = null }, new OpenApiDifference @@ -2033,16 +2006,8 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Pointer = "#/security/1/scheme2", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair>), - SourceValue = new KeyValuePair>(new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, - Id = "scheme2" - } - }, - new List()), + OpenApiComparedElementType = typeof(IList), + SourceValue = new List(), TargetValue = null } } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs index 2b2fcdfe3..0f44d2d43 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs @@ -375,24 +375,24 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou { Pointer = "#/requestBodies/requestBody1/content/application~1json/schema/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/requestBodies/requestBody1/content/application~1json/schema/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -400,49 +400,49 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou Pointer = "#/requestBodies/requestBody1/content/application~1json/schema/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/requestBodies/requestBody1/content/application~1json/schema/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference { Pointer = "#/schemas/schemaObject1/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/schemas/schemaObject1/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -450,49 +450,49 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou Pointer = "#/schemas/schemaObject1/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/schemas/schemaObject1/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference { Pointer = "#/schemas/schemaObject2/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/schemas/schemaObject2/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -500,25 +500,25 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou Pointer = "#/schemas/schemaObject2/properties/property6/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/schemas/schemaObject2/properties/property6/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null } } @@ -637,33 +637,32 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou { Pointer = "#/requestBodies/requestBody2", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiRequestBody), SourceValue = null, - TargetValue = new KeyValuePair("requestBody2", - new OpenApiRequestBody + TargetValue = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = { - Description = "description", - Required = true, - Content = + ["application/json"] = new OpenApiMediaType { - ["application/json"] = new OpenApiMediaType + Schema = new OpenApiSchema { - Schema = new OpenApiSchema - { - Type = "string" - } + Type = "string" } } - }) + } + } }, new OpenApiDifference { Pointer = "#/schemas/schemaObject2", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("schemaObject2", new OpenApiSchema + TargetValue = new OpenApiSchema { Properties = new Dictionary { @@ -672,7 +671,7 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou Type = "integer" } } - }) + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs index f72518e61..d221eb87b 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiInfoComparerTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; @@ -217,57 +218,56 @@ public OpenApiInfoComparerTests(ITestOutputHelper output) public static IEnumerable GetTestCasesForOpenApiInfoComparerShouldSucceed() { - // Differences in ContentType,Style,Explode and AllowReserved yield return new object[] { - "Differences in ContentType,Style,Explode and AllowReserved", - new OpenApiEncoding + "Differences in title, description, version and tos", + new OpenApiInfo { - ContentType = "image/png, image/jpeg", - Style = ParameterStyle.Simple, - Explode = true, - AllowReserved = true + Title = "Test title", + Description = "Test description", + Version = "Test version", + TermsOfService = new Uri("http://localhost/1") }, - new OpenApiEncoding + new OpenApiInfo { - ContentType = "image/jpeg", - Style = ParameterStyle.Form, - Explode = false, - AllowReserved = false + Title = "Test title updated", + Description = "Test description updated", + Version = "Test version updated", + TermsOfService = new Uri("http://localhost/2") }, new List { new OpenApiDifference { - Pointer = "#/contentType", + Pointer = "#/title", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, OpenApiComparedElementType = typeof(string), - TargetValue = "image/jpeg", - SourceValue = "image/png, image/jpeg" + TargetValue = "Test title updated", + SourceValue = "Test title" }, new OpenApiDifference { - Pointer = "#/style", + Pointer = "#/description", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - OpenApiComparedElementType = typeof(ParameterStyle), - TargetValue = ParameterStyle.Form, - SourceValue = ParameterStyle.Simple + OpenApiComparedElementType = typeof(string), + TargetValue = "Test description updated", + SourceValue = "Test description" }, new OpenApiDifference { - Pointer = "#/explode", + Pointer = "#/version", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - OpenApiComparedElementType = typeof(bool?), - TargetValue = false, - SourceValue = true + OpenApiComparedElementType = typeof(string), + TargetValue = "Test version updated", + SourceValue = "Test version" }, new OpenApiDifference { - Pointer = "#/allowReserved", + Pointer = "#/termsOfService", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - OpenApiComparedElementType = typeof(bool?), - TargetValue = false, - SourceValue = true + OpenApiComparedElementType = typeof(Uri), + TargetValue = new Uri("http://localhost/2"), + SourceValue = new Uri("http://localhost/1") } } }; diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiParameterComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiParameterComparerTests.cs index 4bcc4df02..c5460f886 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiParameterComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiParameterComparerTests.cs @@ -344,29 +344,28 @@ public static IEnumerable GetTestCasesForOpenApiParameterComparerShoul { Pointer = "#/content/text~1plain", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), - TargetValue = new KeyValuePair("text/plain", new OpenApiMediaType + OpenApiComparedElementType = typeof(OpenApiMediaType), + TargetValue = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } - }), + }, SourceValue = null }, new OpenApiDifference { Pointer = "#/content/application~1json", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("application/json", - new OpenApiMediaType + OpenApiComparedElementType = typeof(OpenApiMediaType), + SourceValue = new OpenApiMediaType + { + Schema = new OpenApiSchema { - Schema = new OpenApiSchema - { - Type = "string" - } - }), + Type = "string" + } + }, TargetValue = null }, new OpenApiDifference diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiRequestBodyComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiRequestBodyComparerTests.cs index 211df3c1e..1748dc82c 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiRequestBodyComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiRequestBodyComparerTests.cs @@ -312,30 +312,29 @@ public static IEnumerable GetTestCasesForOpenApiRequestBodyComparerSho { Pointer = "#/content/application~1xml", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiMediaType), SourceValue = null, - TargetValue = new KeyValuePair("application/xml", new OpenApiMediaType + TargetValue = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } - }) + } }, new OpenApiDifference { Pointer = "#/content/application~1json", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiMediaType), TargetValue = null, - SourceValue = new KeyValuePair("application/json", - new OpenApiMediaType + SourceValue = new OpenApiMediaType + { + Schema = new OpenApiSchema { - Schema = new OpenApiSchema - { - Type = "string" - } - }) + Type = "string" + } + } } } }; @@ -513,24 +512,24 @@ public static IEnumerable GetTestCasesForOpenApiRequestBodyComparerSho { Pointer = "#/content/application~1json/schema/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/content/application~1json/schema/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -538,25 +537,25 @@ public static IEnumerable GetTestCasesForOpenApiRequestBodyComparerSho Pointer = "#/content/application~1json/schema/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/content/application~1json/schema/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null } } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiResponsesComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiResponsesComparerTests.cs index 8e61fb3f9..c55897eb9 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiResponsesComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiResponsesComparerTests.cs @@ -336,9 +336,9 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul { Pointer = "#/400", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiResponse), SourceValue = null, - TargetValue = new KeyValuePair("400", new OpenApiResponse + TargetValue = new OpenApiResponse { Description = "An updated complex object array response", Content = @@ -359,15 +359,15 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul } } } - }) + } }, new OpenApiDifference { Pointer = "#/200", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiResponse), TargetValue = null, - SourceValue = new KeyValuePair("200", new OpenApiResponse + SourceValue = new OpenApiResponse { Description = "A complex object array response", Content = @@ -388,7 +388,7 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul } } } - }) + } } } }; @@ -459,32 +459,31 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul { Pointer = "#/200/content/application~1json", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiMediaType), SourceValue = null, - TargetValue = new KeyValuePair("application/json", - new OpenApiMediaType + TargetValue = new OpenApiMediaType + { + Schema = new OpenApiSchema { - Schema = new OpenApiSchema + Type = "array", + Items = new OpenApiSchema { - Type = "array", - Items = new OpenApiSchema + Reference = new OpenApiReference { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "schemaObject1" - } + Type = ReferenceType.Schema, + Id = "schemaObject1" } } - }) + } + } }, new OpenApiDifference { Pointer = "#/200/content/text~1plain", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiMediaType), TargetValue = null, - SourceValue = new KeyValuePair("text/plain", new OpenApiMediaType + SourceValue = new OpenApiMediaType { Schema = new OpenApiSchema { @@ -498,7 +497,7 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul } } } - }) + } } } }; @@ -744,24 +743,24 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul { Pointer = "#/200/content/application~1json/schema/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/200/content/application~1json/schema/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null }, new OpenApiDifference @@ -769,25 +768,25 @@ public static IEnumerable GetTestCasesForOpenApiResponsesComparerShoul Pointer = "#/200/content/application~1json/schema/properties/property6/properties/property6/properties/property5", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair), + OpenApiComparedElementType = typeof(OpenApiSchema), SourceValue = null, - TargetValue = new KeyValuePair("property5", new OpenApiSchema + TargetValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }) + } }, new OpenApiDifference { Pointer = "#/200/content/application~1json/schema/properties/property6/properties/property6/properties/property7", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair), - SourceValue = new KeyValuePair("property7", new OpenApiSchema + OpenApiComparedElementType = typeof(OpenApiSchema), + SourceValue = new OpenApiSchema { Type = "string", MaxLength = 15 - }), + }, TargetValue = null } } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs index a69cb9057..0c1d6f8a0 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiSecurityRequirementComparerTests.cs @@ -150,27 +150,13 @@ public static IEnumerable GetTestCasesForOpenApiSecurityRequirementCom }, new List { - new OpenApiDifference - { - Pointer = "#/scheme3", - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - OpenApiComparedElementType = typeof(KeyValuePair>), - SourceValue = new KeyValuePair>(new OpenApiSecurityScheme - { - Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme3"} - }, new List()), - TargetValue = null - }, new OpenApiDifference { Pointer = "#/scheme4", OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - OpenApiComparedElementType = typeof(KeyValuePair>), + OpenApiComparedElementType = typeof(IList), SourceValue = null, - TargetValue = new KeyValuePair>(new OpenApiSecurityScheme - { - Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "scheme4"} - }, new List()) + TargetValue = new List() }, new OpenApiDifference { @@ -179,6 +165,14 @@ public static IEnumerable GetTestCasesForOpenApiSecurityRequirementCom OpenApiComparedElementType = typeof(string), SourceValue = "Test", TargetValue = "Test Updated" + }, + new OpenApiDifference + { + Pointer = "#/scheme3", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(IList), + SourceValue = new List(), + TargetValue = null } } }; @@ -275,6 +269,8 @@ public void OpenApiSecurityRequirementComparerShouldSucceed( OpenApiSecurityRequirement source, OpenApiSecurityRequirement target, List expectedDifferences) + + { _output.WriteLine(testCaseName); From f3efe853aaba601fd7c0d71774370aff344d9dbe Mon Sep 17 00:00:00 2001 From: Shweta Patil Date: Thu, 11 Oct 2018 15:46:40 -0700 Subject: [PATCH 3/5] Comparer logic for Example --- .../Services/OpenApiAnyComparer.cs | 77 +++ .../Services/OpenApiComparerFactory.cs | 6 +- .../Services/OpenApiComponentsComparer.cs | 9 +- .../Services/OpenApiEncodingComparer.cs | 2 - .../Services/OpenApiExampleComparer.cs | 65 +++ .../Services/OpenApiHeaderComparer.cs | 17 +- .../Services/OpenApiMediaTypeComparer.cs | 19 +- .../Services/OpenApiParameterComparer.cs | 16 +- .../Services/OpenApiPathItemComparer.cs | 2 - .../Services/OpenApiRequestBodyComparer.cs | 2 - .../Services/OpenApiResponseComparer.cs | 1 - .../Services/OpenApiSchemaComparer.cs | 11 +- .../Services/OpenApiServerComparer.cs | 2 - .../Services/OpenApiComparerTestCases.cs | 390 +++++++++++++++ .../Services/OpenApiComparerTests.cs | 40 ++ .../Services/OpenApiComponentsTests.cs | 206 ++++++++ .../Services/OpenApiExampleComparerTests.cs | 461 ++++++++++++++++++ 17 files changed, 1303 insertions(+), 23 deletions(-) create mode 100644 src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs create mode 100644 src/Microsoft.OpenApi/Services/OpenApiExampleComparer.cs create mode 100644 test/Microsoft.OpenApi.Tests/Services/OpenApiExampleComparerTests.cs diff --git a/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs new file mode 100644 index 000000000..4ed13217d --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System; +using System.IO; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Writers; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiAnyComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + IOpenApiAny source, + IOpenApiAny target, + ComparisonContext comparisonContext) + { + if (source == null && target == null) + { + return; + } + + if (source == null || target == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = source, + TargetValue = target, + OpenApiComparedElementType = typeof(IOpenApiAny), + Pointer = comparisonContext.PathString + }); + + return; + } + + var sourceStringWriter = new StringWriter(); + var sourceWriter = new OpenApiJsonWriter(sourceStringWriter); + + source.Write(sourceWriter, OpenApiSpecVersion.OpenApi3_0); + var sourceValue = sourceStringWriter.GetStringBuilder().ToString(); + + var targetStringWriter = new StringWriter(); + var targetWriter = new OpenApiJsonWriter(targetStringWriter); + + target.Write(targetWriter, OpenApiSpecVersion.OpenApi3_0); + var targetValue = targetStringWriter.GetStringBuilder().ToString(); + + if (string.IsNullOrWhiteSpace(sourceValue) && string.IsNullOrWhiteSpace(targetValue)) + { + return; + } + + if (string.Compare(sourceValue, targetValue, StringComparison.CurrentCultureIgnoreCase) != 0) + { + comparisonContext.AddOpenApiDifference(new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = source, + TargetValue = target, + Pointer = comparisonContext.PathString + }); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs b/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs index e5c9a7da5..b1ad1e269 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -55,7 +56,10 @@ public class OpenApiComparerFactory {typeof(IList), new OpenApiOrderedListComparer()}, {typeof(OpenApiExternalDocs), new OpenApiExternalDocsComparer()}, {typeof(OpenApiTag), new OpenApiTagComparer()}, - {typeof(OpenApiSecurityScheme), new OpenApiSecuritySchemeComparer()} + {typeof(OpenApiSecurityScheme), new OpenApiSecuritySchemeComparer()}, + {typeof(OpenApiExample), new OpenApiExampleComparer()}, + {typeof(IDictionary), new OpenApiDictionaryComparer()}, + {typeof(IOpenApiAny), new OpenApiAnyComparer()} }; private readonly Dictionary _typeToComparerMap = new Dictionary(); diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs index 23bdc629f..e1b04dae4 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs @@ -84,10 +84,15 @@ public override void Compare( .GetComparer>() .Compare(sourceComponents.SecuritySchemes, targetComponents.SecuritySchemes, comparisonContext)); - // To Do compare Examples + WalkAndCompare( + comparisonContext, + OpenApiConstants.Examples, + () => comparisonContext + .GetComparer>() + .Compare(sourceComponents.Examples, targetComponents.Examples, comparisonContext)); + // To Do compare Links // To Do compare Callbacks - // To Do compare Extensions } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiEncodingComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiEncodingComparer.cs index 923ab1420..1e1aa7fef 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiEncodingComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiEncodingComparer.cs @@ -60,8 +60,6 @@ public override void Compare( () => comparisonContext .GetComparer>() .Compare(sourceEncoding.Headers, targetEncoding.Headers, comparisonContext)); - - // To Do Compare Extensions } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiExampleComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiExampleComparer.cs new file mode 100644 index 000000000..70ab5082f --- /dev/null +++ b/src/Microsoft.OpenApi/Services/OpenApiExampleComparer.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; + +namespace Microsoft.OpenApi.Services +{ + /// + /// Defines behavior for comparing properties of . + /// + public class OpenApiExampleComparer : OpenApiComparerBase + { + /// + /// Executes comparision against source and target . + /// + /// The source. + /// The target. + /// Context under which to compare the source and target. + public override void Compare( + OpenApiExample sourceExample, + OpenApiExample targetExample, + ComparisonContext comparisonContext) + { + if (sourceExample == null && targetExample == null) + { + return; + } + + if (sourceExample == null || targetExample == null) + { + comparisonContext.AddOpenApiDifference( + new OpenApiDifference + { + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + SourceValue = sourceExample, + TargetValue = targetExample, + OpenApiComparedElementType = typeof(OpenApiExample), + Pointer = comparisonContext.PathString + }); + + return; + } + + new OpenApiReferenceComparer() + .Compare(sourceExample.Reference, targetExample.Reference, comparisonContext); + + WalkAndCompare(comparisonContext, OpenApiConstants.Description, + () => Compare(sourceExample.Description, targetExample.Description, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.Summary, + () => Compare(sourceExample.Summary, targetExample.Summary, comparisonContext)); + + WalkAndCompare(comparisonContext, OpenApiConstants.ExternalValue, + () => Compare(sourceExample.ExternalValue, targetExample.ExternalValue, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Value, + () => comparisonContext + .GetComparer() + .Compare(sourceExample.Value, targetExample.Value, comparisonContext)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiHeaderComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiHeaderComparer.cs index b57ff4071..9f25751b2 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiHeaderComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiHeaderComparer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -104,9 +105,19 @@ public override void Compare( .GetComparer() .Compare(sourceHeader.Schema, targetHeader.Schema, comparisonContext)); - // To do compare example - // To do compare examples - // To do compare extensions + WalkAndCompare( + comparisonContext, + OpenApiConstants.Examples, + () => comparisonContext + .GetComparer>() + .Compare(sourceHeader.Examples, targetHeader.Examples, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Example, + () => comparisonContext + .GetComparer() + .Compare(sourceHeader.Example, targetHeader.Example, comparisonContext)); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiMediaTypeComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiMediaTypeComparer.cs index 9578e211d..b93b33e45 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiMediaTypeComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiMediaTypeComparer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -47,7 +48,7 @@ public override void Compare( OpenApiConstants.Schema, () => comparisonContext .GetComparer() - .Compare( sourceMediaType.Schema, targetMediaType.Schema, comparisonContext ) ); + .Compare(sourceMediaType.Schema, targetMediaType.Schema, comparisonContext)); WalkAndCompare( comparisonContext, @@ -56,9 +57,19 @@ public override void Compare( .GetComparer>() .Compare(sourceMediaType.Encoding, sourceMediaType.Encoding, comparisonContext)); - // To Do Compare Example - // To Do Compare Examples - // To Do Compare Extensions + WalkAndCompare( + comparisonContext, + OpenApiConstants.Examples, + () => comparisonContext + .GetComparer>() + .Compare(sourceMediaType.Examples, targetMediaType.Examples, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Example, + () => comparisonContext + .GetComparer() + .Compare(sourceMediaType.Example, targetMediaType.Example, comparisonContext)); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs index ee4df45cf..43b185e4e 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -86,8 +87,19 @@ public override void Compare( .GetComparer() .Compare(sourceParameter.Schema, targetParameter.Schema, comparisonContext)); - // To Do Compare Examples - // To Do Compare parameter as IOpenApiExtensible + WalkAndCompare( + comparisonContext, + OpenApiConstants.Examples, + () => comparisonContext + .GetComparer>() + .Compare(sourceParameter.Examples, targetParameter.Examples, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Example, + () => comparisonContext + .GetComparer() + .Compare(sourceParameter.Example, targetParameter.Example, comparisonContext)); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiPathItemComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiPathItemComparer.cs index 84c590eee..6a5657e0f 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiPathItemComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiPathItemComparer.cs @@ -53,8 +53,6 @@ public override void Compare( () => comparisonContext .GetComparer>() .Compare(sourcePathItem?.Servers, targetPathItem?.Servers, comparisonContext)); - - // To Do Compare Extensions } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs index d3ca3fc65..cce69dad2 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiRequestBodyComparer.cs @@ -57,8 +57,6 @@ public override void Compare( () => comparisonContext .GetComparer>() .Compare(sourceRequestBody.Content, targetRequestBody.Content, comparisonContext)); - - //To Do Compare Extensions } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiResponseComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiResponseComparer.cs index 805ad2743..4f47516b7 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiResponseComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiResponseComparer.cs @@ -90,7 +90,6 @@ public override void Compare( .Compare(sourceResponse.Headers, targetResponse.Headers, comparisonContext)); // To Do Compare Link - // To Do Compare Extensions } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs index 5d9561209..2fbb98694 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Collections.Generic; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Services @@ -157,11 +158,17 @@ public override void Compare( OpenApiConstants.ExternalDocs, () => comparisonContext .GetComparer() - .Compare(sourceSchema?.ExternalDocs, targetSchema?.ExternalDocs, comparisonContext)); + .Compare(sourceSchema.ExternalDocs, targetSchema.ExternalDocs, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Example, + () => comparisonContext + .GetComparer() + .Compare(sourceSchema.Example, targetSchema.Example, comparisonContext)); // To Do Compare schema.AllOf // To Do Compare schema.AnyOf - // To Do compare schema as IOpenApiExtensible comparisonContext.SourceSchemaLoop.Pop(); comparisonContext.TargetSchemaLoop.Pop(); diff --git a/src/Microsoft.OpenApi/Services/OpenApiServerComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiServerComparer.cs index 47245bd71..c5d17d443 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiServerComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiServerComparer.cs @@ -54,8 +54,6 @@ public override void Compare( () => comparisonContext .GetComparer>() .Compare(sourceServer.Variables, sourceServer.Variables, comparisonContext)); - - // To Do compare extensions } } } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs index 7471440a5..76df51c25 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTestCases.cs @@ -590,6 +590,19 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Id = "schemaObject2" } } + }, + Example = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } } }, ["schemaObject2"] = new OpenApiSchema @@ -693,6 +706,19 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Id = "schemaObject2" } } + }, + Example = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } } }, ["schemaObject2"] = new OpenApiSchema @@ -848,6 +874,168 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( MaxLength = 15 }, TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/components/schemas/schemaObject1/example", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiDifference + { + Pointer = "#/components/schemas/schemaObject2/properties/property6/example", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiDifference + { + Pointer = + "#/paths/~1test/get/parameters/0/schema/properties/property6/properties/property6/example", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiDifference + { + Pointer = "#/paths/~1test/get/parameters/0/schema/example", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiDifference + { + Pointer = + "#/components/schemas/schemaObject1/properties/property6/properties/property6/example", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } } } }; @@ -885,6 +1073,19 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Id = "schemaObject1", Type = ReferenceType.Schema } + }, + Examples = new Dictionary + { + { + "example1", new OpenApiExample + { + Reference = new OpenApiReference + { + Id = "example1", + Type = ReferenceType.Example + } + } + } } } } @@ -973,6 +1174,50 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( } } } + }, + Examples = new Dictionary + { + ["example1"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + ["example3"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } } } }, @@ -1005,6 +1250,19 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( Id = "schemaObject1", Type = ReferenceType.Schema } + }, + Examples = new Dictionary + { + { + "example1", new OpenApiExample + { + Reference = new OpenApiReference + { + Id = "example1", + Type = ReferenceType.Example + } + } + } } } } @@ -1110,6 +1368,50 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( } } } + }, + Examples = new Dictionary + { + ["example1"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + ["example3"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } } } }, @@ -1313,6 +1615,94 @@ public static IEnumerable GetTestCasesForOpenApiComparerShouldSucceed( MaxLength = 15 }, TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/paths/~1test/get/requestBody/content/application~1xml/examples/example1/value", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + }, + TargetValue = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + new OpenApiDifference + { + Pointer = "#/components/examples/example1/value", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + }, + TargetValue = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relupdate"] = new OpenApiString("sampleRel1") + } + } + } + } + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTests.cs index 306a40abe..277e03da4 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComparerTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; @@ -14,6 +15,43 @@ namespace Microsoft.OpenApi.Tests.Services [Collection("DefaultSettings")] public class OpenApiComparerTests { + public static OpenApiExample AdvancedExample = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + }, + + new OpenApiObject + { + ["status"] = new OpenApiString("Status2"), + ["id"] = new OpenApiString("v2"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/2"), + ["rel"] = new OpenApiString("sampleRel2") + } + } + } + } + } + }; + private readonly ITestOutputHelper _output; public OpenApiComparerTests(ITestOutputHelper output) @@ -33,6 +71,8 @@ public void OpenApiComparerShouldSucceed( { _output.WriteLine(testCaseName); + new OpenApiExampleComparer().Compare(AdvancedExample, AdvancedExample, + new ComparisonContext(new OpenApiComparerFactory(), new OpenApiDocument(), new OpenApiDocument())); var differences = OpenApiComparer.Compare(source, target).ToList(); differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs index 0f44d2d43..06e5d0caa 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiComponentsTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; @@ -675,6 +676,211 @@ public static IEnumerable GetTestCasesForOpenApiComponentsComparerShou } } }; + + // New, removed and updated examples + yield return new object[] + { + "New, removed and updated examples", + new OpenApiComponents + { + Examples = new Dictionary + { + ["example1"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + ["example3"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + } + }, + new OpenApiComponents + { + Examples = new Dictionary + { + ["example2"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + ["example3"] = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + } + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/examples/example2", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, + OpenApiComparedElementType = typeof(OpenApiExample), + SourceValue = null, + TargetValue = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + } + }, + new OpenApiDifference + { + Pointer = "#/examples/example1", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, + OpenApiComparedElementType = typeof(OpenApiExample), + SourceValue = new OpenApiExample + { + Value = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }, + TargetValue = null + }, + new OpenApiDifference + { + Pointer = "#/examples/example3/value", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + SourceValue = new OpenApiObject + { + ["versions"] = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + }, + TargetValue = new OpenApiObject + { + ["versions"] = new OpenApiArray + { + new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + } + } + }; } [Theory] diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiExampleComparerTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiExampleComparerTests.cs new file mode 100644 index 000000000..472c609f5 --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiExampleComparerTests.cs @@ -0,0 +1,461 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Services; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.OpenApi.Tests.Services +{ + [Collection("DefaultSettings")] + public class OpenApiExampleComparerTests + { + private readonly ITestOutputHelper _output; + + private readonly OpenApiDocument _sourceDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property7"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + private readonly OpenApiDocument _targetDocument = new OpenApiDocument + { + Components = new OpenApiComponents + { + Schemas = new Dictionary + { + ["schemaObject1"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject2" + } + } + } + }, + ["schemaObject2"] = new OpenApiSchema + { + Properties = new Dictionary + { + ["property2"] = new OpenApiSchema + { + Type = "integer" + }, + ["property5"] = new OpenApiSchema + { + Type = "string", + MaxLength = 15 + }, + ["property6"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + } + } + } + } + }, + RequestBodies = new Dictionary + { + ["requestBody1"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + }, + ["requestBody2"] = new OpenApiRequestBody + { + Description = "description", + Required = true, + Content = + { + ["application/json"] = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "schemaObject1", + Type = ReferenceType.Schema + } + } + } + } + } + } + } + }; + + public OpenApiExampleComparerTests(ITestOutputHelper output) + { + _output = output; + } + + public static IEnumerable GetTestCasesForOpenApiExampleComparerShouldSucceed() + { + yield return new object[] + { + "Differences in description, summary and external value", + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + ExternalValue = "http://localhost/1" + }, + new OpenApiExample + { + Description = "Test description updated", + Summary = "Test summary updated", + ExternalValue = "http://localhost/2" + }, + new List + { + new OpenApiDifference + { + Pointer = "#/description", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test description", + TargetValue = "Test description updated" + }, + new OpenApiDifference + { + Pointer = "#/summary", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "Test summary", + TargetValue = "Test summary updated" + }, + new OpenApiDifference + { + Pointer = "#/externalValue", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(string), + SourceValue = "http://localhost/1", + TargetValue = "http://localhost/2" + } + } + }; + + yield return new object[] + { + "Null source", + null, + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + ExternalValue = "http://localhost/1" + }, + new List + { + new OpenApiDifference + { + Pointer = "#/", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiExample), + SourceValue = null, + TargetValue = new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + ExternalValue = "http://localhost/1" + } + } + } + }; + + yield return new object[] + { + "Null target", + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + ExternalValue = "http://localhost/1" + }, + null, + new List + { + new OpenApiDifference + { + Pointer = "#/", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(OpenApiExample), + TargetValue = null, + SourceValue = new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + ExternalValue = "http://localhost/1" + } + } + } + }; + + yield return new object[] + { + "Difference in value", + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + Value = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + Value = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relUpdated"] = new OpenApiString("sampleRel1") + } + } + } + }, + new List + { + new OpenApiDifference + { + Pointer = "#/value", + OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, + OpenApiComparedElementType = typeof(IOpenApiAny), + TargetValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["relUpdated"] = new OpenApiString("sampleRel1") + } + } + }, + SourceValue = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + } + } + }; + + yield return new object[] + { + "No differences", + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + Value = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + }, + new OpenApiExample + { + Description = "Test description", + Summary = "Test summary", + Value = new OpenApiObject + { + ["status"] = new OpenApiString("Status1"), + ["id"] = new OpenApiString("v1"), + ["links"] = new OpenApiArray + { + new OpenApiObject + { + ["href"] = new OpenApiString("http://example.com/1"), + ["rel"] = new OpenApiString("sampleRel1") + } + } + } + }, + new List() + }; + } + + [Theory] + [MemberData(nameof(GetTestCasesForOpenApiExampleComparerShouldSucceed))] + public void OpenApiExampleComparerShouldSucceed( + string testCaseName, + OpenApiExample source, + OpenApiExample target, + List expectedDifferences) + { + _output.WriteLine(testCaseName); + + var comparisonContext = new ComparisonContext(new OpenApiComparerFactory(), _sourceDocument, + _targetDocument); + var comparer = new OpenApiExampleComparer(); + comparer.Compare(source, target, comparisonContext); + + var differences = comparisonContext.OpenApiDifferences.ToList(); + differences.Count().ShouldBeEquivalentTo(expectedDifferences.Count); + + differences.ShouldBeEquivalentTo(expectedDifferences); + } + } +} \ No newline at end of file From 17079eeca0578f4da51ab2bd3295d46392488156 Mon Sep 17 00:00:00 2001 From: Shweta Patil Date: Thu, 11 Oct 2018 16:01:32 -0700 Subject: [PATCH 4/5] Fix merge issues --- .../Services/OpenApiComponentsComparer.cs | 16 ++- .../Services/OpenApiSchemaComparer.cs | 103 ++++-------------- 2 files changed, 33 insertions(+), 86 deletions(-) diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs index 98825e69c..e1b04dae4 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs @@ -77,8 +77,20 @@ public override void Compare( .GetComparer>() .Compare(sourceComponents.Headers, targetComponents.Headers, comparisonContext)); - // To Do compare Examples - // To Do compare SecuritySchemes + WalkAndCompare( + comparisonContext, + OpenApiConstants.SecuritySchemes, + () => comparisonContext + .GetComparer>() + .Compare(sourceComponents.SecuritySchemes, targetComponents.SecuritySchemes, comparisonContext)); + + WalkAndCompare( + comparisonContext, + OpenApiConstants.Examples, + () => comparisonContext + .GetComparer>() + .Compare(sourceComponents.Examples, targetComponents.Examples, comparisonContext)); + // To Do compare Links // To Do compare Callbacks } diff --git a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs index f26178073..2fbb98694 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiSchemaComparer.cs @@ -145,92 +145,27 @@ public override void Compare( .Compare(sourceSchema.Items, targetSchema.Items, comparisonContext)); } - if (sourceSchema.Reference != null - && targetSchema.Reference != null - && sourceSchema.Reference.Id != targetSchema.Reference.Id) - { - WalkAndAddOpenApiDifference( - comparisonContext, - OpenApiConstants.DollarRef, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update, - SourceValue = sourceSchema.Reference?.Id, - TargetValue = targetSchema.Reference?.Id, - OpenApiComparedElementType = typeof(string) - }); - - return; - } - - if (sourceSchema.Reference != null) - { - sourceSchema = (OpenApiSchema) comparisonContext.SourceDocument.ResolveReference( - sourceSchema.Reference); - } - - if (targetSchema.Reference != null) - { - targetSchema = (OpenApiSchema) comparisonContext.TargetDocument.ResolveReference( - targetSchema.Reference); - } + WalkAndCompare( + comparisonContext, + OpenApiConstants.Properties, + () => comparisonContext + .GetComparer>() + .Compare(sourceSchema.Properties, + targetSchema.Properties, comparisonContext)); - if (targetSchema.Properties != null) - { - IEnumerable newPropertiesInTarget = sourceSchema.Properties == null - ? targetSchema.Properties.Keys - : targetSchema.Properties.Keys.Except(sourceSchema.Properties.Keys) - .ToList(); - - WalkAndCompare(comparisonContext, OpenApiConstants.Properties, () => - { - foreach (var newPropertyInTarget in newPropertiesInTarget) - { - WalkAndAddOpenApiDifference( - comparisonContext, - newPropertyInTarget, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add, - TargetValue = new KeyValuePair(newPropertyInTarget, - targetSchema.Properties[newPropertyInTarget]), - OpenApiComparedElementType = typeof(KeyValuePair) - }); - } - }); - } + WalkAndCompare( + comparisonContext, + OpenApiConstants.ExternalDocs, + () => comparisonContext + .GetComparer() + .Compare(sourceSchema.ExternalDocs, targetSchema.ExternalDocs, comparisonContext)); - if (sourceSchema.Properties != null) - { - WalkAndCompare(comparisonContext, OpenApiConstants.Properties, () => - { - foreach (var sourceSchemaProperty in sourceSchema.Properties) - { - if (targetSchema.Properties.ContainsKey(sourceSchemaProperty.Key)) - { - WalkAndCompare( - comparisonContext, - sourceSchemaProperty.Key, - () => comparisonContext - .GetComparer() - .Compare(sourceSchemaProperty.Value, - targetSchema.Properties[sourceSchemaProperty.Key], comparisonContext)); - } - else - { - WalkAndAddOpenApiDifference( - comparisonContext, - sourceSchemaProperty.Key, - new OpenApiDifference - { - OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove, - SourceValue = sourceSchemaProperty, - OpenApiComparedElementType = typeof(KeyValuePair) - }); - } - } - }); - } + WalkAndCompare( + comparisonContext, + OpenApiConstants.Example, + () => comparisonContext + .GetComparer() + .Compare(sourceSchema.Example, targetSchema.Example, comparisonContext)); // To Do Compare schema.AllOf // To Do Compare schema.AnyOf From 9063d2acf8529afef030c26e6b00855ea9bd6838 Mon Sep 17 00:00:00 2001 From: Shweta Patil Date: Tue, 16 Oct 2018 16:20:27 -0700 Subject: [PATCH 5/5] Fix review comments --- src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs b/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs index 4ed13217d..2b3d2ad11 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiAnyComparer.cs @@ -56,12 +56,7 @@ public override void Compare( target.Write(targetWriter, OpenApiSpecVersion.OpenApi3_0); var targetValue = targetStringWriter.GetStringBuilder().ToString(); - if (string.IsNullOrWhiteSpace(sourceValue) && string.IsNullOrWhiteSpace(targetValue)) - { - return; - } - - if (string.Compare(sourceValue, targetValue, StringComparison.CurrentCultureIgnoreCase) != 0) + if (string.Compare(sourceValue, targetValue, StringComparison.InvariantCulture) != 0) { comparisonContext.AddOpenApiDifference(new OpenApiDifference {