Skip to content

Commit 7f7f531

Browse files
authored
Merge pull request #687 from immutable/feat/sdk-128-json-serialiser
feat(audience): Json — IL2CPP-safe manual JSON serialiser (SDK-128)
2 parents a680432 + 726126e commit 7f7f531

6 files changed

Lines changed: 419 additions & 0 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Audience package — Unit Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'src/Packages/Audience/**'
8+
- '.github/workflows/test-audience-sdk.yml'
9+
pull_request:
10+
paths:
11+
- 'src/Packages/Audience/**'
12+
- '.github/workflows/test-audience-sdk.yml'
13+
14+
jobs:
15+
test:
16+
name: Unit Tests (.NET)
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Setup .NET
23+
uses: actions/setup-dotnet@v4
24+
with:
25+
dotnet-version: '8.0.x'
26+
27+
- name: Restore dependencies
28+
run: dotnet restore src/Packages/Audience/Tests/Audience.Tests.csproj
29+
30+
- name: Build
31+
run: dotnet build src/Packages/Audience/Tests/Audience.Tests.csproj --no-restore --configuration Release
32+
33+
- name: Run tests
34+
run: >
35+
dotnet test src/Packages/Audience/Tests/Audience.Tests.csproj
36+
--no-build --configuration Release
37+
--logger "trx;LogFileName=test-results.trx"
38+
--logger "console;verbosity=normal"
39+
40+
- name: Upload test results
41+
uses: actions/upload-artifact@v4
42+
if: always()
43+
with:
44+
name: audience-test-results
45+
path: '**/test-results.trx'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using System.Runtime.CompilerServices;
2+
3+
[assembly: InternalsVisibleTo("Immutable.Audience.Runtime.Tests")]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>netstandard2.1</TargetFramework>
4+
<LangVersion>9.0</LangVersion>
5+
<Nullable>disable</Nullable>
6+
<!-- Match the Unity asmdef assembly name so InternalsVisibleTo works in both contexts -->
7+
<AssemblyName>Immutable.Audience.Runtime</AssemblyName>
8+
</PropertyGroup>
9+
<!--
10+
Exclude modules that depend on Unity APIs (added in later PRs).
11+
These compile fine in Unity but cannot be built with the .NET SDK alone.
12+
Update this list as Unity-specific modules are added under Collection/ and Utility/MainThreadDispatcher.cs.
13+
-->
14+
</Project>
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Text;
5+
6+
namespace Immutable.Audience
7+
{
8+
internal static class Json
9+
{
10+
internal static string Serialize(Dictionary<string, object> data)
11+
{
12+
var sb = new StringBuilder();
13+
WriteObject(sb, data);
14+
return sb.ToString();
15+
}
16+
17+
private static void WriteValue(StringBuilder sb, object value)
18+
{
19+
if (value == null)
20+
{
21+
sb.Append("null");
22+
}
23+
else if (value is string s)
24+
{
25+
WriteString(sb, s);
26+
}
27+
else if (value is bool b)
28+
{
29+
sb.Append(b ? "true" : "false");
30+
}
31+
else if (value is int i)
32+
{
33+
sb.Append(i);
34+
}
35+
else if (value is long l)
36+
{
37+
sb.Append(l);
38+
}
39+
else if (value is float f)
40+
{
41+
if (float.IsNaN(f) || float.IsInfinity(f))
42+
sb.Append("null");
43+
else
44+
sb.Append(f.ToString("R", CultureInfo.InvariantCulture));
45+
}
46+
else if (value is double d)
47+
{
48+
if (double.IsNaN(d) || double.IsInfinity(d))
49+
sb.Append("null");
50+
else
51+
sb.Append(d.ToString("R", CultureInfo.InvariantCulture));
52+
}
53+
else if (value is decimal dec)
54+
{
55+
sb.Append(dec.ToString(CultureInfo.InvariantCulture));
56+
}
57+
else if (value is Dictionary<string, object> dict)
58+
{
59+
WriteObject(sb, dict);
60+
}
61+
else if (value is IList list)
62+
{
63+
WriteArray(sb, list);
64+
}
65+
else
66+
{
67+
WriteString(sb, value.ToString());
68+
}
69+
}
70+
71+
private static void WriteObject(StringBuilder sb, Dictionary<string, object> dict)
72+
{
73+
sb.Append('{');
74+
var first = true;
75+
foreach (var kvp in dict)
76+
{
77+
if (!first)
78+
sb.Append(',');
79+
first = false;
80+
WriteString(sb, kvp.Key);
81+
sb.Append(':');
82+
WriteValue(sb, kvp.Value);
83+
}
84+
sb.Append('}');
85+
}
86+
87+
private static void WriteArray(StringBuilder sb, IList list)
88+
{
89+
sb.Append('[');
90+
for (var i = 0; i < list.Count; i++)
91+
{
92+
if (i > 0)
93+
sb.Append(',');
94+
WriteValue(sb, list[i]);
95+
}
96+
sb.Append(']');
97+
}
98+
99+
private static void WriteString(StringBuilder sb, string s)
100+
{
101+
sb.Append('"');
102+
foreach (var c in s)
103+
{
104+
switch (c)
105+
{
106+
case '\\':
107+
sb.Append("\\\\");
108+
break;
109+
case '"':
110+
sb.Append("\\\"");
111+
break;
112+
case '\n':
113+
sb.Append("\\n");
114+
break;
115+
case '\r':
116+
sb.Append("\\r");
117+
break;
118+
case '\t':
119+
sb.Append("\\t");
120+
break;
121+
default:
122+
if (c < 0x20)
123+
sb.Append("\\u").Append(((int)c).ToString("X4"));
124+
else
125+
sb.Append(c);
126+
break;
127+
}
128+
}
129+
sb.Append('"');
130+
}
131+
}
132+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<LangVersion>9.0</LangVersion>
5+
<Nullable>disable</Nullable>
6+
<IsPackable>false</IsPackable>
7+
<!-- Match the Unity asmdef assembly name so InternalsVisibleTo("Immutable.Audience.Runtime.Tests") resolves correctly -->
8+
<AssemblyName>Immutable.Audience.Runtime.Tests</AssemblyName>
9+
</PropertyGroup>
10+
<ItemGroup>
11+
<PackageReference Include="NUnit" Version="3.14.0" />
12+
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
14+
</ItemGroup>
15+
<ItemGroup>
16+
<ProjectReference Include="../Runtime/Audience.Runtime.csproj" />
17+
</ItemGroup>
18+
</Project>

0 commit comments

Comments
 (0)