Skip to content

Commit a674f47

Browse files
committed
Added comparison logic for
- OpenApiInfo - OpenApiContact - OpenApiLicense - OpenApiExternalDocs - OpenApiSecurityRequirements - OpenApiTag
1 parent 0c86ee2 commit a674f47

23 files changed

+2824
-42
lines changed

src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
57
using Microsoft.OpenApi.Models;
68

79
namespace Microsoft.OpenApi.Services
@@ -46,6 +48,32 @@ internal void Compare(string source, string target, ComparisonContext comparison
4648
}
4749
}
4850

51+
/// <summary>
52+
/// Compares two Uri object.
53+
/// </summary>
54+
/// <param name="source">The source.</param>
55+
/// <param name="target">The target.</param>
56+
/// <param name="comparisonContext">The context under which to compare the objects.</param>
57+
internal void Compare(Uri source, Uri target, ComparisonContext comparisonContext)
58+
{
59+
if (source == null && target == null)
60+
{
61+
return;
62+
}
63+
64+
if (source != target)
65+
{
66+
comparisonContext.AddOpenApiDifference(new OpenApiDifference
67+
{
68+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
69+
OpenApiComparedElementType = typeof(Uri),
70+
SourceValue = source,
71+
TargetValue = target,
72+
Pointer = comparisonContext.PathString
73+
});
74+
}
75+
}
76+
4977
/// <summary>
5078
/// Compares two boolean object.
5179
/// </summary>
@@ -138,6 +166,125 @@ internal void Compare<TEnum>(Enum source, Enum target, ComparisonContext compari
138166
}
139167
}
140168

169+
/// <summary>
170+
/// Compares <see cref="OpenApiReference"/> object.
171+
/// </summary>
172+
/// <param name="sourceReference">The source.</param>
173+
/// <param name="targetReference">The target.</param>
174+
/// <param name="comparisonContext">The context under which to compare the objects.</param>
175+
internal void Compare<TReference>(
176+
OpenApiReference sourceReference,
177+
OpenApiReference targetReference,
178+
ComparisonContext comparisonContext)
179+
{
180+
if (sourceReference == null && targetReference == null)
181+
{
182+
return;
183+
}
184+
185+
if (sourceReference == null || targetReference == null)
186+
{
187+
comparisonContext.AddOpenApiDifference(
188+
new OpenApiDifference
189+
{
190+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
191+
SourceValue = sourceReference,
192+
TargetValue = targetReference,
193+
OpenApiComparedElementType = typeof(OpenApiReference),
194+
Pointer = comparisonContext.PathString
195+
});
196+
197+
return;
198+
}
199+
200+
if (sourceReference.Id != targetReference.Id || sourceReference.Type != targetReference.Type)
201+
{
202+
WalkAndAddOpenApiDifference(
203+
comparisonContext,
204+
OpenApiConstants.DollarRef,
205+
new OpenApiDifference
206+
{
207+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
208+
SourceValue = sourceReference,
209+
TargetValue = targetReference,
210+
OpenApiComparedElementType = typeof(OpenApiReference)
211+
});
212+
213+
return;
214+
}
215+
216+
var source = (TReference) comparisonContext.SourceDocument.ResolveReference(
217+
sourceReference);
218+
219+
var target = (TReference) comparisonContext.TargetDocument.ResolveReference(
220+
targetReference);
221+
222+
comparisonContext
223+
.GetComparer<TReference>()
224+
.Compare(source, target, comparisonContext);
225+
}
226+
227+
/// <summary>
228+
/// Compares <see cref="IDictionary{TKey,TValue}"/> where TKey is <see cref="string"/> and TValue is
229+
/// <see cref="string"/>.
230+
/// </summary>
231+
/// <param name="source">The source.</param>
232+
/// <param name="target">The target.</param>
233+
/// <param name="comparisonContext">The context under which to compare the objects.</param>
234+
internal void Compare(IDictionary<string, string> source, IDictionary<string, string> target,
235+
ComparisonContext comparisonContext)
236+
{
237+
if (source == null && target == null)
238+
{
239+
return;
240+
}
241+
242+
if (source == null || target == null)
243+
{
244+
comparisonContext.AddOpenApiDifference(
245+
new OpenApiDifference
246+
{
247+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
248+
SourceValue = source,
249+
TargetValue = target,
250+
OpenApiComparedElementType = typeof(IDictionary<string, T>),
251+
Pointer = comparisonContext.PathString
252+
});
253+
254+
return;
255+
}
256+
257+
var newKeysInTarget = target.Keys.Except(source.Keys).ToList();
258+
259+
foreach (var newKeyInTarget in newKeysInTarget)
260+
{
261+
comparisonContext.AddOpenApiDifference(
262+
new OpenApiDifference
263+
{
264+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add,
265+
TargetValue = new KeyValuePair<string, string>(
266+
newKeyInTarget,
267+
target[newKeyInTarget]),
268+
OpenApiComparedElementType = typeof(KeyValuePair<string, string>)
269+
});
270+
}
271+
272+
var removedKeysFromSource = source.Keys.Except(target.Keys).ToList();
273+
274+
foreach (var removedKeyFromSource in removedKeysFromSource)
275+
{
276+
comparisonContext.AddOpenApiDifference(
277+
new OpenApiDifference
278+
{
279+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add,
280+
TargetValue = new KeyValuePair<string, string>(
281+
removedKeyFromSource,
282+
source[removedKeyFromSource]),
283+
OpenApiComparedElementType = typeof(KeyValuePair<string, string>)
284+
});
285+
}
286+
}
287+
141288
/// <summary>
142289
/// Adds a segment to the context path to enable pointing to the current location in the document.
143290
/// </summary>

