Skip to content

Commit 3c3e74f

Browse files
committed
- Added comparer for Schema, RequestBody, Responses, MediaType
1 parent 0f2626b commit 3c3e74f

20 files changed

+2431
-109
lines changed

src/Microsoft.OpenApi/Services/ComparisonContext.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.Linq;
6+
using Microsoft.OpenApi.Models;
67

78
namespace Microsoft.OpenApi.Services
89
{
@@ -13,15 +14,23 @@ public class ComparisonContext
1314
{
1415
private readonly IList<OpenApiDifference> _openApiDifferences = new List<OpenApiDifference>();
1516
private readonly Stack<string> _path = new Stack<string>();
17+
internal readonly OpenApiDocument SourceDocument;
18+
internal readonly Stack<OpenApiSchema> SourceSchemaLoop = new Stack<OpenApiSchema>();
19+
internal readonly OpenApiDocument TargetDocument;
20+
internal readonly Stack<OpenApiSchema> TargetSchemaLoop = new Stack<OpenApiSchema>();
1621
internal OpenApiComparerFactory OpenApiComparerFactory;
1722

1823
/// <summary>
1924
/// Creates instance of <see cref="ComparisonContext"/>.
2025
/// </summary>
21-
/// <param name="openApiComparerFactory"></param>
22-
public ComparisonContext(OpenApiComparerFactory openApiComparerFactory)
26+
public ComparisonContext(
27+
OpenApiComparerFactory openApiComparerFactory,
28+
OpenApiDocument sourceDocument,
29+
OpenApiDocument targetDocument)
2330
{
2431
OpenApiComparerFactory = openApiComparerFactory;
32+
SourceDocument = sourceDocument;
33+
TargetDocument = targetDocument;
2534
}
2635

2736
/// <summary>

src/Microsoft.OpenApi/Services/OpenApiComparer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static IEnumerable<OpenApiDifference> Compare(OpenApiDocument source, Ope
2626
throw Error.ArgumentNull(nameof(target));
2727
}
2828

29-
var comparisionContext = new ComparisonContext(new OpenApiComparerFactory());
29+
var comparisionContext = new ComparisonContext(new OpenApiComparerFactory(), source, target);
3030

3131
new OpenApiDocumentComparer().Compare(source, target, comparisionContext);
3232

src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
// Licensed under the MIT license.
33

44
using System;
5+
using Microsoft.OpenApi.Models;
56

67
namespace Microsoft.OpenApi.Services
78
{
89
/// <summary>
9-
/// Defines behavior for comparing parts of <see cref="OpenAPiDocument"/> class.
10+
/// Defines behavior for comparing parts of <see cref="OpenApiDocument"/> class.
1011
/// </summary>
1112
/// <typeparam name="T">Type of class to compare.</typeparam>
1213
public abstract class OpenApiComparerBase<T>
@@ -71,6 +72,32 @@ internal void Compare(bool? source, bool? target, ComparisonContext comparisonCo
7172
}
7273
}
7374

75+
/// <summary>
76+
/// Compares two decimal object.
77+
/// </summary>
78+
/// <param name="source">The source.</param>
79+
/// <param name="target">The target.</param>
80+
/// <param name="comparisonContext">The context under which to compare the objects.</param>
81+
internal void Compare(decimal? source, decimal? target, ComparisonContext comparisonContext)
82+
{
83+
if (source == null && target == null)
84+
{
85+
return;
86+
}
87+
88+
if (source != target)
89+
{
90+
comparisonContext.AddOpenApiDifference(new OpenApiDifference
91+
{
92+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
93+
OpenApiComparedElementType = typeof(decimal),
94+
SourceValue = source,
95+
TargetValue = target,
96+
Pointer = comparisonContext.PathString
97+
});
98+
}
99+
}
100+
74101
/// <summary>
75102
/// Adds a segment to the context path to enable pointing to the current location in the document.
76103
/// </summary>

src/Microsoft.OpenApi/Services/OpenApiComparerFactory.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ public class OpenApiComparerFactory
1919
{typeof(OpenApiOperation), new OpenApiOperationComparer()},
2020
{typeof(IDictionary<OperationType, OpenApiOperation>), new OpenApiOperationsComparer()},
2121
{typeof(IList<OpenApiParameter>), new OpenApiParametersComparer()},
22-
{typeof(OpenApiParameter), new OpenApiParameterComparer()}
22+
{typeof(OpenApiParameter), new OpenApiParameterComparer()},
23+
{typeof(OpenApiSchema), new OpenApiSchemaComparer()},
24+
{typeof(OpenApiMediaType), new OpenApiMediaTypeComparer()},
25+
{typeof(IDictionary<string, OpenApiMediaType>), new OpenApiDictionaryComparer<OpenApiMediaType>()},
26+
{typeof(IDictionary<string, OpenApiResponse>), new OpenApiDictionaryComparer<OpenApiResponse>()},
27+
{typeof(OpenApiRequestBody), new OpenApiRequestBodyComparer()},
28+
{typeof(OpenApiResponse), new OpenApiResponseComparer()}
2329
};
2430

2531
private readonly Dictionary<Type, object> _typeToComparerMap = new Dictionary<Type, object>();
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using Microsoft.OpenApi.Interfaces;
7+
8+
namespace Microsoft.OpenApi.Services
9+
{
10+
/// <summary>
11+
/// Defines behavior for comparing <see cref="IDictionary{TKey,TValue}"/> where TKey is <see cref="string"/>
12+
/// and TValue is <see cref="IOpenApiSerializable"/>.
13+
/// </summary>
14+
public class OpenApiDictionaryComparer<T> : OpenApiComparerBase<IDictionary<string, T>>
15+
where T : IOpenApiSerializable
16+
{
17+
/// <summary>
18+
/// Executes comparision against source and target <see cref="IDictionary{TKey, TValue}"/>
19+
/// where TKey is <see cref="string"/> and TValue is <see cref="IOpenApiSerializable"/>.
20+
/// </summary>
21+
/// <param name="sourceFragment">The source.</param>
22+
/// <param name="targetFragment">The target.</param>
23+
/// <param name="comparisonContext">Context under which to compare the source and target.</param>
24+
public override void Compare(
25+
IDictionary<string, T> sourceFragment,
26+
IDictionary<string, T> targetFragment,
27+
ComparisonContext comparisonContext)
28+
{
29+
if (sourceFragment == null && targetFragment == null)
30+
{
31+
return;
32+
}
33+
34+
if (sourceFragment == null || targetFragment == null)
35+
{
36+
comparisonContext.AddOpenApiDifference(
37+
new OpenApiDifference
38+
{
39+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
40+
SourceValue = sourceFragment,
41+
TargetValue = targetFragment,
42+
OpenApiComparedElementType = typeof(IDictionary<string, T>),
43+
Pointer = comparisonContext.PathString
44+
});
45+
46+
return;
47+
}
48+
49+
var newKeysInTarget = targetFragment.Keys.Except(sourceFragment.Keys).ToList();
50+
51+
foreach (var newKeyInTarget in newKeysInTarget)
52+
{
53+
WalkAndAddOpenApiDifference(
54+
comparisonContext,
55+
newKeyInTarget,
56+
new OpenApiDifference
57+
{
58+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add,
59+
TargetValue = new KeyValuePair<string, T>(
60+
newKeyInTarget,
61+
targetFragment[newKeyInTarget]),
62+
OpenApiComparedElementType = typeof(KeyValuePair<string, T>)
63+
});
64+
}
65+
66+
foreach (var source in sourceFragment)
67+
{
68+
if (targetFragment.Keys.Contains(source.Key))
69+
{
70+
WalkAndCompare(comparisonContext, source.Key,
71+
() => comparisonContext
72+
.GetComparer<T>()
73+
.Compare(source.Value, targetFragment[source.Key], comparisonContext));
74+
}
75+
else
76+
{
77+
WalkAndAddOpenApiDifference(
78+
comparisonContext,
79+
source.Key,
80+
new OpenApiDifference
81+
{
82+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove,
83+
SourceValue = source,
84+
OpenApiComparedElementType = typeof(KeyValuePair<string, T>)
85+
});
86+
}
87+
}
88+
}
89+
}
90+
}

src/Microsoft.OpenApi/Services/OpenApiDocumentComparer.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ public override void Compare(
2121
OpenApiDocument targetDocument,
2222
ComparisonContext comparisonContext)
2323
{
24-
comparisonContext.GetComparer<OpenApiPaths>().Compare(
25-
sourceDocument.Paths,
26-
targetDocument.Paths,
27-
comparisonContext);
24+
WalkAndCompare(
25+
comparisonContext,
26+
OpenApiConstants.Paths,
27+
() => comparisonContext
28+
.GetComparer<OpenApiPaths>()
29+
.Compare(sourceDocument.Paths, targetDocument.Paths, comparisonContext));
2830

2931
// To Do Compare Info
3032
// To Do Compare Servers
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="OpenApiMediaType"/>.
10+
/// </summary>
11+
public class OpenApiMediaTypeComparer : OpenApiComparerBase<OpenApiMediaType>
12+
{
13+
/// <summary>
14+
/// Executes comparision against source and target <see cref="OpenApiMediaType"/>.
15+
/// </summary>
16+
/// <param name="sourceMediaType">The source.</param>
17+
/// <param name="targetMediaType">The target.</param>
18+
/// <param name="comparisonContext">Context under which to compare the source and target.</param>
19+
public override void Compare(
20+
OpenApiMediaType sourceMediaType,
21+
OpenApiMediaType targetMediaType,
22+
ComparisonContext comparisonContext)
23+
{
24+
if (sourceMediaType == null && targetMediaType == null)
25+
{
26+
return;
27+
}
28+
29+
if (sourceMediaType == null || targetMediaType == null)
30+
{
31+
comparisonContext.AddOpenApiDifference(
32+
new OpenApiDifference
33+
{
34+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
35+
SourceValue = sourceMediaType,
36+
TargetValue = targetMediaType,
37+
OpenApiComparedElementType = typeof(OpenApiMediaType),
38+
Pointer = comparisonContext.PathString
39+
});
40+
41+
return;
42+
}
43+
44+
comparisonContext
45+
.GetComparer<OpenApiSchema>()
46+
.Compare(sourceMediaType.Schema, targetMediaType.Schema, comparisonContext);
47+
48+
// To Do Compare Example
49+
// To Do Compare Examples
50+
// To Do Compare Encoding
51+
// To Do Compare Extensions
52+
}
53+
}
54+
}

src/Microsoft.OpenApi/Services/OpenApiOperationComparer.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,16 @@ public override void Compare(
5252
.GetComparer<IList<OpenApiParameter>>()
5353
.Compare(sourceOperation?.Parameters, targetOperation?.Parameters, comparisonContext));
5454

55+
WalkAndCompare(comparisonContext, OpenApiConstants.RequestBody,
56+
() => comparisonContext
57+
.GetComparer<OpenApiRequestBody>()
58+
.Compare(sourceOperation?.RequestBody, targetOperation?.RequestBody, comparisonContext));
59+
60+
WalkAndCompare(comparisonContext, OpenApiConstants.Responses,
61+
() => comparisonContext
62+
.GetComparer<IDictionary<string, OpenApiResponse>>()
63+
.Compare(sourceOperation?.Responses, targetOperation?.Responses, comparisonContext));
5564

56-
// Compare Responses
57-
// Compare Request Body
5865
// Compare CallBack
5966
// Compare Security Requirements
6067
// Compare Extensions

src/Microsoft.OpenApi/Services/OpenApiOperationsComparer.cs

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,17 @@ public override void Compare(
3131
return;
3232
}
3333

34-
if (sourceOperations != null && targetOperations == null)
34+
if (sourceOperations == null || targetOperations == null)
3535
{
36-
foreach (var sourceOperation in sourceOperations)
37-
{
38-
WalkAndAddOpenApiDifference(
39-
comparisonContext,
40-
sourceOperation.Key.GetDisplayName(),
41-
new OpenApiDifference
42-
{
43-
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Remove,
44-
SourceValue = sourceOperation,
45-
OpenApiComparedElementType = typeof(KeyValuePair<OperationType, OpenApiOperation>)
46-
});
47-
}
48-
49-
return;
50-
}
51-
52-
if (sourceOperations == null)
53-
{
54-
foreach (var targetOperation in targetOperations)
55-
{
56-
WalkAndAddOpenApiDifference(
57-
comparisonContext,
58-
targetOperation.Key.GetDisplayName(),
59-
new OpenApiDifference
60-
{
61-
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Add,
62-
SourceValue = targetOperation,
63-
OpenApiComparedElementType = typeof(KeyValuePair<OperationType, OpenApiOperation>)
64-
});
65-
}
36+
comparisonContext.AddOpenApiDifference(
37+
new OpenApiDifference
38+
{
39+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
40+
SourceValue = sourceOperations,
41+
TargetValue = targetOperations,
42+
OpenApiComparedElementType = typeof(IDictionary<OperationType, OpenApiOperation>),
43+
Pointer = comparisonContext.PathString
44+
});
6645

6746
return;
6847
}

src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using System.Collections.Generic;
45
using Microsoft.OpenApi.Models;
56

67
namespace Microsoft.OpenApi.Services
@@ -23,10 +24,36 @@ public override void Compare(
2324
{
2425
if (sourceParameter == null && targetParameter == null)
2526
{
27+
return;
2628
}
2729

28-
// To Do Compare Schema
29-
// To Do Compare Content
30+
if (sourceParameter == null || targetParameter == null)
31+
{
32+
comparisonContext.AddOpenApiDifference(
33+
new OpenApiDifference
34+
{
35+
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
36+
SourceValue = sourceParameter,
37+
TargetValue = targetParameter,
38+
OpenApiComparedElementType = typeof(OpenApiParameter),
39+
Pointer = comparisonContext.PathString
40+
});
41+
42+
return;
43+
}
44+
45+
comparisonContext.GetComparer<OpenApiSchema>().Compare(
46+
sourceParameter?.Schema,
47+
targetParameter?.Schema,
48+
comparisonContext);
49+
50+
WalkAndCompare(
51+
comparisonContext,
52+
OpenApiConstants.Content,
53+
() => comparisonContext
54+
.GetComparer<IDictionary<string, OpenApiMediaType>>()
55+
.Compare(sourceParameter.Content, targetParameter.Content, comparisonContext));
56+
3057
// To Do Compare Examples
3158
// To Do Compare parameter as IOpenApiExtensible
3259
}

0 commit comments

Comments
 (0)