Skip to content

Commit

Permalink
Implement CBOR Write/ReadEncodedValue() methods
Browse files Browse the repository at this point in the history
  • Loading branch information
eiriktsarpalis committed Apr 8, 2020
1 parent 614cac4 commit 5815768
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,98 @@ public static void VerifyMap(CborReader reader, object[] expectedValues, bool ex
reader.ReadEndMap();
}
}

public static string[] SampleCborValues =>
new[]
{
// numeric values
"01",
"37",
"3818",
"1818",
"190100",
"390100",
"1a000f4240",
"3affffffff",
// byte strings
"40",
"4401020304",
"5f41ab40ff",
// text strings
"60",
"6161",
"6449455446",
"7f62616260ff",
// Arrays
"80",
"840120604107",
"8301820203820405",
"9f182aff",
// Maps
"a0",
"a201020304",
"a1a1617802182a",
"bf01020304ff",
// tagged values
"c202",
"d82076687474703a2f2f7777772e6578616d706c652e636f6d",
// special values
"f4",
"f6",
"fa47c35000",
};

public static string[] InvalidCborValues =>
new[]
{
"",
// numeric types with missing bytes
"18",
"19ff",
"1affffff",
"1bffffffffffffff",
"38",
"39ff",
"3affffff",
"3bffffffffffffff",
// definite-length strings with missing bytes
"41",
"4201",
"61",
"6261",
// indefinite-length strings with missing break byte
"5f41ab40",
"7f62616260",
// definite-length arrays with missing elements
"81",
"8201",
// definite-length maps with missing fields
"a1",
"a20102",
// maps with odd number of elements
"a101",
"a2010203",
"bf01ff",
// indefinite-length collections with missing break byte
"9f",
"9f01",
"bf",
"bf0102",
// tags missing data
"d8",
"d9ff",
"daffffff",
"daffffffffff",
// valid tag not followed by value
"c2",
// floats missing data
"f9ff",
"faffffff",
"fbffffffffffffff",
// special value missing data
"f8",
// invalid special value
"f81f",
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace System.Security.Cryptography.Encoding.Tests.Cbor
public partial class CborReaderTests
{
[Theory]
[MemberData(nameof(SampleValues))]
[MemberData(nameof(SkipTestInputs))]
public static void SkipValue_RootValue_HappyPath(string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
Expand All @@ -26,7 +26,7 @@ public static void SkipValue_RootValue_HappyPath(string hexEncoding)
}

[Theory]
[MemberData(nameof(SampleValues))]
[MemberData(nameof(SkipTestInputs))]
public static void SkipValue_NestedValue_HappyPath(string hexEncoding)
{
byte[] encoding = $"8301{hexEncoding}03".HexToByteArray();
Expand All @@ -41,7 +41,7 @@ public static void SkipValue_NestedValue_HappyPath(string hexEncoding)
}

[Theory]
[MemberData(nameof(SampleValues))]
[MemberData(nameof(SkipTestInputs))]
public static void SkipValue_TaggedValue_HappyPath(string hexEncoding)
{
byte[] encoding = $"c2{hexEncoding}".HexToByteArray();
Expand All @@ -63,11 +63,7 @@ public static void SkipValue_NotAtValue_ShouldThrowInvalidOperationException()
}

[Theory]
[InlineData("")]
[InlineData("ff")]
[InlineData("c2")]
[InlineData("bf01ff")]
[InlineData("7f01ff")]
[MemberData(nameof(SkipTestInvalidCborInputs))]
public static void SkipValue_InvalidFormat_ShouldThrowFormatException(string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
Expand Down Expand Up @@ -104,39 +100,7 @@ public static void SkipValue_ExtremelyNestedValues_ShouldNotStackOverflow(int de
Assert.Equal(CborReaderState.Finished, reader.Peek());
}

public static IEnumerable<object[]> SampleValues =>
new string[]
{
// numeric values
"01",
"1a000f4240",
"3affffffff",
// byte strings
"40",
"4401020304",
"5f41ab40ff",
// text strings
"60",
"6161",
"6449455446",
"7f62616260ff",
// Arrays
"80",
"840120604107",
"8301820203820405",
"9f182aff",
// Maps
"a0",
"a201020304",
"a1a1617802182a",
"bf01020304ff",
// tagged values
"c202",
"d82076687474703a2f2f7777772e6578616d706c652e636f6d",
// special values
"f4",
"f6",
"fa47c35000",
}.Select(x => new object[] { x });
public static IEnumerable<object[]> SkipTestInputs => SampleCborValues.Select(x => new [] { x });
public static IEnumerable<object[]> SkipTestInvalidCborInputs => InvalidCborValues.Select(x => new[] { x });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Test.Cryptography;
using Xunit;

Expand Down Expand Up @@ -74,5 +76,44 @@ public static void CborReader_ReadingTwoPrimitiveValues_ShouldThrowInvalidOperat
Assert.Equal(CborReaderState.Finished, reader.Peek());
Assert.Throws<InvalidOperationException>(() => reader.ReadInt64());
}

[Theory]
[MemberData(nameof(EncodedValueInputs))]
public static void ReadEncodedValue_RootValue_HappyPath(string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
var reader = new CborReader(encoding);

byte[] encodedValue = reader.ReadEncodedValue().ToArray();
Assert.Equal(hexEncoding, encodedValue.ByteArrayToHex().ToLower());
}

[Theory]
[MemberData(nameof(EncodedValueInputs))]
public static void ReadEncodedValue_NestedValue_HappyPath(string hexEncoding)
{
byte[] encoding = $"8301{hexEncoding}60".HexToByteArray();

var reader = new CborReader(encoding);

reader.ReadStartArray();
reader.ReadInt64();
byte[] encodedValue = reader.ReadEncodedValue().ToArray();

Assert.Equal(hexEncoding, encodedValue.ByteArrayToHex().ToLower());
}

[Theory]
[MemberData(nameof(EncodedValueInvalidInputs))]
public static void ReadEncodedValue_InvalidCbor_ShouldThrowFormatException(string hexEncoding)
{
byte[] encoding = hexEncoding.HexToByteArray();
var reader = new CborReader(encoding);

Assert.Throws<FormatException>(() => reader.ReadEncodedValue());
}

public static IEnumerable<object[]> EncodedValueInputs => CborReaderTests.SampleCborValues.Select(x => new[] { x });
public static IEnumerable<object[]> EncodedValueInvalidInputs => CborReaderTests.InvalidCborValues.Select(x => new[] { x });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Test.Cryptography;
using Xunit;

Expand Down Expand Up @@ -43,5 +45,70 @@ public static void BytesWritten_SingleValue_ShouldReturnBytesWritten()
writer.WriteTextString("test");
Assert.Equal(5, writer.BytesWritten);
}

[Theory]
[MemberData(nameof(EncodedValueInputs))]
public static void WriteEncodedValue_RootValue_HappyPath(string hexEncodedValue)
{
byte[] encodedValue = hexEncodedValue.HexToByteArray();

using var writer = new CborWriter();
writer.WriteEncodedValue(encodedValue);

string hexResult = writer.ToArray().ByteArrayToHex();
Assert.Equal(hexEncodedValue, hexResult.ToLower());
}

[Theory]
[MemberData(nameof(EncodedValueInputs))]
public static void WriteEncodedValue_NestedValue_HappyPath(string hexEncodedValue)
{
byte[] encodedValue = hexEncodedValue.HexToByteArray();

using var writer = new CborWriter();
writer.WriteStartArray(3);
writer.WriteInt64(1);
writer.WriteEncodedValue(encodedValue);
writer.WriteTextString("");
writer.WriteEndArray();

string hexResult = writer.ToArray().ByteArrayToHex();
Assert.Equal("8301" + hexEncodedValue + "60", hexResult.ToLower());
}

[Fact]
public static void WriteEncodedValue_BadIndefiniteLengthStringValue_ShouldThrowInvalidOperationException()
{
using var writer = new CborWriter();
writer.WriteStartTextStringIndefiniteLength();
Assert.Throws<InvalidOperationException>(() => writer.WriteEncodedValue(new byte[] { 0x01 }));
}

[Fact]
public static void WriteEncodedValue_AtEndOfDefiniteLengthCollection_ShouldThrowInvalidOperationException()
{
using var writer = new CborWriter();
writer.WriteInt64(0);
Assert.Throws<InvalidOperationException>(() => writer.WriteEncodedValue(new byte[] { 0x01 }));
}

[Theory]
[MemberData(nameof(EncodedValueBadInputs))]
public static void WriteEncodedValue_InvalidCbor_ShouldThrowArgumentException(string hexEncodedInput)
{
byte[] encodedInput = hexEncodedInput.HexToByteArray();
using var writer = new CborWriter();
Assert.Throws<ArgumentException>(() => writer.WriteEncodedValue(encodedInput));
}

[Fact]
public static void WriteEncodedValue_ValidPayloadWithTrailingBytes_ShouldThrowArgumentException()
{
using var writer = new CborWriter();
Assert.Throws<ArgumentException>(() => writer.WriteEncodedValue(new byte[] { 0x01, 0x01 }));
}

public static IEnumerable<object[]> EncodedValueInputs => CborReaderTests.SampleCborValues.Select(x => new [] { x });
public static IEnumerable<object[]> EncodedValueBadInputs => CborReaderTests.InvalidCborValues.Select(x => new[] { x });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ static CborReaderState MapSpecialValueTagToReaderState (CborAdditionalInfo value
}
}

public ReadOnlyMemory<byte> ReadEncodedValue()
{
// keep a snapshot of the initial buffer state
ReadOnlyMemory<byte> initialBuffer = _buffer;
int initialBytesRead = _bytesRead;

// call skip to read and validate the next value
SkipValue();

// return the slice corresponding to the consumed value
return initialBuffer.Slice(0, _bytesRead - initialBytesRead);
}

private CborInitialByte PeekInitialByte()
{
if (_remainingDataItems == 0)
Expand Down
Loading

0 comments on commit 5815768

Please sign in to comment.