Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C# Async with .NET Core Kaitai.Struct.Runtime.Async #17

Open
wants to merge 46 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e8f7a92
Add EditorConfig with default MS configuration.
pluskal Nov 21, 2019
be2c108
Split types to separate files
pluskal Nov 21, 2019
bf275d0
Extract IKaitaiStream interface.
pluskal Nov 21, 2019
c61561a
Use composition instead of inheritance with BinaryReader
pluskal Nov 21, 2019
6e597f8
Add source and EOL in .editorconfig
pluskal Dec 12, 2019
a748b58
Fix XML comment indentation.
pluskal Dec 12, 2019
d634aab
Change file layout -> fileds, constructors, properties. Chage abstrac…
pluskal Dec 12, 2019
aa93ab7
Use string interpolation and clean up redundant code.
pluskal Dec 12, 2019
638cc2d
Add initial configuration for C# Async. Use C# naming conventions.
pluskal Jan 3, 2020
9c85cf0
Extract non KaitaiStream related methods into static Utilities.
pluskal Jan 3, 2020
3436623
Extract KaitaiStreamBase containing utility methods.
pluskal Jan 3, 2020
f534e90
Add simple Async implementation.
pluskal Jan 3, 2020
a91e516
Remove ambigous comments.
pluskal Jan 8, 2020
9812fe7
Add test for Kaitai.Struct.Async runtime.
pluskal Jan 8, 2020
c4af369
Merge branch 'Async' into 'master'
pluskal Jan 20, 2020
c161b7f
Pipe reader
pluskal Jan 22, 2020
797617d
Merge branch 'PipeReader' into 'master'
pluskal Jan 22, 2020
e389f4b
Ensure that ReadResult is not default before first read.
pluskal Jan 29, 2020
bd7655e
Merge branch '4-ensure-that-readresult-is-not-default-before-first-re…
pluskal Jan 29, 2020
885971b
Introduce GetSizeAsync, IsEofAsync. Fix KaitaiAsyncStream Size delega…
pluskal Jan 30, 2020
e048edf
Merge branch '5-position-should-remain-the-same-on-size-pos-iseof-cal…
pluskal Jan 30, 2020
c071b83
IsEofAsync should check the _bitsLeft as well.
pluskal Feb 11, 2020
628f31d
Add Seek with ulong overrides.
pluskal Jun 12, 2020
7c10982
Add ImplicitNullable type.
pluskal Jul 3, 2020
a738aff
Merge branch '6-nullable-t-for-optional-fields-are-call' into 'master'
pluskal Jul 3, 2020
5c1be97
Resolve "ImplicitNullable fails during serialization."
pluskal Jul 13, 2020
029d318
Merge branch '7-implicitnullable-fails-during-serialization' into 'ma…
pluskal Jul 13, 2020
80da927
Allow extensibility in end-user code.
pluskal Jul 17, 2020
d29166e
Merge branch '8-kaitaistreamasync-encapsulating-pipereader-should-imp…
pluskal Jul 17, 2020
2547b57
Add CancellationToken support.
pluskal Oct 1, 2020
3f11b47
Merge branch '9-add-cancellationtoken-support' into 'master'
fukaminakrize Oct 1, 2020
c36377d
Fixing forward seek after read to end followed by position reset on P…
vecera-vojtech Dec 8, 2020
17da91f
Merge branch '10-forward-pipereader-seekasync-on-completed-readresult…
pluskal Dec 8, 2020
99eb420
Fix AdvanceTo that shoudl report buffer end as examined.
pluskal Dec 11, 2020
afba747
Merge branch '11-fix-pipereadercontext-readbyteasync-should-advance-t…
pluskal Dec 11, 2020
87e6ec6
Add Validation* errors as in Java - generalmimon committed on Mar 21,…
pluskal Mar 12, 2021
a290a18
Add UndecidedEndiannessError - generalmimon committed on Mar 21, 2020
pluskal Mar 12, 2021
a0055c6
Implement StringReverse method - generalmimon committed on Mar 21, 2020
pluskal Mar 12, 2021
6eb7a68
Rename ReadBitsInt -> *Be, deprecate ReadBitsInt, Shorten ReadBitsInt…
pluskal Mar 12, 2021
8ae3adf
Simplify ReadBitsIntBe as in https://github.com/kaitai-io/kaitai_stru…
pluskal Mar 12, 2021
11b940d
Add ValidationExprError - generalmimon committed on May 21, 2020
pluskal Mar 12, 2021
94ee1ea
Add byte array support in validation errors - generalmimon committed …
pluskal Mar 12, 2021
3c82433
Mark EnsureFixedContents() as obsolete - generalmimon committed on Oc…
pluskal Mar 12, 2021
829d555
Merge branch 'Async' into 'master'
pluskal Mar 12, 2021
94e1e2f
Exceptions should accept IKaitaiStreamBase
pluskal Mar 18, 2021
149d6cb
Merge branch '12-update-exceptions-to-use-interfaces-ikaitaiasyncstre…
pluskal Mar 18, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Kaitai.Struct.Runtime.Async.Tests/CancelableTestsBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Kaitai.Struct.Runtime.Async.Tests
{
public abstract class CancelableTestsBase
{
protected readonly CancellationToken CancellationToken;

protected CancelableTestsBase(bool isTestingCancellation)
{
CancellationToken = new CancellationToken(isTestingCancellation);
}

protected async Task Evaluate(Func<Task> assertFunc)
{
if (CancellationToken.IsCancellationRequested)
{
await Assert.ThrowsAsync<TaskCanceledException>(assertFunc);
}
else
{
await assertFunc();
}
}

protected async Task EvaluateMaybeCancelled(Func<Task> assertFunc)
{
try
{
await assertFunc();
}
catch (TaskCanceledException)
{
}
}

protected async Task Evaluate<TExpectedException>(Func<Task> assertFunc) where TExpectedException : Exception
{
try
{
await assertFunc();
}
catch (TaskCanceledException)
{
}
catch (TExpectedException)
{
}
}
}
}
166 changes: 166 additions & 0 deletions Kaitai.Struct.Runtime.Async.Tests/Data/BitsData.cs

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions Kaitai.Struct.Runtime.Async.Tests/Data/DecimalData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace Kaitai.Struct.Runtime.Async.Tests
{
public class DecimalData
{
public static IEnumerable<object[]> Decimal4Data =>
new List<(float expected, byte[] streamContent)>
{
(0f, BitConverter.GetBytes(0f)),
(1f, BitConverter.GetBytes(1f)),
(0.1f, BitConverter.GetBytes(0.1f)),
(1.1f, BitConverter.GetBytes(1.1f)),
(float.MinValue, BitConverter.GetBytes(float.MinValue)),
(float.MaxValue, BitConverter.GetBytes(float.MaxValue))
}.Select(t => new object[] {t.expected, t.streamContent});

public static IEnumerable<object[]> Decimal8Data =>
new List<(double expected, byte[] streamContent)>
{
(0d, BitConverter.GetBytes(0d)),
(1d, BitConverter.GetBytes(1d)),
(0.1d, BitConverter.GetBytes(0.1d)),
(1.1d, BitConverter.GetBytes(1.1d)),
(double.MinValue, BitConverter.GetBytes(double.MinValue)),
(double.MaxValue, BitConverter.GetBytes(double.MaxValue))
}.Select(t => new object[] {t.expected, t.streamContent});
}
}
82 changes: 82 additions & 0 deletions Kaitai.Struct.Runtime.Async.Tests/Data/IntegralData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Collections.Generic;
using System.Linq;

