From 86c0d9f764e0260efc456c555a24cb86397ff75e Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Sat, 8 Oct 2022 21:57:25 +0200 Subject: [PATCH] Fix string length detection - Unicode string length detection only checked one byte instead of both - UTF32 string length detection only checked one byte instead of all four - Added Unit tests to test for special chars which would provoke wrong string length detection --- .github/workflows/ci.yml | 4 ++ src/Directory.Build.props | 8 +++ .../HidApi.Net.Benchmark.csproj | 21 +++---- .../HidApi.Net.Tester.csproj | 8 +-- src/HidApi.Net.Tests/HidApi.Net.Tests.csproj | 17 ++++++ src/HidApi.Net.Tests/StringTests.cs | 56 +++++++++++++++++++ src/HidApi.Net.sln | 7 +++ src/HidApi.Net/HidApi.Net.csproj | 5 +- src/HidApi.Net/Internal/Unicode.cs | 10 ++-- src/HidApi.Net/Internal/Utf32.cs | 10 ++-- 10 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 src/Directory.Build.props create mode 100644 src/HidApi.Net.Tests/HidApi.Net.Tests.csproj create mode 100644 src/HidApi.Net.Tests/StringTests.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c48e94a..e8e7d42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,10 @@ jobs: run: dotnet format --no-restore --verify-no-changes working-directory: './src' + - name: Run unit tests + run: dotnet test --no-restore -c ${{ env.configuration }} + working-directory: './src' + - name: Test Linux 64 bit if: ${{ matrix.os == 'ubuntu-22.04' }} run: | diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..3ec396f --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,8 @@ + + + net6.0 + enable + enable + true + + \ No newline at end of file diff --git a/src/HidApi.Net.Benchmark/HidApi.Net.Benchmark.csproj b/src/HidApi.Net.Benchmark/HidApi.Net.Benchmark.csproj index c24b542..7e3312d 100644 --- a/src/HidApi.Net.Benchmark/HidApi.Net.Benchmark.csproj +++ b/src/HidApi.Net.Benchmark/HidApi.Net.Benchmark.csproj @@ -1,16 +1,11 @@ + + Exe + true + false + - - Exe - net6.0 - enable - enable - true - false - - - - - - + + + diff --git a/src/HidApi.Net.Tester/HidApi.Net.Tester.csproj b/src/HidApi.Net.Tester/HidApi.Net.Tester.csproj index 56bfea5..1ebb90c 100644 --- a/src/HidApi.Net.Tester/HidApi.Net.Tester.csproj +++ b/src/HidApi.Net.Tester/HidApi.Net.Tester.csproj @@ -1,16 +1,12 @@ - Exe - net6.0 - enable - enable true false - - + + diff --git a/src/HidApi.Net.Tests/HidApi.Net.Tests.csproj b/src/HidApi.Net.Tests/HidApi.Net.Tests.csproj new file mode 100644 index 0000000..2652a9f --- /dev/null +++ b/src/HidApi.Net.Tests/HidApi.Net.Tests.csproj @@ -0,0 +1,17 @@ + + + false + true + + + + + + + + + + + + + diff --git a/src/HidApi.Net.Tests/StringTests.cs b/src/HidApi.Net.Tests/StringTests.cs new file mode 100644 index 0000000..a092ce3 --- /dev/null +++ b/src/HidApi.Net.Tests/StringTests.cs @@ -0,0 +1,56 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace HidApi.Tests; + +[TestClass] +public class StringTests +{ + [TestMethod] + public void TestUnicode() + { + var data = new byte[6]; + data[0] = 0; + data[1] = 1; + data[2] = 0; + data[3] = 1; + data[4] = 0; + data[5] = 0; + + unsafe + { + fixed (byte* p = data) + { + var str = Unicode.Read(p); + str.Should().Be(new string(new[] { '\u0100', '\u0100' })); + } + } + } + + [TestMethod] + public void TestUtf32() + { + var data = new byte[12]; + data[0] = 0; + data[1] = 1; + data[2] = 0; + data[3] = 0; + data[4] = 0; + data[5] = 1; + data[6] = 0; + data[7] = 0; + data[8] = 0; + data[9] = 0; + data[10] = 0; + data[11] = 0; + + unsafe + { + fixed (byte* p = data) + { + var str = Utf32.Read(p); + str.Should().Be(new string(new[] { '\u0100', '\u0100' })); + } + } + } +} diff --git a/src/HidApi.Net.sln b/src/HidApi.Net.sln index 93aa5f3..6eb0933 100644 --- a/src/HidApi.Net.sln +++ b/src/HidApi.Net.sln @@ -9,12 +9,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt ..\.editorconfig = ..\.editorconfig ..\.github\workflows\ci.yml = ..\.github\workflows\ci.yml ..\.github\dependabot.yml = ..\.github\dependabot.yml + Directory.Build.props = Directory.Build.props EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidApi.Net.Benchmark", "HidApi.Net.Benchmark\HidApi.Net.Benchmark.csproj", "{0AFE95CC-90A8-490A-8FE5-2604A1BB13CE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidApi.Net.Tester", "HidApi.Net.Tester\HidApi.Net.Tester.csproj", "{D7FE837A-D24D-4D56-B538-CCC6968DDF1E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidApi.Net.Tests", "HidApi.Net.Tests\HidApi.Net.Tests.csproj", "{3F7CF192-630B-4981-963A-6BA97F8C65EA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,5 +36,9 @@ Global {D7FE837A-D24D-4D56-B538-CCC6968DDF1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {D7FE837A-D24D-4D56-B538-CCC6968DDF1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {D7FE837A-D24D-4D56-B538-CCC6968DDF1E}.Release|Any CPU.Build.0 = Release|Any CPU + {3F7CF192-630B-4981-963A-6BA97F8C65EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F7CF192-630B-4981-963A-6BA97F8C65EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F7CF192-630B-4981-963A-6BA97F8C65EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F7CF192-630B-4981-963A-6BA97F8C65EA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/HidApi.Net/HidApi.Net.csproj b/src/HidApi.Net/HidApi.Net.csproj index a03e585..9a2bb38 100644 --- a/src/HidApi.Net/HidApi.Net.csproj +++ b/src/HidApi.Net/HidApi.Net.csproj @@ -2,11 +2,7 @@ 0.1.1 - net6.0 - enable - enable HidApi - true true Marcel Tiede @@ -32,6 +28,7 @@ + diff --git a/src/HidApi.Net/Internal/Unicode.cs b/src/HidApi.Net/Internal/Unicode.cs index f55331b..a2f0ba7 100644 --- a/src/HidApi.Net/Internal/Unicode.cs +++ b/src/HidApi.Net/Internal/Unicode.cs @@ -4,11 +4,9 @@ namespace HidApi; internal static class Unicode { - private const int UnicodeSize = 2; - public static ReadOnlySpan CreateBuffer(int size) { - return new byte[size * UnicodeSize]; + return new byte[size * sizeof(ushort)]; } public static unsafe string Read(byte* ptr) @@ -25,13 +23,13 @@ private static unsafe int Length(byte* ptr) //check code to throw exception in case of arithmethic overflow checked { - var current = ptr; + var current = (ushort*) ptr; while (*current != 0) { - current += UnicodeSize; //Jump to next unicode char + current += 1; //Jump to next unicode char } - return (int) (current - ptr); + return (int) ((byte*) current - ptr); } } } diff --git a/src/HidApi.Net/Internal/Utf32.cs b/src/HidApi.Net/Internal/Utf32.cs index feababe..23b4846 100644 --- a/src/HidApi.Net/Internal/Utf32.cs +++ b/src/HidApi.Net/Internal/Utf32.cs @@ -4,11 +4,9 @@ namespace HidApi; internal static class Utf32 { - private const int Utf32Size = 4; - public static ReadOnlySpan CreateBuffer(int size) { - return new byte[size * Utf32Size]; + return new byte[size * sizeof(uint)]; } public static unsafe string Read(byte* ptr) @@ -25,13 +23,13 @@ private static unsafe int Length(byte* ptr) //check code to throw exception in case of arithmethic overflow checked { - var current = ptr; + var current = (uint*) ptr; while (*current != 0) { - current += Utf32Size; //Jump to next UTF32 char + current += 1; //Jump to next UTF32 char } - return (int) (current - ptr); + return (int) ((byte*) current - ptr); } } }