Skip to content

Commit 7b46b92

Browse files
authored
Merge pull request #8 from voltaney/feature/avoid-forcing-null-deserialization
Avoid forcing null deserialization
2 parents 3a9bb6f + 66238d3 commit 7b46b92

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ on:
88
jobs:
99
build-and-test:
1010
runs-on: windows-latest
11-
1211
steps:
1312
- name: Checkout code
1413
uses: actions/checkout@v4
1514

16-
- name: Setup .NET
17-
uses: actions/setup-dotnet@v4
18-
with:
19-
dotnet-version: 8
15+
# If preinstalled in windows-latest, this step can be skipped
16+
# - name: Setup .NET ${{ matrix.dotnet-version }}
17+
# uses: actions/setup-dotnet@v4
18+
# with:
19+
# dotnet-version: ${{ matrix.dotnet-version }}
2020

2121
- name: Build
2222
run: dotnet build --configuration Release

TouchSenderInterpreter.Test/InterpreterTest.cs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ internal class TestDataGenerator
1414
static readonly DeviceInfo FullDeviceInfo = new(Width: 1920, Height: 1080);
1515
static readonly SingleTouch FullSingleTouch = new(X: 0.5, Y: 0.5);
1616
static readonly TouchSenderPayload FullPayload = new(ExampleId, FullDeviceInfo, FullSingleTouch);
17+
18+
/// <summary>
19+
/// Generate payloads with full data
20+
/// </summary>
1721
public static IEnumerable<object[]> FullPayloads()
1822
{
1923
yield return new object[]
@@ -22,7 +26,9 @@ public static IEnumerable<object[]> FullPayloads()
2226
};
2327
}
2428

25-
// Generate payloads with null values
29+
/// <summary>
30+
/// Generate payloads with some null values
31+
/// </summary>
2632
public static IEnumerable<object[]> PayloadsWithSingleTouchNull()
2733
{
2834
yield return new object[]
@@ -31,7 +37,9 @@ public static IEnumerable<object[]> PayloadsWithSingleTouchNull()
3137
};
3238
}
3339

34-
// Generate payloads with different values
40+
/// <summary>
41+
/// Generate payloads with different values
42+
/// </summary>
3543
public static IEnumerable<object[]> DifferenctPayloads()
3644
{
3745
var payload1 = new TouchSenderPayload(ExampleId, FullDeviceInfo, FullSingleTouch);
@@ -44,7 +52,9 @@ payload1 with {
4452
};
4553
}
4654

47-
// Generate payloads with same values
55+
/// <summary>
56+
/// Generate payloads with same values but different references
57+
/// </summary>
4858
public static IEnumerable<object[]> SamePayloads()
4959
{
5060
var payload1 = new TouchSenderPayload(ExampleId, FullDeviceInfo, FullSingleTouch);
@@ -54,9 +64,14 @@ public static IEnumerable<object[]> SamePayloads()
5464
yield return new object[] { payload1, payload1 with { } };
5565
}
5666
}
67+
5768
// Inject ITestOutputHelper to write logs
5869
public class InterpreterTest(ITestOutputHelper output)
5970
{
71+
72+
/// <summary>
73+
/// Test the Read method with a valid full JSON payload
74+
/// </summary>
6075
[Theory]
6176
[MemberData(nameof(TestDataGenerator.FullPayloads), MemberType = typeof(TestDataGenerator))]
6277
public void Read_ValidFullJson_ReturnsSuccessResult(TouchSenderPayload payload)
@@ -77,6 +92,9 @@ public void Read_ValidFullJson_ReturnsSuccessResult(TouchSenderPayload payload)
7792
Assert.Equal(payload, result.Payload);
7893
}
7994

95+
/// <summary>
96+
/// Test the Read method with a valid JSON payload with null values
97+
/// </summary>
8098
[Theory]
8199
[MemberData(nameof(TestDataGenerator.PayloadsWithSingleTouchNull), MemberType = typeof(TestDataGenerator))]
82100
public void Read_ValidNullJson_ReturnsSuccessResult(TouchSenderPayload payload)
@@ -96,6 +114,10 @@ public void Read_ValidNullJson_ReturnsSuccessResult(TouchSenderPayload payload)
96114
Assert.NotNull(result.Payload);
97115
Assert.Equal(payload, result.Payload);
98116
}
117+
118+
/// <summary>
119+
/// Test the Read method with an invalid JSON payload
120+
/// </summary>
99121
[Theory]
100122
[InlineData("invaid json")] // no closing brace
101123
[InlineData("{")] // missing closing brace
@@ -116,6 +138,42 @@ public void Read_InvalidJson_ReturnsFailureResult(string invalidJson)
116138
Assert.NotNull(result.ErrorMessage);
117139
}
118140

141+
/// <summary>
142+
/// Test the Read method with an empty JSON payload.
143+
///
144+
/// for .NET 9.0 or greater, it should return a failure result
145+
/// for .NET 8.0 or lower, it should return a success result with null payload
146+
/// </summary>
147+
[Theory]
148+
[InlineData("{}")]
149+
[InlineData("{\"Id\":0,\"DeviceInfo\":null,\"SingleTouch\":null}")]
150+
public void Read_EmptyJson_ReturnsUnsucceededResult(string invalidJson)
151+
{
152+
// Log
153+
output.WriteLine(invalidJson);
154+
155+
// Arrange
156+
var input = Encoding.UTF8.GetBytes(invalidJson);
157+
158+
// Act
159+
var result = Interpreter.Read(input);
160+
output.WriteLine(result.ToString());
161+
162+
// Assert
163+
#if NET9_0_OR_GREATER
164+
Assert.False(result.IsSuccess);
165+
Assert.Null(result.Payload);
166+
Assert.NotNull(result.ErrorMessage);
167+
#else
168+
Assert.True(result.IsSuccess);
169+
Assert.NotNull(result.Payload);
170+
Assert.Null(result.ErrorMessage);
171+
#endif
172+
}
173+
174+
/// <summary>
175+
/// Test the Equals method with different payloads
176+
/// </summary>
119177
[Theory]
120178
[MemberData(nameof(TestDataGenerator.DifferenctPayloads), MemberType = typeof(TestDataGenerator))]
121179
public void Equals_DifferentPayloads_ReturnsFalse(TouchSenderPayload payload1, TouchSenderPayload payload2)
@@ -127,6 +185,9 @@ public void Equals_DifferentPayloads_ReturnsFalse(TouchSenderPayload payload1, T
127185
Assert.False(result);
128186
}
129187

188+
/// <summary>
189+
/// Test the Equals method with same payloads
190+
/// </summary>
130191
[Theory]
131192
[MemberData(nameof(TestDataGenerator.SamePayloads), MemberType = typeof(TestDataGenerator))]
132193
public void Equals_SamePayloads_ReturnsTrue(TouchSenderPayload payload1, TouchSenderPayload payload2)

TouchSenderInterpreter.Test/TouchSenderInterpreter.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77

TouchSenderInterpreter/Interpreter.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ public class Interpreter
99

1010
private static readonly JsonSerializerOptions _options = new()
1111
{
12-
PropertyNameCaseInsensitive = true
12+
PropertyNameCaseInsensitive = true,
13+
#if NET9_0_OR_GREATER
14+
RespectNullableAnnotations = true,
15+
RespectRequiredConstructorParameters = true,
16+
#endif
1317
};
1418

1519
public static TouchSenderResult Read(byte[] input)

TouchSenderInterpreter/TouchSenderInterpreter.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<Copyright>Copyright (c) Voltaney 2025</Copyright>

0 commit comments

Comments
 (0)