namespace Kaitai.Struct.Runtime.Async.Tests
{
public class IntegralData
{
public static IEnumerable<object[]> Integral1Data =>
new List<(sbyte expected, byte[] streamContent)>
{
(0x00, new byte[] {0x00}),
(0x01, new byte[] {0x01}),
(0x7F, new byte[] {0x7F}),
(unchecked((sbyte) 0xFF), new byte[] {0xFF})
}.Select(t => new object[] {t.expected, t.streamContent});

public static IEnumerable<object[]> Integral2Data =>
new List<(short expected, byte[] streamContent)>
{
(0x00, new byte[] {0x00, 0x00}),
(0x01, new byte[] {0x00, 0x01}),
(0xFF, new byte[] {0x00, 0xFF}),
(0x01_FF, new byte[] {0x01, 0xFF}),
(0x7F_FF, new byte[] {0x7F, 0xFF}),
(unchecked((short) 0xFF_FF), new byte[] {0xFF, 0xFF})
}.Select(t => new object[] {t.expected, t.streamContent});

public static IEnumerable<object[]> Integral4Data =>
new List<(int expected, byte[] streamContent)>
{
(0x00, new byte[] {0x00, 0x00, 0x00, 0x00}),
(0x01, new byte[] {0x00, 0x00, 0x00, 0x01}),
(0xFF, new byte[] {0x00, 0x00, 0x00, 0xFF}),
(0x01_FF, new byte[] {0x00, 0x00, 0x01, 0xFF}),
(0x7F_FF, new byte[] {0x00, 0x00, 0x7F, 0xFF}),
(0xFF_FF, new byte[] {0x00, 0x00, 0xFF, 0xFF}),
(0x01_FF_FF, new byte[] {0x00, 0x01, 0xFF, 0xFF}),
(0x7F_FF_FF, new byte[] {0x00, 0x7F, 0xFF, 0xFF}),
(0xFF_FF_FF, new byte[] {0x00, 0xFF, 0xFF, 0xFF}),
(0x01_FF_FF_FF, new byte[] {0x01, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF, new byte[] {0x7F, 0xFF, 0xFF, 0xFF}),
(unchecked((int) 0xFF_FF_FF_FF), new byte[] {0xFF, 0xFF, 0xFF, 0xFF})
}.Select(t => new object[] {t.expected, t.streamContent});

public static IEnumerable<object[]> Integral8Data =>
new List<(long expected, byte[] streamContent)>
{
(0, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
(1, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),
(0xFF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}),

(0x01_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF}),
(0x7F_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF}),
(0xFF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF}),

(0x01_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF}),
(0x7F_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF}),
(0xFF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF}),

