Skip to content

Commit

Permalink
Add some nativeaot test cases (#426)
Browse files Browse the repository at this point in the history
Add some validations to the NativeAOT code.
  • Loading branch information
jamescourtney authored Feb 24, 2024
1 parent 39223d3 commit 47bb0bf
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
/src/Tests/FlatSharpEndToEndTests_Generated/FlatSharpEndToEndTestsGenerated.xml
**/BenchmarkDotNet.Artifacts/**
/src/Tests/CompileTests/NativeAot/FlatSharp.generated.cs
/src/Tests/CompileTests/CSharp8/FlatSharp.generated.cs
/src/Tests/Stryker/CodeGen/FlatSharp.cs

14 changes: 14 additions & 0 deletions src/CreateCompilerTestFiles.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
dotnet build FlatSharp.Compiler/FlatSharp.Compiler.csproj -c Release -f net8.0

# Native AOT stuff
$fbs = (gci -r Tests/CompileTests/NativeAot/*.fbs) -join ";"
dotnet FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o Tests/CompileTests/NativeAot

# Stryker stuff
$fbs = (gci -r Tests/Stryker/*.fbs) -join ";"
dotnet FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o Tests/Stryker/CodeGen --mutation-testing-mode

# CSharp8 Stuff
$fbs = (gci -r Tests/FlatsharpEndToEndTests/*.fbs | where Name -ne "AccessModifiers.fbs") -join ";"
dotnet FlatSharp.Compiler/bin/Release/net8.0/FlatSharp.Compiler.dll --nullable-warnings false --normalize-field-names true --input "$fbs" -o Tests/CompileTests/CSharp8

227 changes: 209 additions & 18 deletions src/Tests/CompileTests/NativeAot/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
using FlatSharp;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;

namespace NativeAot
{
internal class Program
{
static void Main(string[] args)
static int ExitCode = 0;

static int Main(string[] args)
{
Test_WriteThrough_ValueStruct();
Test_WriteThrough_RefStruct();
Test_IntVector();
Test_IndexedVector();

Console.WriteLine();
Console.WriteLine("Benchmark -- first pass:");

RunBenchmark();

Console.WriteLine();
Console.WriteLine("Benchmark -- second pass:");

RunBenchmark();

return ExitCode;
}

private static void RunBenchmark()
{
IndexedVector<string, KeyValuePair> indexedVector = new();
for (int i = 0; i < 1000; ++i)
for (int i = 0; i < 500; ++i)
{
indexedVector.Add(new KeyValuePair { Key = Guid.NewGuid().ToString(), Value = i });
}
Expand All @@ -32,13 +55,8 @@ static void Main(string[] args)
byte[] buffer = new byte[maxSize];
int bytesWritten = 0;

for (int i = 0; i < 10; ++i)
{
bytesWritten = Root.Serializer.Write(buffer, root);
}

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000; ++i)
for (int i = 0; i < 2000; ++i)
{
bytesWritten = Root.Serializer.Write(buffer, root);
}
Expand All @@ -49,25 +67,198 @@ static void Main(string[] args)

foreach (var option in Enum.GetValues<FlatBufferDeserializationOption>())
{
Traverse<ArrayInputBuffer>(root, new(buffer), option);
Traverse<MemoryInputBuffer>(root, new(buffer), option);
Traverse<ReadOnlyMemoryInputBuffer>(root, new(buffer), option);
Traverse<ArraySegmentInputBuffer>(root, new(buffer), option);
Traverse<CustomInputBuffer>(root, new(new ArrayInputBuffer(buffer)), option);
BenchmarkTraverse<ArrayInputBuffer>(root, new(buffer), option);
BenchmarkTraverse<MemoryInputBuffer>(root, new(buffer), option);
BenchmarkTraverse<ReadOnlyMemoryInputBuffer>(root, new(buffer), option);
BenchmarkTraverse<ArraySegmentInputBuffer>(root, new(buffer), option);
BenchmarkTraverse<CustomInputBuffer>(root, new(new ArrayInputBuffer(buffer)), option);
Console.WriteLine();
}
}

public static void Traverse<TInputBuffer>(Root original, TInputBuffer buffer, FlatBufferDeserializationOption option)
where TInputBuffer : IInputBuffer
private static void Test_IntVector()
{
for (int i = 0; i < 10; ++i)
RunTest(Test);

static void Test(FlatBufferDeserializationOption option)
{
ParseAndTraverse(original, buffer, option);
Root root = new()
{
IntVector = new[] { 1, 2, 3, 4, 5, }
};

byte[] buffer = new byte[Root.Serializer.GetMaxSize(root)];
Root.Serializer.Write(buffer, root);

Root parsed = Root.Serializer.Parse(buffer, option);

Equal(5, parsed.IntVector.Count);
Equal(1, parsed.IntVector[0]);
Equal(2, parsed.IntVector[1]);
Equal(3, parsed.IntVector[2]);
Equal(4, parsed.IntVector[3]);
Equal(5, parsed.IntVector[4]);
}
}

private static void Test_IndexedVector()
{
RunTest(Test);

static void Test(FlatBufferDeserializationOption option)
{
IndexedVector<string, KeyValuePair> sourceVector = new();
for (int i = 0; i < 1000; ++i)
{
sourceVector.Add(new() { Key = Guid.NewGuid().ToString(), Value = i });
}

Root root = new() { IndexedVector = sourceVector };

byte[] buffer = new byte[Root.Serializer.GetMaxSize(root)];
Root.Serializer.Write(buffer, root);

Root parsed = Root.Serializer.Parse(buffer, option);
IIndexedVector<string, KeyValuePair> parsedVector = parsed.IndexedVector;

Equal(sourceVector.Count, parsedVector.Count);

foreach (var kvp in sourceVector)
{
string key = kvp.Key;
KeyValuePair pair = kvp.Value;

Equal(true, parsedVector.ContainsKey(pair.Key));
Equal(true, parsedVector.TryGetValue(pair.Key, out _));
Equal(pair.Value, parsedVector[pair.Key].Value);
}
}
}

private static void Test_WriteThrough_ValueStruct()
{
RunTest(Test);

static void Test(FlatBufferDeserializationOption option)
{
Root root = new()
{
StructVector = new List<Vec3>
{
new() { X = 1, Y = 2, Z = 3 }
}
};

byte[] buffer = new byte[Root.Serializer.GetMaxSize(root)];
Root.Serializer.Write(buffer, root);

Root parsed = Root.Serializer.Parse(buffer, option);
Root parsed2 = Root.Serializer.Parse(buffer, option);

if (option == FlatBufferDeserializationOption.Greedy || option == FlatBufferDeserializationOption.GreedyMutable)
{
Throws(() => parsed.StructVector[0] = new() { X = 6, Y = 7, Z = 8 });
return;
}

parsed.StructVector[0] = new() { X = 6, Y = 7, Z = 8 };

Equal(6, parsed.StructVector[0].X);
Equal(7, parsed.StructVector[0].Y);
Equal(8, parsed.StructVector[0].Z);

Equal(6, parsed2.StructVector[0].X);
Equal(7, parsed2.StructVector[0].Y);
Equal(8, parsed2.StructVector[0].Z);
}
}

private static void Test_WriteThrough_RefStruct()
{
RunTest(Test);

static void Test(FlatBufferDeserializationOption option)
{
Root root = new()
{
RefStruct = new() { X = 1, Y = 2, Z = 3 }
};

byte[] buffer = new byte[Root.Serializer.GetMaxSize(root)];
Root.Serializer.Write(buffer, root);

Root parsed = Root.Serializer.Parse(buffer, option);
Root parsed2 = Root.Serializer.Parse(buffer, option);

if (option == FlatBufferDeserializationOption.Greedy || option == FlatBufferDeserializationOption.GreedyMutable)
{
Throws(() => parsed.RefStruct.X = 1);
Throws(() => parsed.RefStruct.Y = 1);
Throws(() => parsed.RefStruct.Z = 1);
return;
}

parsed.RefStruct.X = 5;
parsed.RefStruct.Y = 6;
parsed.RefStruct.Z = 7;

Equal(5, parsed.RefStruct.X);
Equal(6, parsed.RefStruct.Y);
Equal(7, parsed.RefStruct.Z);

Equal(5, parsed2.RefStruct.X);
Equal(6, parsed2.RefStruct.Y);
Equal(7, parsed2.RefStruct.Z);
}
}

private static void Throws(Action action)
{
try
{
action();
throw new Exception("Exception did not throw");
}
catch
{
}
}

private static void Equal<T>(T? expected, T? actual)
{
if (Comparer<T>.Default.Compare(expected, actual) != 0)
{
throw new Exception($"Assertion failed. Expected = '{expected}'. Actual = '{actual}'.");
}
}

private static void RunTest(Action<FlatBufferDeserializationOption> test, [CallerMemberName] string caller = "")
{
Run(test, FlatBufferDeserializationOption.Lazy, caller);
Run(test, FlatBufferDeserializationOption.Progressive, caller);
Run(test, FlatBufferDeserializationOption.Greedy, caller);
Run(test, FlatBufferDeserializationOption.GreedyMutable, caller);

static void Run(Action<FlatBufferDeserializationOption> test, FlatBufferDeserializationOption option, string caller)
{
try
{
test(option);
Console.WriteLine($"[Passed] {caller} ({option})");
}
catch (Exception ex)
{
ExitCode = 1;
Console.WriteLine($"[Failed] {caller} ({option}): {ex.GetType().FullName} {ex.Message}");
}
}
}

public static void BenchmarkTraverse<TInputBuffer>(Root original, TInputBuffer buffer, FlatBufferDeserializationOption option)
where TInputBuffer : IInputBuffer
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000; ++i)
for (int i = 0; i < 2000; ++i)
{
ParseAndTraverse(original, buffer, option);
}
Expand Down
16 changes: 13 additions & 3 deletions src/Tests/CompileTests/NativeAot/Schema.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@
attribute "fs_serializer";
attribute "fs_valueStruct";
attribute "fs_vector";
attribute "fs_sharedString";
attribute "fs_writeThrough";

namespace NativeAot;

struct Vec3
struct Vec3 (fs_valueStruct)
{
x : float;
y : float;
z : float;
}

struct Vec3Ref
{
x : float (fs_writeThrough);
y : float (fs_writeThrough);
z : float (fs_writeThrough);
}

table KeyValuePair
{
key : string (key);
key : string (key, fs_sharedString);
value : int;
}

table Root (fs_serializer)
{
struct_vector : [ Vec3 ];
struct_vector : [ Vec3 ] (fs_writeThrough);
int_vector : [ int ];
indexed_vector : [ KeyValuePair ] (fs_vector:"IIndexedVector");
ref_struct : Vec3Ref;
}
Empty file.
43 changes: 43 additions & 0 deletions src/Tests/Stryker/StrykerTests.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34616.47
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGen", "CodeGen\CodeGen.csproj", "{BF559FD5-F496-4721-B762-2EA5A35D1F45}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StrykerTests", "Tests\StrykerTests.csproj", "{0EEC851E-71B5-453F-BE02-645BBC959136}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlatSharp.Runtime", "..\..\FlatSharp.Runtime\FlatSharp.Runtime.csproj", "{F9D588F9-51A0-477E-96A3-9881E33EFB2B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlatSharp.UnityPolyfills", "..\..\FlatSharp.UnityPolyfills\FlatSharp.UnityPolyfills.csproj", "{DEC56E1F-FDEB-4178-A471-4E069DD69EAC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BF559FD5-F496-4721-B762-2EA5A35D1F45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF559FD5-F496-4721-B762-2EA5A35D1F45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF559FD5-F496-4721-B762-2EA5A35D1F45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF559FD5-F496-4721-B762-2EA5A35D1F45}.Release|Any CPU.Build.0 = Release|Any CPU
{0EEC851E-71B5-453F-BE02-645BBC959136}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0EEC851E-71B5-453F-BE02-645BBC959136}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EEC851E-71B5-453F-BE02-645BBC959136}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EEC851E-71B5-453F-BE02-645BBC959136}.Release|Any CPU.Build.0 = Release|Any CPU
{F9D588F9-51A0-477E-96A3-9881E33EFB2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9D588F9-51A0-477E-96A3-9881E33EFB2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9D588F9-51A0-477E-96A3-9881E33EFB2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9D588F9-51A0-477E-96A3-9881E33EFB2B}.Release|Any CPU.Build.0 = Release|Any CPU
{DEC56E1F-FDEB-4178-A471-4E069DD69EAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DEC56E1F-FDEB-4178-A471-4E069DD69EAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DEC56E1F-FDEB-4178-A471-4E069DD69EAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DEC56E1F-FDEB-4178-A471-4E069DD69EAC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DAA100EE-7E3A-4209-985E-2CA4FCB8F1E4}
EndGlobalSection
EndGlobal
4 changes: 2 additions & 2 deletions src/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>7.5.0</Version>
<PackageVersion>7.5.0</PackageVersion>
<Version>7.5.1</Version>
<PackageVersion>7.5.1</PackageVersion>
<AssemblyVersion>$(Version)</AssemblyVersion>
<Authors>James Courtney</Authors>
<Description>FlatSharp is a fast, idiomatic implementation of the FlatBuffer binary format.</Description>
Expand Down

0 comments on commit 47bb0bf

Please sign in to comment.