src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,29 @@ public class OpenApiComparerFactory
3333
{typeof(IDictionary<string, OpenApiParameter>), new OpenApiDictionaryComparer<OpenApiParameter>()},
3434
{typeof(IDictionary<string, OpenApiRequestBody>), new OpenApiDictionaryComparer<OpenApiRequestBody>()},
3535
{typeof(IDictionary<string, OpenApiSchema>), new OpenApiDictionaryComparer<OpenApiSchema>()},
36+
{
37+
typeof(IDictionary<string, OpenApiSecurityScheme>),
38+
new OpenApiDictionaryComparer<OpenApiSecurityScheme>()
39+
},
3640
{typeof(OpenApiHeader), new OpenApiHeaderComparer()},
3741
{typeof(OpenApiRequestBody), new OpenApiRequestBodyComparer()},
3842
{typeof(OpenApiResponse), new OpenApiResponseComparer()},
3943
{typeof(OpenApiComponents), new OpenApiComponentsComparer()},
4044
{typeof(OpenApiEncoding), new OpenApiEncodingComparer()},
4145
{typeof(IList<OpenApiServer>), new OpenApiServersComparer()},
4246
{typeof(OpenApiServer), new OpenApiServerComparer()},
43-
{typeof(OpenApiServerVariable), new OpenApiServerVariableComparer()}
47+
{typeof(OpenApiServerVariable), new OpenApiServerVariableComparer()},
48+
{typeof(OpenApiOAuthFlow), new OpenApiOAuthFlowComparer()},
49+
{typeof(OpenApiOAuthFlows), new OpenApiOAuthFlowsComparer()},
50+
{typeof(OpenApiSecurityRequirement), new OpenApiSecurityRequirementComparer()},
51+
{typeof(OpenApiInfo), new OpenApiInfoComparer()},
52+
{typeof(OpenApiContact), new OpenApiContactComparer()},
53+
{typeof(OpenApiLicense), new OpenApiLicenseComparer()},
54+
{typeof(IList<OpenApiSecurityRequirement>), new OpenApiOrderedListComparer<OpenApiSecurityRequirement>()},
55+
{typeof(IList<OpenApiTag>), new OpenApiOrderedListComparer<OpenApiTag>()},
56+
{typeof(OpenApiExternalDocs), new OpenApiExternalDocsComparer()},
57+
{typeof(OpenApiTag), new OpenApiTagComparer()},
58+
{typeof(OpenApiSecurityScheme), new OpenApiSecuritySchemeComparer()}
4459
};
4560

4661
private readonly Dictionary<Type, object> _typeToComparerMap = new Dictionary<Type, object>();

src/Microsoft.OpenApi/Services/OpenApiComponentsComparer.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,14 @@ public override void Compare(
7777
.GetComparer<IDictionary<string, OpenApiHeader>>()
7878
.Compare(sourceComponents.Headers, targetComponents.Headers, comparisonContext));
7979