(0x01_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF}),
(0xFF_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}),

(0x01_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF}),
(0xFF_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),

(0x01_FF_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(0xFF_FF_FF_FF_FF_FF, new byte[] {0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),

(0x01_FF_FF_FF_FF_FF_FF, new byte[] {0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF_FF_FF_FF, new byte[] {0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(0xFF_FF_FF_FF_FF_FF_FF, new byte[] {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),

(0x01_FF_FF_FF_FF_FF_FF_FF, new byte[] {0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(0x7F_FF_FF_FF_FF_FF_FF_FF, new byte[] {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}),
(unchecked((long) 0xFF_FF_FF_FF_FF_FF_FF_FF),
new byte[] {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}.Select(t => new object[] {t.expected, t.streamContent});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Kaitai.Struct.Runtime.Async\Kaitai.Struct.Runtime.Async.csproj" />
</ItemGroup>

</Project>
185 changes: 185 additions & 0 deletions Kaitai.Struct.Runtime.Async.Tests/KaitaiAsyncStreamBaseTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using System;
using System.IO;
using System.IO.Pipelines;
using System.Threading;
using System.Threading.Tasks;
using Kaitai.Async;
using Xunit;

namespace Kaitai.Struct.Runtime.Async.Tests
{
public class StreamKaitaiAsyncStreamBaseTests : KaitaiAsyncStreamBaseTests
{
public StreamKaitaiAsyncStreamBaseTests() : base(false)
{
}

protected override KaitaiAsyncStream Create(byte[] data) => new KaitaiAsyncStream(data);
}

public class PipeReaderKaitaiAsyncStreamBaseTests : KaitaiAsyncStreamBaseTests
{
public PipeReaderKaitaiAsyncStreamBaseTests() : base(false)
{
}

protected override KaitaiAsyncStream Create(byte[] data) =>
new KaitaiAsyncStream(PipeReader.Create(new MemoryStream(data)));
}

public class StreamKaitaiAsyncStreamBaseCancelledTests : KaitaiAsyncStreamBaseTests
{
public StreamKaitaiAsyncStreamBaseCancelledTests() : base(true)
{
}

protected override KaitaiAsyncStream Create(byte[] data) => new KaitaiAsyncStream(data);
}

public class PipeReaderKaitaiAsyncStreamBaseCancelledTests : KaitaiAsyncStreamBaseTests
{
public PipeReaderKaitaiAsyncStreamBaseCancelledTests() : base(true)
{
}

protected override KaitaiAsyncStream Create(byte[] data) =>
new KaitaiAsyncStream(PipeReader.Create(new MemoryStream(data)));
}

public abstract class KaitaiAsyncStreamBaseTests : CancelableTestsBase
{
protected KaitaiAsyncStreamBaseTests(bool isTestingCancellation) : base(isTestingCancellation)
{
}

protected abstract KaitaiAsyncStream Create(byte[] data);

[Theory]
[InlineData(true, 0, 0)]
[InlineData(false, 1, 0)]
[InlineData(false, 1, 1)]
[InlineData(false, 1, 2)]
[InlineData(false, 1, 3)]
[InlineData(false, 1, 4)]
[InlineData(false, 1, 5)]
[InlineData(false, 1, 6)]
[InlineData(false, 1, 7)]
[InlineData(true, 1, 8)]
public async Task Eof_Test(bool shouldBeEof, int streamSize, int readBitsAmount)
{
var kaitaiStreamSUT = Create(new byte[streamSize]);
await EvaluateMaybeCancelled(async () =>
{
await kaitaiStreamSUT.ReadBitsIntAsync(readBitsAmount);
long positionBeforeIsEof = kaitaiStreamSUT.Pos;

if (shouldBeEof)
{
Assert.True(kaitaiStreamSUT.IsEof);
}
else
{
Assert.False(kaitaiStreamSUT.IsEof);
}

Assert.Equal(positionBeforeIsEof, kaitaiStreamSUT.Pos);
});
}

[Theory]
[InlineData(0, 0)]
[InlineData(1, 1)]
public async Task Pos_ByRead_Test(int expectedPos, int readBitsAmount)
{
var kaitaiStreamSUT = Create(new byte[1]);

await EvaluateMaybeCancelled(async () =>
{
await kaitaiStreamSUT.ReadBytesAsync(readBitsAmount);

Assert.Equal(expectedPos, kaitaiStreamSUT.Pos);
});
}

[Theory]
[InlineData(0, 0)]
[InlineData(1, 1)]
public async Task Pos_BySeek_Test(int expectedPos, int position)
{
var kaitaiStreamSUT = Create(new byte[1]);

await EvaluateMaybeCancelled(async () =>
{
await kaitaiStreamSUT.SeekAsync(position);

Assert.Equal(expectedPos, kaitaiStreamSUT.Pos);
});
}

[Fact]
public async Task ForwardSeek_AfterReadToEndAndBackwardSeek_Test()
{
const int toRead = 1;

var kaitaiStreamSUT = Create(new byte[2]);

await EvaluateMaybeCancelled(async () =>
{
// Simulates kaitai compiler generated code for multiple fields defined as `instances`
await kaitaiStreamSUT.ReadBytesFullAsync(CancellationToken.None);
await kaitaiStreamSUT.SeekAsync(0);
await kaitaiStreamSUT.SeekAsync(toRead);

Assert.Equal(toRead, kaitaiStreamSUT.Pos);
});
}

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(100)]
[InlineData(1_000)]
[InlineData(10_000)]
[InlineData(100_000)]
[InlineData(1_000_000)]
public void Size_Test(int streamSize)
{
var kaitaiStreamSUT = Create(new byte[streamSize]);
long positionBeforeIsEof = kaitaiStreamSUT.Pos;

Assert.Equal(streamSize, kaitaiStreamSUT.Size);
Assert.Equal(positionBeforeIsEof, kaitaiStreamSUT.Pos);
}

[Fact]
public async Task AlignToByte_Test()
{
//Arrange
var kaitaiStreamSUT = Create(new byte[] {0b_1000_0000});

ulong read = await kaitaiStreamSUT.ReadBitsIntAsync(1);
Assert.Equal(1u, read);

//Act
kaitaiStreamSUT.AlignToByte();
//Assert
Assert.Equal(1, kaitaiStreamSUT.Pos);
}

[Fact]
public void EmptyStream_NoRead_NoSeek_IsEof_ShouldBe_True()
{
var kaitaiStreamSUT = Create(new byte[0]);

Assert.True(kaitaiStreamSUT.IsEof);
}

[Fact]
public void EmptyStream_NoRead_NoSeek_Pos_ShouldBe_0()
{
var kaitaiStreamSUT = Create(new byte[0]);

Assert.Equal(0, kaitaiStreamSUT.Pos);
}
}
}
Loading