public void Basic_decoding_with_invalid_input___InvalidData(string input, int expectedConsumed, int expectedWritten) { var sut = new Base64UrlEncoder(); ReadOnlySpan <T> encoded; if (typeof(T) == typeof(byte)) { ReadOnlySpan <byte> tmp = Encoding.ASCII.GetBytes(input); encoded = MemoryMarshal.Cast <byte, T>(tmp); } else if (typeof(T) == typeof(char)) { encoded = MemoryMarshal.Cast <char, T>(input.AsSpan()); // .AsSpan() for net48 } else { throw new NotSupportedException(); // just in case new types are introduced in the future } Span <byte> data = new byte[sut.GetMaxDecodedLength(encoded.Length)]; OperationStatus status = sut.DecodeCore(encoded, data, out int consumed, out int written); byte[] actualData = data.Slice(0, written).ToArray(); Assert.Multiple(() => { Assert.AreEqual(OperationStatus.InvalidData, status); Assert.AreEqual(expectedConsumed, consumed); Assert.AreEqual(expectedWritten, written); byte[] expectedData = Convert.FromBase64String(input.Substring(0, consumed).FromBase64Url()); CollectionAssert.AreEqual(expectedData, actualData); }); }
public void DestinationLength_large_but_too_small___status_DestinationTooSmall() { const int base64Length = 400; const int dataLength = 250; var sut = new Base64UrlEncoder(); var data = new byte[dataLength]; T[] base64 = null; if (typeof(T) == typeof(byte)) { base64 = Enumerable.Repeat((T)(object)(byte)'A', base64Length).ToArray(); } else if (typeof(T) == typeof(char)) { base64 = Enumerable.Repeat((T)(object)'A', base64Length).ToArray(); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } OperationStatus status = sut.DecodeCore <T>(base64, data, out int consumed, out int written); Assert.Multiple(() => { int expectedWritten = 250 - 1; int expectedConsumed = expectedWritten / 3 * 4; Assert.AreEqual(OperationStatus.DestinationTooSmall, status); Assert.AreEqual(expectedConsumed, consumed); Assert.AreEqual(expectedWritten, written); }); }
public void DestinationLength_too_small___status_InvalidData(int base64Length, int dataLength) { var sut = new Base64UrlEncoder(); var data = new byte[dataLength]; T[] base64 = null; if (typeof(T) == typeof(byte)) { base64 = Enumerable.Repeat((T)(object)(byte)'A', base64Length).ToArray(); } else if (typeof(T) == typeof(char)) { base64 = Enumerable.Repeat((T)(object)'A', base64Length).ToArray(); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } OperationStatus status = sut.DecodeCore <T>(base64, data, out int consumed, out int written); Assert.Multiple(() => { int expectedConsumed = Math.Max(0, base64Length - 4); int expectedWritten = expectedConsumed / 4 * 3; Assert.AreEqual(OperationStatus.InvalidData, status); Assert.AreEqual(expectedConsumed, consumed); Assert.AreEqual(expectedWritten, written); }); }
public void Malformed_input___status_InvalidData(string input, bool isFinalBlock, int expectedConsumed, int expectedWritten) { var sut = new Base64UrlEncoder(); ReadOnlySpan <T> encoded; if (typeof(T) == typeof(byte)) { ReadOnlySpan <byte> tmp = Encoding.ASCII.GetBytes(input); encoded = MemoryMarshal.Cast <byte, T>(tmp); } else if (typeof(T) == typeof(char)) { encoded = MemoryMarshal.Cast <char, T>(input.AsSpan()); // AsSpan() for net48 } else { throw new NotSupportedException(); // just in case new types are introduced in the future } Span <byte> data = new byte[sut.GetMaxDecodedLength(encoded.Length)]; OperationStatus status = sut.DecodeCore(encoded, data, out int consumed, out int written, isFinalBlock); Assert.Multiple(() => { Assert.AreEqual(OperationStatus.InvalidData, status); Assert.AreEqual(expectedConsumed, consumed); Assert.AreEqual(expectedWritten, written); }); }
public void Buffer_chain_various_length_decode() { var sut = new Base64UrlEncoder(); var rnd = new Random(0); for (int i = 2; i < 200; ++i) { var data = new byte[i]; rnd.NextBytes(data); int encodedLength = sut.GetEncodedLength(data.Length); Span <T> encoded = new T[encodedLength]; OperationStatus status = sut.EncodeCore(data, encoded, out int consumed, out int written); Assume.That(status, Is.EqualTo(OperationStatus.Done), "fail at i = {0}", i); Assume.That(consumed, Is.EqualTo(data.Length), "fail at i = {0}", i); Assume.That(written, Is.EqualTo(encodedLength), "fail at i = {0}", i); //int decodedLength = sut.GetDecodedLength(encodedLength); int decodedLength; if (typeof(T) == typeof(byte)) { decodedLength = sut.GetDecodedLength(MemoryMarshal.AsBytes(encoded)); } else if (typeof(T) == typeof(char)) { decodedLength = sut.GetDecodedLength(MemoryMarshal.Cast <T, char>(encoded)); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } Span <byte> decoded = new byte[decodedLength]; int partialLength = encoded.Length / 2; status = sut.DecodeCore <T>(encoded.Slice(0, partialLength), decoded, out consumed, out int written1, isFinalBlock: false); Assert.AreEqual(partialLength % 4 == 0 ? OperationStatus.Done : OperationStatus.NeedMoreData, status, "fail at i = {0}", i); status = sut.DecodeCore <T>(encoded.Slice(consumed), decoded.Slice(written1), out consumed, out int written2, isFinalBlock: true); Assert.AreEqual(OperationStatus.Done, status, "fail at i = {0}", i); Assert.AreEqual(decodedLength, written1 + written2, "fail at i = {0}", i); CollectionAssert.AreEqual(data, decoded.ToArray(), "fail at i = {0}", i); } }
public void Invalid_data_various_length___status_InvalidData() { var sut = new Base64UrlEncoder(); var rnd = new Random(0); for (int i = 2; i < 200; ++i) { var data = new byte[i]; rnd.NextBytes(data); int encodedLength = sut.GetEncodedLength(data.Length); Span <T> encoded = new T[encodedLength]; OperationStatus status = sut.EncodeCore(data, encoded, out int consumed, out int written); Assume.That(status, Is.EqualTo(OperationStatus.Done)); Assume.That(consumed, Is.EqualTo(data.Length)); Assume.That(written, Is.EqualTo(encodedLength)); int decodedLength; if (typeof(T) == typeof(byte)) { Span <byte> tmp = MemoryMarshal.AsBytes(encoded); decodedLength = sut.GetDecodedLength(tmp); // Insert invalid data, just before eventual padding tmp[tmp.Length - 3] = (byte)'~'; } else if (typeof(T) == typeof(char)) { Span <char> tmp = MemoryMarshal.Cast <T, char>(encoded); decodedLength = sut.GetDecodedLength(tmp); // Insert invalid data, just before eventual padding tmp[tmp.Length - 3] = '~'; } else { throw new NotSupportedException(); // just in case new types are introduced in the future } Span <byte> decoded = new byte[decodedLength]; status = sut.DecodeCore <T>(encoded, decoded, out consumed, out written); // Invalid data is in the last 4 bytes, so everyting up to the last multiple of 4 is read. int expectedConsumed = (encoded.Length - 3) / 4 * 4; int expectedWritten = expectedConsumed / 4 * 3; Assert.Multiple(() => { Assert.AreEqual(OperationStatus.InvalidData, status); Assert.AreEqual(expectedConsumed, consumed, "Fail at i = {0}", i); Assert.AreEqual(expectedWritten, written, "Fail at i = {0}", i); }); } }
public void Empty_input() { var sut = new Base64UrlEncoder(); ReadOnlySpan <T> encoded = ReadOnlySpan <T> .Empty; Span <byte> data = new byte[sut.GetDecodedLength(encoded.Length)]; OperationStatus status = sut.DecodeCore(encoded, data, out int consumed, out int written); Assert.AreEqual(OperationStatus.Done, status); Assert.AreEqual(0, consumed); Assert.AreEqual(0, written); Assert.IsTrue(data.IsEmpty); }
public void Large_data___avx2_event_fired() { Assume.That(Avx2.IsSupported); var sut = new Base64UrlEncoder(); var data = new byte[50]; var rnd = new Random(0); rnd.NextBytes(data); int encodedLength = sut.GetEncodedLength(data.Length); Span <T> encoded = new T[encodedLength]; OperationStatus status = sut.EncodeCore(data, encoded, out int consumed, out int written); Assume.That(status, Is.EqualTo(OperationStatus.Done)); Assume.That(consumed, Is.EqualTo(data.Length)); Assume.That(written, Is.EqualTo(encodedLength)); int decodedLength; if (typeof(T) == typeof(byte)) { decodedLength = sut.GetDecodedLength(MemoryMarshal.AsBytes(encoded)); } else if (typeof(T) == typeof(char)) { decodedLength = sut.GetDecodedLength(MemoryMarshal.Cast <T, char>(encoded)); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } Span <byte> decoded = new byte[decodedLength]; bool avxExecuted = false; Base64UrlEncoder.Avx2Decoded += (s, e) => avxExecuted = true; status = sut.DecodeCore <T>(encoded, decoded, out int _, out int _); Assume.That(status, Is.EqualTo(OperationStatus.Done)); Assert.IsTrue(avxExecuted); }
public void Invalid_bytes___InvalidData(bool isFinalBlock) { var sut = new Base64UrlEncoder(); byte[] invalidBytes = TestHelper.GetInvalidBytes(Base64UrlEncoder.DecodingMap).ToArray(); Assume.That(invalidBytes.Length, Is.EqualTo(byte.MaxValue - 64 + 1)); T[] invalid = new T[invalidBytes.Length - 1]; if (typeof(T) == typeof(byte)) { invalid = invalidBytes.Select(b => (T)(object)b).ToArray(); } else if (typeof(T) == typeof(char)) { invalid = invalidBytes.Select(b => (T)(object)(char)b).ToArray(); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } for (int j = 0; j < 8; ++j) { #pragma warning disable CA2014 // Do not use stackalloc in loops Span <byte> tmp = stackalloc byte[8] { 50, 50, 50, 50, 80, 80, 80, 80 }; // valid input - "2222PPPP" Span <T> encoded = stackalloc T[tmp.Length]; #pragma warning restore CA2014 // Do not use stackalloc in loops if (typeof(T) == typeof(byte)) { encoded = MemoryMarshal.Cast <byte, T>(tmp); } else if (typeof(T) == typeof(char)) { for (int i = 0; i < tmp.Length; ++i) { encoded[i] = (T)(object)(char)tmp[i]; } } else { throw new NotSupportedException(); // just in case new types are introduced in the future } byte[] data = new byte[sut.GetMaxDecodedLength(encoded.Length)]; for (int i = 0; i < invalid.Length; ++i) { encoded[j] = invalid[i]; OperationStatus status = sut.DecodeCore <T>(encoded, data, out int consumed, out int written, isFinalBlock); Assert.Multiple(() => { Assert.AreEqual(OperationStatus.InvalidData, status, "j = {0}, i = {1}", j, i); if (j < 4) { Assert.AreEqual(0, consumed, "j = {0}, i = {1}", j, i); Assert.AreEqual(0, written, "j = {0}, i = {1}", j, i); } else { Assert.AreEqual(4, consumed, "j = {0}, i = {1}", j, i); Assert.AreEqual(3, written, "j = {0}, i = {1}", j, i); #if NETCOREAPP string actual = Convert.ToBase64String(data.AsSpan(0, 3)).ToBase64Url(); #else string actual = Convert.ToBase64String(data, 0, 3).ToBase64Url(); #endif Assert.AreEqual("2222", actual, "j = {0}, i = {1}", j, i); } }); } } } }
public void Data_of_various_length___roundtrips_correclty() { var sut = new Base64UrlEncoder(); var bytes = new byte[byte.MaxValue + 1]; for (int i = 0; i < bytes.Length; ++i) { bytes[i] = (byte)(255 - i); } for (int i = 0; i < 256; ++i) { Span <byte> source = bytes.AsSpan(0, i + 1); Span <T> encoded = new T[sut.GetEncodedLength(source.Length)]; OperationStatus status = sut.EncodeCore(source, encoded, out int consumed, out int written); Assert.AreEqual(OperationStatus.Done, status); Assert.AreEqual(source.Length, consumed); Assert.AreEqual(encoded.Length, written); string encodedText; int decodedLength; if (typeof(T) == typeof(byte)) { Span <byte> encodedBytes = MemoryMarshal.AsBytes(encoded); #if NETCOREAPP encodedText = Encoding.ASCII.GetString(encodedBytes); #else encodedText = Encoding.ASCII.GetString(encodedBytes.ToArray()); #endif decodedLength = sut.GetDecodedLength(encodedBytes); } else if (typeof(T) == typeof(char)) { #if NETCOREAPP encodedText = new string(MemoryMarshal.Cast <T, char>(encoded)); #else encodedText = new string(MemoryMarshal.Cast <T, char>(encoded).ToArray()); #endif decodedLength = sut.GetDecodedLength(encodedText.AsSpan()); } else { throw new NotSupportedException(); // just in case new types are introduced in the future } #if NETCOREAPP string expectedText = Convert.ToBase64String(source); #else string expectedText = Convert.ToBase64String(source.ToArray()); #endif Assert.AreEqual(expectedText.ToBase64Url(), encodedText); Span <byte> decoded = new byte[decodedLength]; status = sut.DecodeCore <T>(encoded, decoded, out consumed, out written); Assert.AreEqual(OperationStatus.Done, status); Assert.AreEqual(encoded.Length, consumed); Assert.AreEqual(decodedLength, written); CollectionAssert.AreEqual(source.ToArray(), decoded.ToArray()); } }