Skip to content

Commit eb6ec97

Browse files
committed
fix(models): preserve tag collection types and comparers in OpenApiDocument copy constructor
1 parent 4f53ad5 commit eb6ec97

2 files changed

Lines changed: 71 additions & 14 deletions

File tree

‎src/Microsoft.OpenApi/Models/OpenApiDocument.cs‎

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,22 @@ public ISet<OpenApiTag>? Tags
8787
}
8888
set
8989
{
90-
if (value is null)
91-
{
92-
_tags = null;
93-
return;
94-
}
95-
_tags = value switch
96-
{
97-
HashSet<OpenApiTag> tags when tags.Comparer != EqualityComparer<OpenApiTag>.Default => value,
98-
SortedSet<OpenApiTag> => value,
90+
_tags = CopyTags(value);
91+
}
92+
}
93+
94+
private static ISet<OpenApiTag>? CopyTags(ISet<OpenApiTag>? tags, bool copy = false)
95+
{
96+
return tags switch
97+
{
98+
null => null,
99+
HashSet<OpenApiTag> hashSet when !ReferenceEquals(hashSet.Comparer, EqualityComparer<OpenApiTag>.Default) => copy ? new HashSet<OpenApiTag>(hashSet, hashSet.Comparer) : hashSet,
100+
SortedSet<OpenApiTag> sorted => copy ? new SortedSet<OpenApiTag>(sorted, sorted.Comparer) : sorted,
99101
#if NET
100-
ImmutableSortedSet<OpenApiTag> => value,
102+
ImmutableSortedSet<OpenApiTag> => tags,
101103
#endif
102-
_ => new HashSet<OpenApiTag>(value, OpenApiTagComparer.Instance),
103-
};
104-
}
104+
_ => new HashSet<OpenApiTag>(tags, OpenApiTagComparer.Instance),
105+
};
105106
}
106107

107108
/// <summary>
@@ -147,7 +148,7 @@ public OpenApiDocument(OpenApiDocument? document)
147148
Webhooks = document?.Webhooks != null ? new Dictionary<string, IOpenApiPathItem>(document.Webhooks) : null;
148149
Components = document?.Components != null ? new(document?.Components) : null;
149150
Security = document?.Security != null ? [.. document.Security] : null;
150-
Tags = document?.Tags != null ? new HashSet<OpenApiTag>(document.Tags, OpenApiTagComparer.Instance) : null;
151+
Tags = CopyTags(document?.Tags, copy: true);
151152
ExternalDocs = document?.ExternalDocs != null ? new(document.ExternalDocs) : null;
152153
Extensions = document?.Extensions != null ? new Dictionary<string, IOpenApiExtension>(document.Extensions) : null;
153154
Metadata = document?.Metadata != null ? new Dictionary<string, object>(document.Metadata) : null;

‎test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,6 +2214,62 @@ public void TagsSupportsImmutableSortedSets()
22142214
Assert.IsType<ImmutableSortedSet<OpenApiTag>>(document.Tags);
22152215
}
22162216

2217+
[Fact]
2218+
public void OpenApiDocumentCopyConstructorPreservesCustomComparer()
2219+
{
2220+
var document = new OpenApiDocument
2221+
{
2222+
Tags = new HashSet<OpenApiTag>(new CaseInsensitiveOpenApiTagEqualityComparer())
2223+
{
2224+
new() { Name = "Tag1" }
2225+
}
2226+
};
2227+
2228+
var copy = new OpenApiDocument(document);
2229+
Assert.NotNull(copy.Tags);
2230+
Assert.False(copy.Tags.Add(new OpenApiTag { Name = "tag1" }));
2231+
Assert.Single(copy.Tags);
2232+
}
2233+
2234+
[Fact]
2235+
public void OpenApiDocumentCopyConstructorPreservesSortedSet()
2236+
{
2237+
var document = new OpenApiDocument
2238+
{
2239+
Tags = new SortedSet<OpenApiTag>(new DescendingOpenApiTagComparer())
2240+
{
2241+
new() { Name = "tagB" },
2242+
new() { Name = "tagA" },
2243+
new() { Name = "tagC" },
2244+
}
2245+
};
2246+
2247+
var copy = new OpenApiDocument(document);
2248+
Assert.IsType<SortedSet<OpenApiTag>>(copy.Tags);
2249+
var copyNames = copy.Tags.Select(t => t.Name);
2250+
Assert.Equal(["tagC", "tagB", "tagA"], copyNames);
2251+
}
2252+
2253+
[Fact]
2254+
public void OpenApiDocumentCopyConstructorPreservesImmutableSortedSet()
2255+
{
2256+
var document = new OpenApiDocument
2257+
{
2258+
Tags = ImmutableSortedSet.Create(
2259+
new DescendingOpenApiTagComparer(),
2260+
[
2261+
new OpenApiTag { Name = "tagB" },
2262+
new OpenApiTag { Name = "tagA" },
2263+
new OpenApiTag { Name = "tagC" },
2264+
]),
2265+
};
2266+
2267+
var copy = new OpenApiDocument(document);
2268+
Assert.IsType<ImmutableSortedSet<OpenApiTag>>(copy.Tags);
2269+
var copyNames = copy.Tags.Select(t => t.Name);
2270+
Assert.Equal(["tagC", "tagB", "tagA"], copyNames);
2271+
}
2272+
22172273
public static TheoryData<OpenApiSpecVersion> OpenApiSpecVersions()
22182274
{
22192275
var values = new TheoryData<OpenApiSpecVersion>();

0 commit comments

Comments
 (0)