namespace Just.Core.Tests.Base32Conversions; public class Decode { [Theory] [InlineData(15243, Base32EncodeOptions.None)] [InlineData(15243, Base32EncodeOptions.LowerCase)] [InlineData(15243, Base32EncodeOptions.NoPadding)] [InlineData(15243, Base32EncodeOptions.LowerCaseNoPadding)] [InlineData(812010, Base32EncodeOptions.None)] [InlineData(812010, Base32EncodeOptions.LowerCase)] [InlineData(812010, Base32EncodeOptions.NoPadding)] [InlineData(812010, Base32EncodeOptions.LowerCaseNoPadding)] [InlineData(97331334, Base32EncodeOptions.None)] [InlineData(97331334, Base32EncodeOptions.LowerCase)] [InlineData(97331334, Base32EncodeOptions.NoPadding)] [InlineData(97331334, Base32EncodeOptions.LowerCaseNoPadding)] [InlineData(20354, Base32EncodeOptions.None)] [InlineData(20354, Base32EncodeOptions.LowerCase)] [InlineData(20354, Base32EncodeOptions.NoPadding)] [InlineData(20354, Base32EncodeOptions.LowerCaseNoPadding)] [InlineData(33409, Base32EncodeOptions.None)] [InlineData(33409, Base32EncodeOptions.LowerCase)] [InlineData(33409, Base32EncodeOptions.NoPadding)] [InlineData(33409, Base32EncodeOptions.LowerCaseNoPadding)] [InlineData(59113, Base32EncodeOptions.None)] [InlineData(59113, Base32EncodeOptions.LowerCase)] [InlineData(59113, Base32EncodeOptions.NoPadding)] [InlineData(59113, Base32EncodeOptions.LowerCaseNoPadding)] public void WhenEncodedToString_ShouldBeDecodedToTheSameByteArray(int seed, Base32EncodeOptions options) { var rng = new Random(seed); for (int i = 1; i <= 512; i++) { var testBytes = new byte[i]; rng.NextBytes(testBytes); var resultString = Base32.Encode(testBytes, options); var resultBytes = Base32.Decode(resultString); resultBytes.ShouldBeEquivalentTo(testBytes); } } [Theory] [InlineData("FG4M3ZQM3TVWDMBUP5L7N7V3JS7KBM2E", new byte[] { 0x29, 0xb8, 0xcd, 0xe6, 0x0c, 0xdc, 0xeb, 0x61, 0xb0, 0x34, 0x7f, 0x57, 0xf6, 0xfe, 0xbb, 0x4c, 0xbe, 0xa0, 0xb3, 0x44, })] [InlineData("fg4m3zqm3tvwdmbup5l7n7v3js7kbm2e", new byte[] { 0x29, 0xb8, 0xcd, 0xe6, 0x0c, 0xdc, 0xeb, 0x61, 0xb0, 0x34, 0x7f, 0x57, 0xf6, 0xfe, 0xbb, 0x4c, 0xbe, 0xa0, 0xb3, 0x44, })] [InlineData("WXYEOQUZULMCY6ZQTDOLTRUZZMKQ====", new byte[] { 0xb5, 0xf0, 0x47, 0x42, 0x99, 0xa2, 0xd8, 0x2c, 0x7b, 0x30, 0x98, 0xdc, 0xb9, 0xc6, 0x99, 0xcb, 0x15, })] [InlineData("wxyeoquzulmcy6zqtdoltruzzmkq====", new byte[] { 0xb5, 0xf0, 0x47, 0x42, 0x99, 0xa2, 0xd8, 0x2c, 0x7b, 0x30, 0x98, 0xdc, 0xb9, 0xc6, 0x99, 0xcb, 0x15, })] [InlineData("2IO2HTALCXZWCBD2", new byte[] { 0xd2, 0x1d, 0xa3, 0xcc, 0x0b, 0x15, 0xf3, 0x61, 0x04, 0x7a, })] [InlineData("ZFXJMF5N", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })] [InlineData("zfxjmf5n", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })] [InlineData("CPIKTMY=", new byte[] { 0b00010011, 0b11010000, 0b10101001, 0b10110011, })] [InlineData("EFCDEAA=", new byte[] { 0x21, 0x44, 0x32, 0x00, })] [InlineData("EFCDEAI=", new byte[] { 0x21, 0x44, 0x32, 0x01, })] [InlineData("EFCDEAQ=", new byte[] { 0x21, 0x44, 0x32, 0x02, })] [InlineData("EFCDEAY=", new byte[] { 0x21, 0x44, 0x32, 0x03, })] [InlineData("EFCDEBA=", new byte[] { 0x21, 0x44, 0x32, 0x04, })] [InlineData("JVNJA===", new byte[] { 0b01001101, 0b01011010, 0b10010000, })] [InlineData("74OQ====", new byte[] { 0b11111111, 0b00011101, })] public void WhenCalledWithValidString_ShouldReturnValidByteArray(string str, byte[] expected) { var actualBytesArray = Base32.Decode(str); actualBytesArray.ShouldBe(expected); } [Theory] [InlineData("ZFXJMF5N====", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })] [InlineData("CPIKTMY=====", new byte[] { 0b00010011, 0b11010000, 0b10101001, 0b10110011, })] [InlineData("JVNJA=======", new byte[] { 0b01001101, 0b01011010, 0b10010000, })] public void WhenCalledWithValidStringThatEndsWithPaddingSign_ShouldReturnValidByteArray(string testString, byte[] expected) { var actualBytesArray = Base32.Decode(testString); actualBytesArray.ShouldBe(expected); } [Theory] [InlineData("ZFXJMF5N", new byte[] { 0b11001001, 0b01101110, 0b10010110, 0b00010111, 0b10101101, })] [InlineData("CPIKTMY", new byte[] { 0b00010011, 0b11010000, 0b10101001, 0b10110011, })] [InlineData("JVNJA", new byte[] { 0b01001101, 0b01011010, 0b10010000, })] public void WhenCalledWithValidStringWithoutPaddingSign_ShouldReturnValidByteArray(string testString, byte[] expected) { var actualBytesArray = Base32.Decode(testString); actualBytesArray.ShouldBe(expected); } [Theory] [InlineData(" ")] [InlineData("hg2515i3215q")] [InlineData("hg712)21")] [InlineData("hg712f 211")] [InlineData("AEBAGB^F")] public void WhenCalledWithNotValidString_ShouldThrowFormatException(string testString) { Action action = () => _ = Base32.Decode(testString); action.ShouldThrow() .WithMessage("Provided string contains invalid characters."); } [Theory] [InlineData("A")] [InlineData("AAA")] [InlineData("AAAAAA")] [InlineData("AEBAGBAFA")] [InlineData("AEBAGBAFAAA")] [InlineData("AEBAGBAFAAAAAA")] public void WhenCalledWithInvalidStringLength_ShouldThrowFormatException(string testString) { Action action = () => _ = Base32.Decode(testString); action.ShouldThrow() .WithMessage("Invalid Base32 string length."); } [Theory] [InlineData("ABCDEFG")] [InlineData("AAAAAAB")] [InlineData("EFCDF5J")] [InlineData("EFCDF5P")] public void WhenCalledWithInvalidLastByteEncoding_ShouldThrowFormatException(string testString) { Action action = () => _ = Base32.Decode(testString); action.ShouldThrow() .WithMessage("Invalid Base32 string. Inconsistent tail bits."); } [Theory] [InlineData(null)] [InlineData("")] public void WhenCalledWithNullString_ShouldReturnEmptyArray(string? testString) { Base32.Decode(testString).ShouldBeEmpty(); } [Theory] [InlineData("====")] [InlineData("============")] public void WhenCalledWithOnlyPadding_ShouldReturnEmptyArray(string testString) { Base32.Decode(testString).ShouldBeEmpty(); } [Theory] [InlineData("AEBAGBAF", 1)] [InlineData("AEBAGBAF", 2)] [InlineData("AEBAGBAF", 3)] [InlineData("AEBAGBAFAY", 5)] [InlineData("AEBAGBAFAYDQ", 6)] public void SpanTooSmall_ThrowsArgumentException(string input, int outputLength) { byte[] output = new byte[outputLength]; Action action = () => _ = Base32.Decode(input, output); action.ShouldThrow() .WithMessage("Decoded input can not fit in output span. (Parameter 'output')"); } }