See More

/** * Copyright (C) 2015 Topology LP * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #define CATCH_CONFIG_MAIN #include #include #include #include #include #include #include #include #include #include #include // for memcmp() #include TEST_CASE("Douglas Crockford's base32", "[base32][crockford]") { using base32 = cppcodec::base32_crockford; SECTION("encoded size calculation") { REQUIRE(base32::encoded_size(0) == 0); REQUIRE(base32::encoded_size(1) == 2); REQUIRE(base32::encoded_size(2) == 4); REQUIRE(base32::encoded_size(3) == 5); REQUIRE(base32::encoded_size(4) == 7); REQUIRE(base32::encoded_size(5) == 8); REQUIRE(base32::encoded_size(6) == 10); REQUIRE(base32::encoded_size(10) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base32::decoded_max_size(0) == 0); REQUIRE(base32::decoded_max_size(1) == 0); REQUIRE(base32::decoded_max_size(2) == 1); REQUIRE(base32::decoded_max_size(3) == 1); REQUIRE(base32::decoded_max_size(4) == 2); REQUIRE(base32::decoded_max_size(5) == 3); REQUIRE(base32::decoded_max_size(6) == 3); REQUIRE(base32::decoded_max_size(7) == 4); REQUIRE(base32::decoded_max_size(8) == 5); REQUIRE(base32::decoded_max_size(9) == 5); REQUIRE(base32::decoded_max_size(10) == 6); REQUIRE(base32::decoded_max_size(16) == 10); } std::string hello = "Hello World"; std::string hello_encoded = "91JPRV3F41BPYWKCCG"; std::string hello_encoded_null = "91JPRV3F41BPYWKCCG00"; const uint8_t* hello_uint_ptr = reinterpret_cast(hello.data()); const uint8_t* hello_uint_ptr_encoded = reinterpret_cast(hello_encoded.data()); std::vector hello_uint_vector(hello_uint_ptr, hello_uint_ptr + hello.size()); std::vector hello_char_vector_encoded( hello_encoded.data(), hello_encoded.data() + hello_encoded.size()); std::vector hello_uint_vector_encoded( hello_uint_ptr_encoded, hello_uint_ptr_encoded + hello_encoded.size()); SECTION("encoding data") { REQUIRE(base32::encode(std::vector()) == ""); REQUIRE(base32::encode(std::vector({0})) == "00"); REQUIRE(base32::encode(std::vector({0, 0})) == "0000"); REQUIRE(base32::encode(std::vector({0, 0, 0})) == "00000"); REQUIRE(base32::encode(std::vector({0, 0, 0, 0})) == "0000000"); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0})) == "00000000"); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0, 0})) == "0000000000"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(base32::encode(std::string("Hello World")) == hello_encoded); REQUIRE(base32::encode("Hello World") == hello_encoded_null); REQUIRE(base32::encode(std::string("foo")) == "CSQPY"); REQUIRE(base32::encode(std::string("lowercase UPPERCASE 1434567 !@#$%^&*")) == "DHQQESBJCDGQ6S90AN850HAJ8D0N6H9064T36D1N6RVJ08A04CJ2AQH658"); REQUIRE(base32::encode(std::string("Wow, it really works!")) == "AXQQEB10D5T20WK5C5P6RY90EXQQ4TVK44"); } SECTION("decoding data") { REQUIRE(base32::decode("") == std::vector()); REQUIRE(base32::decode("00") == std::vector({0})); REQUIRE(base32::decode("0000") == std::vector({0, 0})); REQUIRE(base32::decode("00000") == std::vector({0, 0, 0})); REQUIRE(base32::decode("0000000") == std::vector({0, 0, 0, 0})); REQUIRE(base32::decode("00000000") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base32::decode("0000000000") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(base32::decode(std::string("91JPRV3F41BPYWKCCG")) == hello_uint_vector); REQUIRE(base32::decode("91JPRV3F41BPYWKCCG") == hello_uint_vector); REQUIRE(base32::decode<:string>("CSQPY") == "foo"); REQUIRE(base32::decode<:string>("DHQQESBJCDGQ6S90AN850HAJ8D0N6H9064T36D1N6RVJ08A04CJ2AQH658") == "lowercase UPPERCASE 1434567 !@#$%^&*"); // Lowercase should decode just as well as uppercase. REQUIRE(base32::decode<:string>("AXQQEB10D5T20WK5C5P6RY90EXQQ4TVK44") == "Wow, it really works!"); REQUIRE(base32::decode<:string>("axqqeb10d5t20wk5c5p6ry90exqq4tvk44") == "Wow, it really works!"); // Dashes are allowed for visual separation and ignored when decoding. REQUIRE(base32::decode<:string>("-C-SQ--PY-") == "foo"); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base32::decode("0"), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("000"), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("000000"), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("000000000"), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base32::decode("00======"), cppcodec::symbol_error); // no padding for Crockford REQUIRE_THROWS_AS(base32::decode("Uu"), cppcodec::symbol_error); // only a checksum symbol here REQUIRE_THROWS_AS(base32::decode("++"), cppcodec::symbol_error); // make sure it's not base64 REQUIRE_THROWS_AS(base32::decode("//"), cppcodec::symbol_error); // ...ditto } // Only test overloads once (for base32_crockford, since it happens to be the first one). // Since it's all templated, we assume that overloads work/behave similarly for other codecs. SECTION("encode() overloads") { // Other convenient overloads for taking raw pointer input. REQUIRE(base32::encode(hello.data(), hello.size()) == hello_encoded); REQUIRE(base32::encode(hello_uint_ptr, hello.size()) == hello_encoded); // Reused result pointer. Put the extra null terminator version in the middle to test resizing. std::string result; REQUIRE((base32::encode(result, hello_uint_ptr, hello.size()), result) == hello_encoded); REQUIRE((base32::encode(result, "Hello World"), result) == hello_encoded_null); REQUIRE((base32::encode(result, hello.data(), hello.size()), result) == hello_encoded); // Templated result. Use std::vector to exercise non-char array types. REQUIRE(base32::encode<:vector>>(hello) == hello_uint_vector_encoded); REQUIRE(base32::encode<:vector>>(hello.data(), hello.size()) == hello_uint_vector_encoded); REQUIRE(base32::encode<:vector>>(hello_uint_ptr, hello.size()) == hello_uint_vector_encoded); // Raw pointer output. std::vector hello_char_result; hello_char_result.resize(base32::encoded_size(hello.size())); REQUIRE(hello_char_result.size() == hello_char_vector_encoded.size()); size_t result_size; result_size = base32::encode(hello_char_result.data(), hello_char_result.size(), hello); REQUIRE(result_size == hello_char_vector_encoded.size()); REQUIRE(hello_char_result == hello_char_vector_encoded); result_size = base32::encode( hello_char_result.data(), hello_char_result.size(), hello.data(), hello.size()); REQUIRE(result_size == hello_char_vector_encoded.size()); REQUIRE(hello_char_result == hello_char_vector_encoded); // Test that when passed a larger buffer, the null termination character will be written // after the last proper symbol. (Also test uint8_t* overload.) hello_char_result.resize(hello_char_result.size() + 1); hello_char_result[hello_char_result.size() - 1] = 'x'; result_size = base32::encode( hello_char_result.data(), hello_char_result.size(), hello_uint_ptr, hello.size()); REQUIRE(result_size == hello_char_vector_encoded.size()); REQUIRE(hello_char_result[hello_char_result.size() - 1] == '\0'); hello_char_result.resize(hello_char_result.size() - 1); REQUIRE(hello_char_result == hello_char_vector_encoded); } // Only test overloads once (for base32_crockford, since it happens to be the first one). // Since it's all templated, we assume that overloads work/behave similarly for other codecs. SECTION("decode() overloads") { // Other convenient overloads for taking raw pointer input. REQUIRE(base32::decode(hello_encoded.data(), hello_encoded.size()) == hello_uint_vector); // Reused result pointer. Put a different string in the middle to test resizing. std::vector result; REQUIRE((base32::decode(result, hello_encoded.data(), hello_encoded.size()), result) == hello_uint_vector); REQUIRE((base32::decode(result, "00"), result) == std::vector({0})); REQUIRE((base32::decode(result, hello_encoded), result) == hello_uint_vector); // Templated result. Use std::string to exercise non-uint8_t array types. REQUIRE(base32::decode<:string>(hello_encoded) == hello); REQUIRE(base32::decode<:string>(hello_uint_vector_encoded) == hello); REQUIRE(base32::decode<:string>(hello_encoded.data(), hello_encoded.size()) == hello); // Raw pointer output. std::vector hello_uint_result; std::vector hello_char_result; size_t hello_decoded_max_size = base32::decoded_max_size(hello_encoded.size()); REQUIRE(hello.size() <= hello_decoded_max_size); hello_char_result.resize(hello_decoded_max_size); size_t result_size = base32::decode( hello_char_result.data(), hello_char_result.size(), hello_encoded); REQUIRE(result_size == hello.size()); REQUIRE(std::string(hello_char_result.data(), hello_char_result.data() + result_size) == hello); hello_char_result.resize(hello_decoded_max_size); result_size = base32::decode( hello_char_result.data(), hello_char_result.size(), hello_encoded.data(), hello_encoded.size()); REQUIRE(result_size == hello.size()); REQUIRE(std::string(hello_char_result.data(), hello_char_result.data() + result_size) == hello); hello_uint_result.resize(hello_decoded_max_size); result_size = base32::decode( hello_uint_result.data(), hello_uint_result.size(), hello_encoded); REQUIRE(result_size == hello.size()); hello_uint_result.resize(result_size); REQUIRE(hello_uint_result == hello_uint_vector); hello_uint_result.resize(hello_decoded_max_size); result_size = base32::decode( hello_uint_result.data(), hello_uint_result.size(), hello_encoded.data(), hello_encoded.size()); REQUIRE(result_size == hello.size()); hello_uint_result.resize(result_size); REQUIRE(hello_uint_result == hello_uint_vector); } } TEST_CASE("base32hex", "[base32][hex]") { using base32 = cppcodec::base32_hex; SECTION("encoded size calculation") { REQUIRE(base32::encoded_size(0) == 0); REQUIRE(base32::encoded_size(1) == 8); REQUIRE(base32::encoded_size(2) == 8); REQUIRE(base32::encoded_size(3) == 8); REQUIRE(base32::encoded_size(4) == 8); REQUIRE(base32::encoded_size(5) == 8); REQUIRE(base32::encoded_size(6) == 16); REQUIRE(base32::encoded_size(10) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base32::decoded_max_size(0) == 0); REQUIRE(base32::decoded_max_size(1) == 0); REQUIRE(base32::decoded_max_size(2) == 0); REQUIRE(base32::decoded_max_size(3) == 0); REQUIRE(base32::decoded_max_size(4) == 0); REQUIRE(base32::decoded_max_size(5) == 0); REQUIRE(base32::decoded_max_size(6) == 0); REQUIRE(base32::decoded_max_size(7) == 0); REQUIRE(base32::decoded_max_size(8) == 5); REQUIRE(base32::decoded_max_size(9) == 5); REQUIRE(base32::decoded_max_size(10) == 5); REQUIRE(base32::decoded_max_size(16) == 10); } SECTION("encoding data") { REQUIRE(base32::encode(std::vector()) == ""); REQUIRE(base32::encode(std::vector({0})) == "00======"); REQUIRE(base32::encode(std::vector({0, 0})) == "0000===="); REQUIRE(base32::encode(std::vector({0, 0, 0})) == "00000==="); REQUIRE(base32::encode(std::vector({0, 0, 0, 0})) == "0000000="); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0})) == "00000000"); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0, 0})) == "0000000000======"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(base32::encode(std::string("Hello")) == "91IMOR3F"); REQUIRE(base32::encode("Hello") == "91IMOR3F00======"); // RFC 4648: 10. Test Vectors REQUIRE(base32::encode(std::string("")) == ""); REQUIRE(base32::encode(std::string("f")) == "CO======"); REQUIRE(base32::encode(std::string("fo")) == "CPNG===="); REQUIRE(base32::encode(std::string("foo")) == "CPNMU==="); REQUIRE(base32::encode(std::string("foob")) == "CPNMUOG="); REQUIRE(base32::encode(std::string("fooba")) == "CPNMUOJ1"); REQUIRE(base32::encode(std::string("foobar")) == "CPNMUOJ1E8======"); // Other test strings. REQUIRE(base32::encode(std::vector({255, 255, 255, 255, 255})) == "VVVVVVVV"); } SECTION("decoding data") { REQUIRE(base32::decode("") == std::vector()); REQUIRE(base32::decode("00======") == std::vector({0})); REQUIRE(base32::decode("0000====") == std::vector({0, 0})); REQUIRE(base32::decode("00000===") == std::vector({0, 0, 0})); REQUIRE(base32::decode("0000000=") == std::vector({0, 0, 0, 0})); REQUIRE(base32::decode("00000000") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base32::decode("0000000000======") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(base32::decode<:string>(std::string("91IMOR3F")) == "Hello"); REQUIRE(base32::decode<:string>("91IMOR3F") == "Hello"); // RFC 4648: 10. Test Vectors REQUIRE(base32::decode<:string>("") == ""); REQUIRE(base32::decode<:string>("CO======") == "f"); REQUIRE(base32::decode<:string>("CPNG====") == "fo"); REQUIRE(base32::decode<:string>("CPNMU===") == "foo"); REQUIRE(base32::decode<:string>("CPNMUOG=") == "foob"); REQUIRE(base32::decode<:string>("CPNMUOJ1") == "fooba"); REQUIRE(base32::decode<:string>("CPNMUOJ1E8======") == "foobar"); // Other test strings. REQUIRE(base32::decode("VVVVVVVV") == std::vector({255, 255, 255, 255, 255})); // Lowercase should decode just as well as uppercase. REQUIRE(base32::decode<:string>("cpnmuoj1") == "fooba"); REQUIRE(base32::decode<:string>("cPnMuOj1") == "fooba"); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base32::decode("0"), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("00"), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("00==="), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("0======="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("000====="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("000000=="), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base32::decode("W0======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("X0======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("Y0======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("Z0======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("CPNM UOJ1"), cppcodec::symbol_error); // no spaces REQUIRE_THROWS_AS(base32::decode("CPNM-UOJ1"), cppcodec::symbol_error); // no dashes } } TEST_CASE("base32 (RFC 4648)", "[base32][rfc4648]") { using base32 = cppcodec::base32_rfc4648; SECTION("encoded size calculation") { REQUIRE(base32::encoded_size(0) == 0); REQUIRE(base32::encoded_size(1) == 8); REQUIRE(base32::encoded_size(2) == 8); REQUIRE(base32::encoded_size(3) == 8); REQUIRE(base32::encoded_size(4) == 8); REQUIRE(base32::encoded_size(5) == 8); REQUIRE(base32::encoded_size(6) == 16); REQUIRE(base32::encoded_size(10) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base32::decoded_max_size(0) == 0); REQUIRE(base32::decoded_max_size(1) == 0); REQUIRE(base32::decoded_max_size(2) == 0); REQUIRE(base32::decoded_max_size(3) == 0); REQUIRE(base32::decoded_max_size(4) == 0); REQUIRE(base32::decoded_max_size(5) == 0); REQUIRE(base32::decoded_max_size(6) == 0); REQUIRE(base32::decoded_max_size(7) == 0); REQUIRE(base32::decoded_max_size(8) == 5); REQUIRE(base32::decoded_max_size(9) == 5); REQUIRE(base32::decoded_max_size(10) == 5); REQUIRE(base32::decoded_max_size(16) == 10); } SECTION("encoding data") { REQUIRE(base32::encode(std::vector()) == ""); REQUIRE(base32::encode(std::vector({0})) == "AA======"); REQUIRE(base32::encode(std::vector({0, 0})) == "AAAA===="); REQUIRE(base32::encode(std::vector({0, 0, 0})) == "AAAAA==="); REQUIRE(base32::encode(std::vector({0, 0, 0, 0})) == "AAAAAAA="); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0})) == "AAAAAAAA"); REQUIRE(base32::encode(std::vector({0, 0, 0, 0, 0, 0})) == "AAAAAAAAAA======"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(base32::encode(std::string("12345")) == "GEZDGNBV"); REQUIRE(base32::encode("12345") == "GEZDGNBVAA======"); // RFC 4648: 10. Test Vectors REQUIRE(base32::encode(std::string("")) == ""); REQUIRE(base32::encode(std::string("f")) == "MY======"); REQUIRE(base32::encode(std::string("fo")) == "MZXQ===="); REQUIRE(base32::encode(std::string("foo")) == "MZXW6==="); REQUIRE(base32::encode(std::string("foob")) == "MZXW6YQ="); REQUIRE(base32::encode(std::string("fooba")) == "MZXW6YTB"); REQUIRE(base32::encode(std::string("foobar")) == "MZXW6YTBOI======"); // Other test strings. REQUIRE(base32::encode(std::string("ABCDE")) == "IFBEGRCF"); REQUIRE(base32::encode(std::vector({255, 255, 255, 255, 255})) == "77777777"); } SECTION("decoding data") { REQUIRE(base32::decode("") == std::vector()); REQUIRE(base32::decode("AA======") == std::vector({0})); REQUIRE(base32::decode("AAAA====") == std::vector({0, 0})); REQUIRE(base32::decode("AAAAA===") == std::vector({0, 0, 0})); REQUIRE(base32::decode("AAAAAAA=") == std::vector({0, 0, 0, 0})); REQUIRE(base32::decode("AAAAAAAA") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base32::decode("AAAAAAAAAA======") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(base32::decode<:string>(std::string("GEZDGNBV")) == "12345"); REQUIRE(base32::decode<:string>("GEZDGNBV") == "12345"); // RFC 4648: 10. Test Vectors REQUIRE(base32::decode<:string>("") == ""); REQUIRE(base32::decode<:string>("MY======") == "f"); REQUIRE(base32::decode<:string>("MZXQ====") == "fo"); REQUIRE(base32::decode<:string>("MZXW6===") == "foo"); REQUIRE(base32::decode<:string>("MZXW6YQ=") == "foob"); REQUIRE(base32::decode<:string>("MZXW6YTB") == "fooba"); REQUIRE(base32::decode<:string>("MZXW6YTBOI======") == "foobar"); // Other test strings. REQUIRE(base32::decode<:string>("IFBEGRCF") == "ABCDE"); REQUIRE(base32::decode("77777777") == std::vector({255, 255, 255, 255, 255})); // Lowercase should decode just as well as uppercase. REQUIRE(base32::decode<:string>("mzxw6ytb") == "fooba"); REQUIRE(base32::decode<:string>("mZxW6yTb") == "fooba"); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base32::decode("A"), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("AA"), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("AA==="), cppcodec::padding_error); REQUIRE_THROWS_AS(base32::decode("A======="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("AAA====="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base32::decode("AAAAAA=="), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base32::decode("0A======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("1A======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("8A======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("9A======"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base32::decode("GEZD GNBV"), cppcodec::symbol_error); // no spaces REQUIRE_THROWS_AS(base32::decode("GEZD-GNBV"), cppcodec::symbol_error); // no dashes } } TEST_CASE("base64 (RFC 4648)", "[base64][rfc4648]") { using base64 = cppcodec::base64_rfc4648; SECTION("encoded size calculation") { REQUIRE(base64::encoded_size(0) == 0); REQUIRE(base64::encoded_size(1) == 4); REQUIRE(base64::encoded_size(2) == 4); REQUIRE(base64::encoded_size(3) == 4); REQUIRE(base64::encoded_size(4) == 8); REQUIRE(base64::encoded_size(5) == 8); REQUIRE(base64::encoded_size(6) == 8); REQUIRE(base64::encoded_size(7) == 12); REQUIRE(base64::encoded_size(12) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base64::decoded_max_size(0) == 0); REQUIRE(base64::decoded_max_size(1) == 0); REQUIRE(base64::decoded_max_size(2) == 0); REQUIRE(base64::decoded_max_size(3) == 0); REQUIRE(base64::decoded_max_size(4) == 3); REQUIRE(base64::decoded_max_size(5) == 3); REQUIRE(base64::decoded_max_size(6) == 3); REQUIRE(base64::decoded_max_size(7) == 3); REQUIRE(base64::decoded_max_size(8) == 6); REQUIRE(base64::decoded_max_size(9) == 6); REQUIRE(base64::decoded_max_size(10) == 6); REQUIRE(base64::decoded_max_size(11) == 6); REQUIRE(base64::decoded_max_size(12) == 9); REQUIRE(base64::decoded_max_size(16) == 12); } SECTION("encoding data") { REQUIRE(base64::encode(std::vector()) == ""); REQUIRE(base64::encode(std::vector({0})) == "AA=="); REQUIRE(base64::encode(std::vector({0, 0})) == "AAA="); REQUIRE(base64::encode(std::vector({0, 0, 0})) == "AAAA"); REQUIRE(base64::encode(std::vector({0, 0, 0, 0})) == "AAAAAA=="); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0})) == "AAAAAAA="); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0, 0})) == "AAAAAAAA"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(base64::encode(std::string("Man")) == "TWFu"); REQUIRE(base64::encode("Man") == "TWFuAA=="); // Wikipedia REQUIRE(base64::encode(std::string("pleasure.")) == "cGxlYXN1cmUu"); REQUIRE(base64::encode(std::string("leasure.")) == "bGVhc3VyZS4="); REQUIRE(base64::encode(std::string("easure.")) == "ZWFzdXJlLg=="); REQUIRE(base64::encode(std::string("asure.")) == "YXN1cmUu"); REQUIRE(base64::encode(std::string("sure.")) == "c3VyZS4="); REQUIRE(base64::encode(std::string("any carnal pleas")) == "YW55IGNhcm5hbCBwbGVhcw=="); REQUIRE(base64::encode(std::string("any carnal pleasu")) == "YW55IGNhcm5hbCBwbGVhc3U="); REQUIRE(base64::encode(std::string("any carnal pleasur")) == "YW55IGNhcm5hbCBwbGVhc3Vy"); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})) == "FPu/A9l+"); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})) == "FPu/A9k="); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03})) == "FPu/Aw=="); // RFC 4648: 10. Test Vectors REQUIRE(base64::encode(std::string("")) == ""); REQUIRE(base64::encode(std::string("f")) == "Zg=="); REQUIRE(base64::encode(std::string("fo")) == "Zm8="); REQUIRE(base64::encode(std::string("foo")) == "Zm9v"); REQUIRE(base64::encode(std::string("foob")) == "Zm9vYg=="); REQUIRE(base64::encode(std::string("fooba")) == "Zm9vYmE="); REQUIRE(base64::encode(std::string("foobar")) == "Zm9vYmFy"); // Other test strings. REQUIRE(base64::encode(std::string("123")) == "MTIz"); REQUIRE(base64::encode(std::string("ABC")) == "QUJD"); REQUIRE(base64::encode(std::string("\xFF\xFF\xFF")) == "////"); } SECTION("decoding data") { REQUIRE(base64::decode("") == std::vector()); REQUIRE(base64::decode("AA==") == std::vector({0})); REQUIRE(base64::decode("AAA=") == std::vector({0, 0})); REQUIRE(base64::decode("AAAA") == std::vector({0, 0, 0})); REQUIRE(base64::decode("AAAAAA==") == std::vector({0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAA=") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAAA") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(base64::decode<:string>(std::string("TWFu")) == "Man"); REQUIRE(base64::decode<:string>("TWFu") == "Man"); // Wikipedia REQUIRE(base64::decode<:string>("cGxlYXN1cmUu") == "pleasure."); REQUIRE(base64::decode<:string>("bGVhc3VyZS4=") == "leasure."); REQUIRE(base64::decode<:string>("ZWFzdXJlLg==") == "easure."); REQUIRE(base64::decode<:string>("YXN1cmUu") == "asure."); REQUIRE(base64::decode<:string>("c3VyZS4=") == "sure."); REQUIRE(base64::decode<:string>("YW55IGNhcm5hbCBwbGVhcw==") == "any carnal pleas"); REQUIRE(base64::decode<:string>("YW55IGNhcm5hbCBwbGVhc3U=") == "any carnal pleasu"); REQUIRE(base64::decode<:string>("YW55IGNhcm5hbCBwbGVhc3Vy") == "any carnal pleasur"); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::decode("FPu/A9l+") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})); REQUIRE(base64::decode("FPu/A9k=") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})); REQUIRE(base64::decode("FPu/Aw==") == std::vector({0x14, 0xFB, 0xBF, 0x03})); // RFC 4648: 10. Test Vectors REQUIRE(base64::decode<:string>("") == ""); REQUIRE(base64::decode<:string>("Zg==") == "f"); REQUIRE(base64::decode<:string>("Zm8=") == "fo"); REQUIRE(base64::decode<:string>("Zm9v") == "foo"); REQUIRE(base64::decode<:string>("Zm9vYg==") == "foob"); REQUIRE(base64::decode<:string>("Zm9vYmE=") == "fooba"); REQUIRE(base64::decode<:string>("Zm9vYmFy") == "foobar"); // Other test strings. REQUIRE(base64::decode<:string>("MTIz") == "123"); REQUIRE(base64::decode<:string>("QUJD") == "ABC"); REQUIRE(base64::decode("////") == std::vector({255, 255, 255})); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base64::decode("A"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("AA"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("ABCDE"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("A==="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base64::decode("AAAA===="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base64::decode("AAAAA==="), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base64::decode("A&B="), cppcodec::symbol_error); REQUIRE_THROWS_AS(base64::decode("--"), cppcodec::symbol_error); // this is not base64url REQUIRE_THROWS_AS(base64::decode("__"), cppcodec::symbol_error); // ...ditto } } TEST_CASE("base64 (unpadded URL-safe)", "[base64][url_unpadded]") { using base64 = cppcodec::base64_url_unpadded; SECTION("encoded size calculation") { REQUIRE(base64::encoded_size(0) == 0); REQUIRE(base64::encoded_size(1) == 2); REQUIRE(base64::encoded_size(2) == 3); REQUIRE(base64::encoded_size(3) == 4); REQUIRE(base64::encoded_size(4) == 6); REQUIRE(base64::encoded_size(5) == 7); REQUIRE(base64::encoded_size(6) == 8); REQUIRE(base64::encoded_size(7) == 10); REQUIRE(base64::encoded_size(12) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base64::decoded_max_size(0) == 0); REQUIRE(base64::decoded_max_size(1) == 0); REQUIRE(base64::decoded_max_size(2) == 1); REQUIRE(base64::decoded_max_size(3) == 2); REQUIRE(base64::decoded_max_size(4) == 3); REQUIRE(base64::decoded_max_size(5) == 3); REQUIRE(base64::decoded_max_size(6) == 4); REQUIRE(base64::decoded_max_size(7) == 5); REQUIRE(base64::decoded_max_size(8) == 6); REQUIRE(base64::decoded_max_size(9) == 6); REQUIRE(base64::decoded_max_size(10) == 7); REQUIRE(base64::decoded_max_size(11) == 8); REQUIRE(base64::decoded_max_size(12) == 9); REQUIRE(base64::decoded_max_size(16) == 12); } SECTION("encoding data") { REQUIRE(base64::encode(std::vector()) == ""); REQUIRE(base64::encode(std::vector({0})) == "AA"); REQUIRE(base64::encode(std::vector({0, 0})) == "AAA"); REQUIRE(base64::encode(std::vector({0, 0, 0})) == "AAAA"); REQUIRE(base64::encode(std::vector({0, 0, 0, 0})) == "AAAAAA"); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0})) == "AAAAAAA"); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0, 0})) == "AAAAAAAA"); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})) == "FPu_A9l-"); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})) == "FPu_A9k"); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03})) == "FPu_Aw"); // RFC 4648: 10. Test Vectors REQUIRE(base64::encode(std::string("")) == ""); REQUIRE(base64::encode(std::string("f")) == "Zg"); REQUIRE(base64::encode(std::string("fo")) == "Zm8"); REQUIRE(base64::encode(std::string("foo")) == "Zm9v"); REQUIRE(base64::encode(std::string("foob")) == "Zm9vYg"); REQUIRE(base64::encode(std::string("fooba")) == "Zm9vYmE"); REQUIRE(base64::encode(std::string("foobar")) == "Zm9vYmFy"); // Other test strings. REQUIRE(base64::encode(std::string("123")) == "MTIz"); REQUIRE(base64::encode(std::string("ABC")) == "QUJD"); REQUIRE(base64::encode(std::string("\xFF\xFF\xFF")) == "____"); } SECTION("decoding data") { REQUIRE(base64::decode("") == std::vector()); REQUIRE(base64::decode("AA") == std::vector({0})); REQUIRE(base64::decode("AAA") == std::vector({0, 0})); REQUIRE(base64::decode("AAAA") == std::vector({0, 0, 0})); REQUIRE(base64::decode("AAAAAA") == std::vector({0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAA") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAAA") == std::vector({0, 0, 0, 0, 0, 0})); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::decode("FPu_A9l-") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})); REQUIRE(base64::decode("FPu_A9k") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})); REQUIRE(base64::decode("FPu_Aw") == std::vector({0x14, 0xFB, 0xBF, 0x03})); // RFC 4648: 10. Test Vectors REQUIRE(base64::decode<:string>("") == ""); REQUIRE(base64::decode<:string>("Zg") == "f"); REQUIRE(base64::decode<:string>("Zg==") == "f"); REQUIRE(base64::decode<:string>("Zm8") == "fo"); REQUIRE(base64::decode<:string>("Zm8=") == "fo"); REQUIRE(base64::decode<:string>("Zm9v") == "foo"); REQUIRE(base64::decode<:string>("Zm9vYg") == "foob"); REQUIRE(base64::decode<:string>("Zm9vYg==") == "foob"); REQUIRE(base64::decode<:string>("Zm9vYmE") == "fooba"); REQUIRE(base64::decode<:string>("Zm9vYmE=") == "fooba"); REQUIRE(base64::decode<:string>("Zm9vYmFy") == "foobar"); // Unpadded base64_url allows padding, but an incorrect number of padding characters is still wrong. REQUIRE_THROWS_AS(base64::decode<:string>("Zg="), cppcodec::padding_error); // Other test strings. REQUIRE(base64::decode<:string>("MTIz") == "123"); REQUIRE(base64::decode<:string>("QUJD") == "ABC"); REQUIRE(base64::decode("____") == std::vector({255, 255, 255})); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base64::decode("A"), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base64::decode("AAAAA"), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base64::decode("A&B"), cppcodec::symbol_error); REQUIRE_THROWS_AS(base64::decode("++"), cppcodec::symbol_error); // this is not standard base64 REQUIRE_THROWS_AS(base64::decode("//"), cppcodec::symbol_error); // ...ditto } } TEST_CASE("base64 (URL-safe)", "[base64][url]") { using base64 = cppcodec::base64_url; SECTION("encoded size calculation") { REQUIRE(base64::encoded_size(0) == 0); REQUIRE(base64::encoded_size(1) == 4); REQUIRE(base64::encoded_size(2) == 4); REQUIRE(base64::encoded_size(3) == 4); REQUIRE(base64::encoded_size(4) == 8); REQUIRE(base64::encoded_size(5) == 8); REQUIRE(base64::encoded_size(6) == 8); REQUIRE(base64::encoded_size(7) == 12); REQUIRE(base64::encoded_size(12) == 16); } SECTION("maximum decoded size calculation") { REQUIRE(base64::decoded_max_size(0) == 0); REQUIRE(base64::decoded_max_size(1) == 0); REQUIRE(base64::decoded_max_size(2) == 0); REQUIRE(base64::decoded_max_size(3) == 0); REQUIRE(base64::decoded_max_size(4) == 3); REQUIRE(base64::decoded_max_size(5) == 3); REQUIRE(base64::decoded_max_size(6) == 3); REQUIRE(base64::decoded_max_size(7) == 3); REQUIRE(base64::decoded_max_size(8) == 6); REQUIRE(base64::decoded_max_size(9) == 6); REQUIRE(base64::decoded_max_size(10) == 6); REQUIRE(base64::decoded_max_size(11) == 6); REQUIRE(base64::decoded_max_size(12) == 9); REQUIRE(base64::decoded_max_size(16) == 12); } SECTION("encoding data") { REQUIRE(base64::encode(std::vector()) == ""); REQUIRE(base64::encode(std::vector({0})) == "AA=="); REQUIRE(base64::encode(std::vector({0, 0})) == "AAA="); REQUIRE(base64::encode(std::vector({0, 0, 0})) == "AAAA"); REQUIRE(base64::encode(std::vector({0, 0, 0, 0})) == "AAAAAA=="); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0})) == "AAAAAAA="); REQUIRE(base64::encode(std::vector({0, 0, 0, 0, 0, 0})) == "AAAAAAAA"); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})) == "FPu_A9l-"); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})) == "FPu_A9k="); REQUIRE(base64::encode(std::vector({0x14, 0xFB, 0xBF, 0x03})) == "FPu_Aw=="); // RFC 4648: 10. Test Vectors REQUIRE(base64::encode(std::string("")) == ""); REQUIRE(base64::encode(std::string("f")) == "Zg=="); REQUIRE(base64::encode(std::string("fo")) == "Zm8="); REQUIRE(base64::encode(std::string("foo")) == "Zm9v"); REQUIRE(base64::encode(std::string("foob")) == "Zm9vYg=="); REQUIRE(base64::encode(std::string("fooba")) == "Zm9vYmE="); REQUIRE(base64::encode(std::string("foobar")) == "Zm9vYmFy"); // Other test strings. REQUIRE(base64::encode(std::string("123")) == "MTIz"); REQUIRE(base64::encode(std::string("ABC")) == "QUJD"); REQUIRE(base64::encode(std::string("\xFF\xFF\xFF")) == "____"); } SECTION("decoding data") { REQUIRE(base64::decode("") == std::vector()); REQUIRE(base64::decode("AA==") == std::vector({0})); REQUIRE(base64::decode("AAA=") == std::vector({0, 0})); REQUIRE(base64::decode("AAAA") == std::vector({0, 0, 0})); REQUIRE(base64::decode("AAAAAA==") == std::vector({0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAA=") == std::vector({0, 0, 0, 0, 0})); REQUIRE(base64::decode("AAAAAAAA") == std::vector({0, 0, 0, 0, 0, 0})); // RFC 4648: 9. Illustrations and Examples, adapted for more special characters REQUIRE(base64::decode("FPu_A9l-") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9, 0x7E})); REQUIRE(base64::decode("FPu_A9k=") == std::vector({0x14, 0xFB, 0xBF, 0x03, 0xD9})); REQUIRE(base64::decode("FPu_Aw==") == std::vector({0x14, 0xFB, 0xBF, 0x03})); // RFC 4648: 10. Test Vectors REQUIRE(base64::decode<:string>("") == ""); REQUIRE(base64::decode<:string>("Zg==") == "f"); REQUIRE(base64::decode<:string>("Zm8=") == "fo"); REQUIRE(base64::decode<:string>("Zm9v") == "foo"); REQUIRE(base64::decode<:string>("Zm9vYg==") == "foob"); REQUIRE(base64::decode<:string>("Zm9vYmE=") == "fooba"); REQUIRE(base64::decode<:string>("Zm9vYmFy") == "foobar"); // Other test strings. REQUIRE(base64::decode<:string>("MTIz") == "123"); REQUIRE(base64::decode<:string>("QUJD") == "ABC"); REQUIRE(base64::decode("____") == std::vector({255, 255, 255})); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(base64::decode("A"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("AA"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("ABCDE"), cppcodec::padding_error); REQUIRE_THROWS_AS(base64::decode("A==="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base64::decode("AAAA===="), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(base64::decode("AAAAA==="), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(base64::decode("A&B="), cppcodec::symbol_error); REQUIRE_THROWS_AS(base64::decode("++"), cppcodec::symbol_error); // this is not standard base64 REQUIRE_THROWS_AS(base64::decode("//"), cppcodec::symbol_error); // ...ditto } } TEST_CASE("hex (lowercase)", "[hex][lower]") { using hex = cppcodec::hex_lower; SECTION("encoded size calculation") { REQUIRE(hex::encoded_size(0) == 0); REQUIRE(hex::encoded_size(1) == 2); REQUIRE(hex::encoded_size(2) == 4); REQUIRE(hex::encoded_size(3) == 6); REQUIRE(hex::encoded_size(4) == 8); REQUIRE(hex::encoded_size(5) == 10); REQUIRE(hex::encoded_size(6) == 12); REQUIRE(hex::encoded_size(8) == 16); REQUIRE(hex::encoded_size(10) == 20); } SECTION("maximum decoded size calculation") { REQUIRE(hex::decoded_max_size(0) == 0); REQUIRE(hex::decoded_max_size(1) == 0); REQUIRE(hex::decoded_max_size(2) == 1); REQUIRE(hex::decoded_max_size(3) == 1); REQUIRE(hex::decoded_max_size(4) == 2); REQUIRE(hex::decoded_max_size(5) == 2); REQUIRE(hex::decoded_max_size(6) == 3); REQUIRE(hex::decoded_max_size(7) == 3); REQUIRE(hex::decoded_max_size(8) == 4); REQUIRE(hex::decoded_max_size(9) == 4); REQUIRE(hex::decoded_max_size(10) == 5); REQUIRE(hex::decoded_max_size(16) == 8); REQUIRE(hex::decoded_max_size(20) == 10); } SECTION("encoding data") { REQUIRE(hex::encode(std::vector()) == ""); REQUIRE(hex::encode(std::vector({0})) == "00"); REQUIRE(hex::encode(std::vector({0, 0})) == "0000"); REQUIRE(hex::encode(std::vector({0, 0, 0})) == "000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0})) == "00000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0, 0})) == "0000000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0, 0, 0})) == "000000000000"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(hex::encode(std::string("1")) == "31"); REQUIRE(hex::encode("1") == "3100"); REQUIRE(hex::encode(std::string("A")) == "41"); REQUIRE(hex::encode(std::vector({255})) == "ff"); // RFC 4648: 10. Test Vectors REQUIRE(hex::encode(std::string("")) == ""); REQUIRE(hex::encode(std::string("f")) == "66"); REQUIRE(hex::encode(std::string("fo")) == "666f"); REQUIRE(hex::encode(std::string("foo")) == "666f6f"); REQUIRE(hex::encode(std::string("foob")) == "666f6f62"); REQUIRE(hex::encode(std::string("fooba")) == "666f6f6261"); REQUIRE(hex::encode(std::string("foobar")) == "666f6f626172"); } SECTION("decoding data") { REQUIRE(hex::decode("") == std::vector()); REQUIRE(hex::decode("00") == std::vector({0})); REQUIRE(hex::decode("0000") == std::vector({0, 0})); REQUIRE(hex::decode("000000") == std::vector({0, 0, 0})); REQUIRE(hex::decode("00000000") == std::vector({0, 0, 0, 0})); REQUIRE(hex::decode("0000000000") == std::vector({0, 0, 0, 0, 0})); REQUIRE(hex::decode("000000000000") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(hex::decode<:string>(std::string("31")) == "1"); REQUIRE(hex::decode<:string>("31") == "1"); // RFC 4648: 10. Test Vectors REQUIRE(hex::decode<:string>("") == ""); REQUIRE(hex::decode<:string>("66") == "f"); REQUIRE(hex::decode<:string>("666f") == "fo"); REQUIRE(hex::decode<:string>("666f6f") == "foo"); REQUIRE(hex::decode<:string>("666f6f62") == "foob"); REQUIRE(hex::decode<:string>("666f6f6261") == "fooba"); REQUIRE(hex::decode<:string>("666f6f626172") == "foobar"); // Uppercase should decode just as well as lowercase. REQUIRE(hex::decode<:string>("666F6F6261") == "fooba"); REQUIRE(hex::decode<:string>("666F6f6261") == "fooba"); // An invalid number of symbols should throw the right kind of parse_error. REQUIRE_THROWS_AS(hex::decode("0"), cppcodec::invalid_input_length); REQUIRE_THROWS_AS(hex::decode("000"), cppcodec::invalid_input_length); // An invalid symbol should throw a symbol error. REQUIRE_THROWS_AS(hex::decode("1g"), cppcodec::symbol_error); REQUIRE_THROWS_AS(hex::decode("66 6f"), cppcodec::symbol_error); // no spaces REQUIRE_THROWS_AS(hex::decode("66-6f"), cppcodec::symbol_error); // no dashes } } TEST_CASE("hex (uppercase)", "[hex][upper]") { using hex = cppcodec::hex_upper; SECTION("encoded size calculation") { REQUIRE(hex::encoded_size(0) == 0); REQUIRE(hex::encoded_size(1) == 2); REQUIRE(hex::encoded_size(2) == 4); REQUIRE(hex::encoded_size(3) == 6); REQUIRE(hex::encoded_size(4) == 8); REQUIRE(hex::encoded_size(5) == 10); REQUIRE(hex::encoded_size(6) == 12); REQUIRE(hex::encoded_size(8) == 16); REQUIRE(hex::encoded_size(10) == 20); } SECTION("maximum decoded size calculation") { REQUIRE(hex::decoded_max_size(0) == 0); REQUIRE(hex::decoded_max_size(1) == 0); REQUIRE(hex::decoded_max_size(2) == 1); REQUIRE(hex::decoded_max_size(3) == 1); REQUIRE(hex::decoded_max_size(4) == 2); REQUIRE(hex::decoded_max_size(5) == 2); REQUIRE(hex::decoded_max_size(6) == 3); REQUIRE(hex::decoded_max_size(7) == 3); REQUIRE(hex::decoded_max_size(8) == 4); REQUIRE(hex::decoded_max_size(9) == 4); REQUIRE(hex::decoded_max_size(10) == 5); REQUIRE(hex::decoded_max_size(16) == 8); REQUIRE(hex::decoded_max_size(20) == 10); } SECTION("encoding data") { REQUIRE(hex::encode(std::vector()) == ""); REQUIRE(hex::encode(std::vector({0})) == "00"); REQUIRE(hex::encode(std::vector({0, 0})) == "0000"); REQUIRE(hex::encode(std::vector({0, 0, 0})) == "000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0})) == "00000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0, 0})) == "0000000000"); REQUIRE(hex::encode(std::vector({0, 0, 0, 0, 0, 0})) == "000000000000"); // Constructing an std::string reduces the size of the char array by one (null terminator). // Therefore, the result for passing the string literal directly ends up encoding // one more character, which produces two more symbols in this particular case. REQUIRE(hex::encode(std::string("1")) == "31"); REQUIRE(hex::encode("1") == "3100"); REQUIRE(hex::encode(std::string("A")) == "41"); REQUIRE(hex::encode(std::vector({255})) == "FF"); // RFC 4648: 10. Test Vectors REQUIRE(hex::encode(std::string("")) == ""); REQUIRE(hex::encode(std::string("f")) == "66"); REQUIRE(hex::encode(std::string("fo")) == "666F"); REQUIRE(hex::encode(std::string("foo")) == "666F6F"); REQUIRE(hex::encode(std::string("foob")) == "666F6F62"); REQUIRE(hex::encode(std::string("fooba")) == "666F6F6261"); REQUIRE(hex::encode(std::string("foobar")) == "666F6F626172"); } SECTION("decoding data") { REQUIRE(hex::decode("") == std::vector()); REQUIRE(hex::decode("00") == std::vector({0})); REQUIRE(hex::decode("0000") == std::vector({0, 0})); REQUIRE(hex::decode("000000") == std::vector({0, 0, 0})); REQUIRE(hex::decode("00000000") == std::vector({0, 0, 0, 0})); REQUIRE(hex::decode("0000000000") == std::vector({0, 0, 0, 0, 0})); REQUIRE(hex::decode("000000000000") == std::vector({0, 0, 0, 0, 0, 0})); // For decoding data, the result should be the same whether or not there is // a null terminator at the end, because the input is a string (not binary array). REQUIRE(hex::decode<:string>(std::string("31")) == "1"); REQUIRE(hex::decode<:string>("31") == "1"); // RFC 4648: 10. Test Vectors REQUIRE(hex::decode<:string>("") == ""); REQUIRE(hex::decode<:string>("66") == "f"); REQUIRE(hex::decode<:string>("666F") == "fo"); REQUIRE(hex::decode