80+
WalkAndCompare(
81+
comparisonContext,
82+
OpenApiConstants.SecuritySchemes,
83+
() => comparisonContext
84+
.GetComparer<IDictionary<string, OpenApiSecurityScheme>>()
85+
.Compare(sourceComponents.SecuritySchemes, targetComponents.SecuritySchemes, comparisonContext));
86+
8087
// To Do compare Examples
81-
// To Do compare SecuritySchemes
8288
// To Do compare Links
8389
// To Do compare Callbacks
8490
// To Do compare Extensions
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using Microsoft.OpenApi.Models;
5+
6+
namespace Microsoft.OpenApi.Services
7+
{
8+
/// <summary>
9+
/// Defines behavior for comparing properties of <see cref="OpenApiContact"/>.
10+
/// </summary>
11+
public class OpenApiContactComparer : OpenApiComparerBase<OpenApiContact>
12+
{
13+
/// <summary>
14+
/// Executes comparision against source and target <see cref="OpenApiContact"/>.
15+
/// </summary>
16+
/// <param name="sourceContact">The source.</param>
17+
/// <param name="targetContact">The target.</param>
18+
/// <param name="comparisonContext">Context under which to compare the source and target.</param>
19+
public override void Compare(
20+
OpenApiContact sourceContact,
21+
OpenApiContact targetContact,
22+
ComparisonContext comparisonContext)
23+
{
24+
if (sourceContact == null && targetContact == null)
25+
{
26+
return;
27+
}
28+
29+
if (sourceContact == null || targetContact == null)
30+
{
31+
comparisonContext.AddOpenApiDifference(
32+
new OpenApiDifference
33+
{
34+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
35+
SourceValue = sourceContact,
36+
TargetValue = targetContact,
37+
OpenApiComparedElementType = typeof(OpenApiContact),
38+
Pointer = comparisonContext.PathString
39+
});
40+
41+
return;
42+
}
43+
44+
WalkAndCompare(comparisonContext, OpenApiConstants.Name,
45+
() => Compare(sourceContact.Name, targetContact.Name, comparisonContext));
46+
47+
WalkAndCompare(comparisonContext, OpenApiConstants.Email,
48+
() => Compare(sourceContact.Email, targetContact.Email, comparisonContext));
49+
50+
WalkAndCompare(comparisonContext, OpenApiConstants.Url,
51+
() => Compare(sourceContact.Url, targetContact.Url, comparisonContext));
52+
}
53+
}
54+
}

src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,34 @@ public override void Compare(
4343
.GetComparer<IList<OpenApiServer>>()
4444
.Compare(sourceDocument.Servers, targetDocument.Servers, comparisonContext));
4545

46-
// To Do Compare Info
47-
// To Do Compare Security Requirements
48-
// To Do Compare Tags
49-
// To Do Compare External Docs
50-
// To Do Compare Extensions
46+
WalkAndCompare(
47+
comparisonContext,
48+
OpenApiConstants.Info,
49+
() => comparisonContext
50+
.GetComparer<OpenApiInfo>()
51+
.Compare(sourceDocument.Info, targetDocument.Info, comparisonContext));
52+
53+
WalkAndCompare(
54+
comparisonContext,
55+
OpenApiConstants.Security,
56+
() => comparisonContext
57+
.GetComparer<IList<OpenApiSecurityRequirement>>()
58+
.Compare(sourceDocument.SecurityRequirements, targetDocument.SecurityRequirements,
59+
comparisonContext));
60+
61+
WalkAndCompare(
62+
comparisonContext,
63+
OpenApiConstants.Tags,
64+
() => comparisonContext
65+
.GetComparer<IList<OpenApiTag>>()
66+
.Compare(sourceDocument.Tags, targetDocument.Tags, comparisonContext));
67+
68+
WalkAndCompare(
69+
comparisonContext,
70+
OpenApiConstants.ExternalDocs,
71+
() => comparisonContext
72+
.GetComparer<OpenApiExternalDocs>()
73+
.Compare(sourceDocument.ExternalDocs, targetDocument.ExternalDocs, comparisonContext));
5174
}
5275
}
5376
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using Microsoft.OpenApi.Models;
5+
6+
namespace Microsoft.OpenApi.Services
7+
{
8+
/// <summary>
9+
/// Defines behavior for comparing properties of <see cref="OpenApiExternalDocs"/>.
10+
/// </summary>
11+
public class OpenApiExternalDocsComparer : OpenApiComparerBase<OpenApiExternalDocs>
12+
{
13+
/// <summary>
14+
/// Executes comparision against source and target <see cref="OpenApiExternalDocs"/>.
15+
/// </summary>
16+
/// <param name="sourceDocs">The source.</param>
17+
/// <param name="targetDocs">The target.</param>
18+
/// <param name="comparisonContext">Context under which to compare the source and target.</param>
19+
public override void Compare(OpenApiExternalDocs sourceDocs, OpenApiExternalDocs targetDocs,
20+
ComparisonContext comparisonContext)
21+
{
22+
if (sourceDocs == null && targetDocs == null)
23+
{
24+
return;
25+
}
26+
27+
if (sourceDocs == null || targetDocs == null)
28+
{
29+
comparisonContext.AddOpenApiDifference(
30+
new OpenApiDifference
31+
{
32+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
33+
SourceValue = sourceDocs,
34+
TargetValue = targetDocs,
35+
OpenApiComparedElementType = typeof(OpenApiExternalDocs),
36+
Pointer = comparisonContext.PathString
37+
});
38+
return;
39+
}
40+
41+
WalkAndCompare(comparisonContext, OpenApiConstants.Description,
42+
() => Compare(sourceDocs.Description, targetDocs.Description, comparisonContext));
43+
44+
WalkAndCompare(comparisonContext, OpenApiConstants.Url,
45+
() => Compare(sourceDocs.Url, targetDocs.Url, comparisonContext));
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)