Skip to content

Commit 41340c2

Browse files
committed
Adds tests for validating attribute visibility on schema generation based on attribute capabilities (#1056)
1 parent ba3accf commit 41340c2

3 files changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Text.Json;
2+
using JsonApiDotNetCore.Resources.Annotations;
3+
using TestBuildingBlocks;
4+
using Xunit;
5+
using Xunit.Abstractions;
6+
7+
namespace OpenApiTests.AttributeTypes;
8+
9+
public sealed class AttributeCapabilitiesTests : IClassFixture<OpenApiTestContext<AttributeTypesStartup, AttributeTypesDbContext>>
10+
{
11+
private enum RequestType{ Response, Create, Update }
12+
13+
private static readonly Dictionary<RequestType, AttrCapabilities> CapabilitiesByRequestType = new()
14+
{
15+
{ RequestType.Response, AttrCapabilities.AllowView },
16+
{ RequestType.Create, AttrCapabilities.AllowCreate },
17+
{ RequestType.Update, AttrCapabilities.AllowChange }
18+
};
19+
20+
private static readonly Dictionary<RequestType, string> SchemaPathByRequestType = new()
21+
{
22+
{ RequestType.Response, "components.schemas.attributesInBookResponse.allOf[1].properties" },
23+
{ RequestType.Create, "components.schemas.attributesInCreateBookRequest.allOf[1].properties" },
24+
{ RequestType.Update, "components.schemas.attributesInUpdateBookRequest.allOf[1].properties" }
25+
};
26+
27+
private static readonly Dictionary<AttrCapabilities, List<string>> BookModelAttrsByCapability = new()
28+
{
29+
{ AttrCapabilities.AllowView, ["title", "isbn", "publishedOn"] },
30+
{ AttrCapabilities.AllowChange, ["title", "internalNotes"] },
31+
{ AttrCapabilities.AllowCreate, ["draftContent"] },
32+
{ AttrCapabilities.None, ["secretCode"] }
33+
};
34+
35+
private readonly OpenApiTestContext<AttributeTypesStartup, AttributeTypesDbContext> _testContext;
36+
37+
public AttributeCapabilitiesTests(
38+
OpenApiTestContext<AttributeTypesStartup, AttributeTypesDbContext> testContext,
39+
ITestOutputHelper output)
40+
{
41+
_testContext = testContext;
42+
_testContext.UseController<BooksController>();
43+
_testContext.SetTestOutputHelper(output);
44+
}
45+
46+
[Theory]
47+
[InlineData(RequestType.Response)]
48+
[InlineData(RequestType.Create)]
49+
[InlineData(RequestType.Update)]
50+
private async Task Generated_Schema_Includes_Only_Expected_Attrs_For_Request_Type_Async(RequestType requestType)
51+
{
52+
// Arrange
53+
string path = SchemaPathByRequestType[requestType];
54+
JsonElement document = await _testContext.GetSwaggerDocumentAsync();
55+
JsonElement attrs = document.Should().ContainPath(path);
56+
57+
IList<string> bookExpectedAttrs = BookModelAttrsByCapability[CapabilitiesByRequestType[requestType]];
58+
IList<string> bookUnexpectedAttrs = BookModelAttrsByCapability.SelectMany(kvPair => kvPair.Value)
59+
.Except(bookExpectedAttrs).ToList();
60+
61+
// Assert
62+
foreach (string attrName in bookExpectedAttrs)
63+
{
64+
attrs.Should().ContainProperty(attrName);
65+
}
66+
foreach (string attrName in bookUnexpectedAttrs)
67+
{
68+
attrs.Should().NotContainPath($"properties.{attrName}");
69+
}
70+
}
71+
}

test/OpenApiTests/AttributeTypes/AttributeTypesDbContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace OpenApiTests.AttributeTypes;
1414
public sealed class AttributeTypesDbContext(DbContextOptions<AttributeTypesDbContext> options)
1515
: TestableDbContext(options)
1616
{
17+
public DbSet<Book> Books => Set<Book>();
1718
public DbSet<TypeContainer> TypeContainers => Set<TypeContainer>();
1819

1920
protected override void ConfigureConventions(ModelConfigurationBuilder builder)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using JetBrains.Annotations;
2+
using JsonApiDotNetCore.Resources;
3+
using JsonApiDotNetCore.Resources.Annotations;
4+
5+
namespace OpenApiTests.AttributeTypes;
6+
7+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
8+
[Resource(ControllerNamespace = "OpenApiTests.AttributeTypes")]
9+
public sealed class Book : Identifiable<int>
10+
{
11+
// Visible in GET, PATCH, included in all operations
12+
[Attr(Capabilities = AttrCapabilities.AllowView | AttrCapabilities.AllowChange)]
13+
public string Title { get; set; } = null!;
14+
15+
// Only visible in GET
16+
[Attr(Capabilities = AttrCapabilities.AllowView)]
17+
public string ISBN { get; set; } = null!;
18+
19+
// Only visible in GET
20+
[Attr(Capabilities = AttrCapabilities.AllowView)]
21+
public DateOnly PublishedOn { get; set; }
22+
23+
// Only usable in POST
24+
[Attr(Capabilities = AttrCapabilities.AllowCreate)]
25+
public string DraftContent { get; set; } = null!;
26+
27+
// Only usable in PATCH
28+
[Attr(Capabilities = AttrCapabilities.AllowChange)]
29+
public string InternalNotes { get; set; } = null!;
30+
31+
// No visibility or modifiers whatsoever
32+
[Attr(Capabilities = AttrCapabilities.None)]
33+
public string SecretCode { get; set; } = null!;
34+
}

0 commit comments

Comments
 (0)