Skip to content

Commit 67ce54f

Browse files
CopilotScarletKuro
andauthored
Tests: Coverage for JsonDateTimeFormat attribute behavior and DateTimeConverterResolver (#8)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ScarletKuro <19953225+ScarletKuro@users.noreply.github.com>
1 parent 709d47b commit 67ce54f

3 files changed

Lines changed: 407 additions & 0 deletions

File tree

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Serialization.Metadata;
3+
using Scarlet.System.Text.Json.DateTimeConverter.Tests.Model;
4+
5+
namespace Scarlet.System.Text.Json.DateTimeConverter.Tests;
6+
7+
public class DateTimeConverterResolverTests
8+
{
9+
[Fact]
10+
public void DateTimeConverterResolver_ParameterlessConstructor_CanBeCreated()
11+
{
12+
// Arrange & Act
13+
var resolver = new DateTimeConverterResolver();
14+
15+
// Assert
16+
Assert.NotNull(resolver);
17+
}
18+
19+
[Fact]
20+
public void DateTimeConverterResolver_WithJsonSerializerOptionsConstructor_CanBeCreated()
21+
{
22+
// Arrange
23+
var options = new JsonSerializerOptions();
24+
25+
// Act
26+
var resolver = new DateTimeConverterResolver(options);
27+
28+
// Assert
29+
Assert.NotNull(resolver);
30+
}
31+
32+
[Fact]
33+
public void DateTimeConverterResolver_ParameterlessConstructor_GetTypeInfo_ReturnsNull()
34+
{
35+
// Arrange
36+
var resolver = new DateTimeConverterResolver();
37+
38+
// Act
39+
// This exercises the parameterless constructor and the fallback path in GetTypeInfo(Type)
40+
// since _source is null, it calls GetTypeInfo(type, Options), which returns null
41+
var typeInfo = resolver.GetTypeInfo(typeof(SourceGeneratorModelWithAttribute));
42+
43+
// Assert
44+
// Without a source resolver, GetTypeInfo should return null
45+
Assert.Null(typeInfo);
46+
}
47+
48+
[Fact]
49+
public void DateTimeConverterResolver_WithOptionsConstructor_GetTypeInfo_UsesFallbackPath_ReturnsNull()
50+
{
51+
// Arrange
52+
var options = new JsonSerializerOptions
53+
{
54+
TypeInfoResolver = ResolverModelJsonSerializerContext.Default
55+
};
56+
// Create a resolver with options - this exercises the JsonSerializerOptions constructor
57+
var resolver = new DateTimeConverterResolver(options);
58+
59+
// Act
60+
// Call the single-parameter GetTypeInfo
61+
// This will use the fallback path: GetTypeInfo(type, Options) on line 59
62+
// since _source is null (not a JsonSerializerContext)
63+
// However, GetTypeInfo(Type, JsonSerializerOptions) needs _source to work, so it returns null
64+
var typeInfo = resolver.GetTypeInfo(typeof(SourceGeneratorModelWithAttribute));
65+
66+
// Assert
67+
// Without _source set, the resolver can't resolve type info
68+
Assert.Null(typeInfo);
69+
}
70+
71+
[Fact]
72+
public void DateTimeConverterResolver_GetTypeInfo_WithJsonSerializerContextSource_UsesContextOptions()
73+
{
74+
// Arrange
75+
var sourceContext = ResolverModelJsonSerializerContext.Default;
76+
var resolver = new DateTimeConverterResolver(sourceContext);
77+
78+
// Act
79+
// This should use the JsonSerializerContext path in GetTypeInfo(Type)
80+
// where it detects _source is JsonSerializerContext and uses its Options
81+
var typeInfo = resolver.GetTypeInfo(typeof(SourceGeneratorModelWithAttribute));
82+
83+
// Assert
84+
Assert.NotNull(typeInfo);
85+
Assert.Equal(typeof(SourceGeneratorModelWithAttribute), typeInfo.Type);
86+
}
87+
88+
[Fact]
89+
public void DateTimeConverterResolver_WithParameterlessConstructor_CanSerializeWithSourceContext()
90+
{
91+
// Arrange
92+
var resolver = new DateTimeConverterResolver();
93+
var options = new JsonSerializerOptions
94+
{
95+
TypeInfoResolver = JsonTypeInfoResolver.Combine(resolver, ResolverModelJsonSerializerContext.Default),
96+
WriteIndented = true
97+
};
98+
var model = new SourceGeneratorModelWithAttribute
99+
{
100+
DateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
101+
DateOnlyProperty = new DateOnly(2023, 10, 1)
102+
};
103+
104+
// Act
105+
var json = JsonSerializer.Serialize(model, options);
106+
107+
// Assert
108+
// Should use default formats since resolver has no source with attributes
109+
Assert.Contains("\"DateTimeProperty\": \"2023-10-01T12:00:00Z\"", json);
110+
Assert.Contains("\"DateOnlyProperty\": \"2023-10-01\"", json);
111+
}
112+
113+
[Fact]
114+
public void DateTimeConverterResolver_WithOptionsConstructor_StoresOptionsForBaseClass()
115+
{
116+
// Arrange
117+
var options = new JsonSerializerOptions
118+
{
119+
WriteIndented = true,
120+
TypeInfoResolver = ResolverModelJsonSerializerContext.Default
121+
};
122+
// This tests the constructor with JsonSerializerOptions parameter
123+
// The options are passed to the base class JsonSerializerContext
124+
var resolver = new DateTimeConverterResolver(options);
125+
126+
// Act & Assert
127+
// The resolver is successfully created with the options
128+
// The constructor is used when the resolver is part of framework integration
129+
Assert.NotNull(resolver);
130+
}
131+
132+
[Fact]
133+
public void DateTimeConverterResolver_WithIJsonTypeInfoResolverSource_UsesSourceForGetTypeInfo()
134+
{
135+
// Arrange
136+
var sourceResolver = ResolverModelJsonSerializerContext.Default;
137+
var resolver = new DateTimeConverterResolver(sourceResolver);
138+
var options = new JsonSerializerOptions();
139+
140+
// Act
141+
// Call GetTypeInfo with explicit options - this tests the two-parameter GetTypeInfo
142+
var typeInfo = resolver.GetTypeInfo(typeof(SourceGeneratorModelWithAttribute), options);
143+
144+
// Assert
145+
// Should get typeInfo from the source resolver
146+
Assert.NotNull(typeInfo);
147+
Assert.Equal(typeof(SourceGeneratorModelWithAttribute), typeInfo.Type);
148+
}
149+
}
150+
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System.Text.Json;
2+
using Scarlet.System.Text.Json.DateTimeConverter.Tests.Model;
3+
4+
namespace Scarlet.System.Text.Json.DateTimeConverter.Tests;
5+
6+
public partial class ReflectionBasedTests
7+
{
8+
[Fact]
9+
public void ReflectionBased_WithoutResolver_WithFormatAttribute_DoesNotApplyFormat()
10+
{
11+
// Arrange
12+
var options = new JsonSerializerOptions
13+
{
14+
WriteIndented = true
15+
};
16+
var originalModel = new SourceGeneratorModelWithAttribute
17+
{
18+
DateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
19+
NullableDateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
20+
DateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero),
21+
NullableDateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero),
22+
DateOnlyProperty = new DateOnly(2023, 10, 1),
23+
NullableDateOnlyProperty = new DateOnly(2023, 10, 1),
24+
TimeOnlyProperty = new TimeOnly(14, 30, 45),
25+
NullableTimeOnlyProperty = new TimeOnly(14, 30, 45)
26+
};
27+
// Expected JSON with DEFAULT formats (not the custom formats from JsonDateTimeFormat attribute)
28+
const string expectedJson = """
29+
{
30+
"DateTimeProperty": "2023-10-01T12:00:00Z",
31+
"NullableDateTimeProperty": "2023-10-01T12:00:00Z",
32+
"DateTimeOffsetProperty": "2023-10-01T12:00:00+00:00",
33+
"NullableDateTimeOffsetProperty": "2023-10-01T12:00:00+00:00",
34+
"DateOnlyProperty": "2023-10-01",
35+
"NullableDateOnlyProperty": "2023-10-01",
36+
"TimeOnlyProperty": "14:30:45",
37+
"NullableTimeOnlyProperty": "14:30:45"
38+
}
39+
""";
40+
41+
// Act
42+
var json = JsonSerializer.Serialize(originalModel, options);
43+
var deserializedModel = JsonSerializer.Deserialize<SourceGeneratorModelWithAttribute>(json, options);
44+
45+
// Assert
46+
Assert.NotNull(deserializedModel);
47+
Assert.Equal(originalModel.DateTimeProperty, deserializedModel.DateTimeProperty);
48+
Assert.Equal(originalModel.NullableDateTimeProperty, deserializedModel.NullableDateTimeProperty);
49+
Assert.Equal(originalModel.DateTimeOffsetProperty, deserializedModel.DateTimeOffsetProperty);
50+
Assert.Equal(originalModel.NullableDateTimeOffsetProperty, deserializedModel.NullableDateTimeOffsetProperty);
51+
Assert.Equal(originalModel.DateOnlyProperty, deserializedModel.DateOnlyProperty);
52+
Assert.Equal(originalModel.NullableDateOnlyProperty, deserializedModel.NullableDateOnlyProperty);
53+
Assert.Equal(originalModel.TimeOnlyProperty, deserializedModel.TimeOnlyProperty);
54+
Assert.Equal(originalModel.NullableTimeOnlyProperty, deserializedModel.NullableTimeOnlyProperty);
55+
Assert.Equal(expectedJson, json);
56+
}
57+
58+
[Fact]
59+
public void ReflectionBased_WithoutResolver_WithFormatAttribute_WithNullValues_DoesNotApplyFormat()
60+
{
61+
// Arrange
62+
var options = new JsonSerializerOptions
63+
{
64+
WriteIndented = true
65+
};
66+
var originalModel = new SourceGeneratorModelWithAttribute
67+
{
68+
DateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
69+
NullableDateTimeProperty = null,
70+
DateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero),
71+
NullableDateTimeOffsetProperty = null,
72+
DateOnlyProperty = new DateOnly(2023, 10, 1),
73+
NullableDateOnlyProperty = null,
74+
TimeOnlyProperty = new TimeOnly(14, 30, 45),
75+
NullableTimeOnlyProperty = null
76+
};
77+
// Expected JSON with DEFAULT formats (not the custom formats from JsonDateTimeFormat attribute)
78+
const string expectedJson = """
79+
{
80+
"DateTimeProperty": "2023-10-01T12:00:00Z",
81+
"NullableDateTimeProperty": null,
82+
"DateTimeOffsetProperty": "2023-10-01T12:00:00+00:00",
83+
"NullableDateTimeOffsetProperty": null,
84+
"DateOnlyProperty": "2023-10-01",
85+
"NullableDateOnlyProperty": null,
86+
"TimeOnlyProperty": "14:30:45",
87+
"NullableTimeOnlyProperty": null
88+
}
89+
""";
90+
91+
// Act
92+
var json = JsonSerializer.Serialize(originalModel, options);
93+
var deserializedModel = JsonSerializer.Deserialize<SourceGeneratorModelWithAttribute>(json, options);
94+
95+
// Assert
96+
Assert.NotNull(deserializedModel);
97+
Assert.Equal(originalModel.DateTimeProperty, deserializedModel.DateTimeProperty);
98+
Assert.Null(deserializedModel.NullableDateTimeProperty);
99+
Assert.Equal(originalModel.DateTimeOffsetProperty, deserializedModel.DateTimeOffsetProperty);
100+
Assert.Null(deserializedModel.NullableDateTimeOffsetProperty);
101+
Assert.Equal(originalModel.DateOnlyProperty, deserializedModel.DateOnlyProperty);
102+
Assert.Null(deserializedModel.NullableDateOnlyProperty);
103+
Assert.Equal(originalModel.TimeOnlyProperty, deserializedModel.TimeOnlyProperty);
104+
Assert.Null(deserializedModel.NullableTimeOnlyProperty);
105+
Assert.Equal(expectedJson, json);
106+
}
107+
}

0 commit comments

Comments
 (0)