196 строки
9.0 KiB
C++
196 строки
9.0 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "TestHelpers.h"
|
|
|
|
#include "hermes/ADT/SafeInt.h"
|
|
#include "hermes/VM/JSLib/Base64Util.h"
|
|
#include "hermes/VM/StringBuilder.h"
|
|
|
|
using namespace hermes::vm;
|
|
|
|
namespace {
|
|
|
|
using Base64UtilTest = RuntimeTestFixture;
|
|
|
|
#define EXPECT_ENCODED(original, expected) \
|
|
{ \
|
|
uint64_t expectedLength = ((original.size() + 2) / 3) * 4; \
|
|
EXPECT_LE(expectedLength, std::numeric_limits<uint32_t>::max()); \
|
|
hermes::SafeUInt32 outputLength{static_cast<uint32_t>(expectedLength)}; \
|
|
CallResult<StringBuilder> builder = \
|
|
StringBuilder::createStringBuilder(runtime, outputLength, true); \
|
|
EXPECT_NE(builder, ExecutionStatus::EXCEPTION); \
|
|
\
|
|
bool success = base64Encode(original, *builder); \
|
|
EXPECT_TRUE(success); \
|
|
EXPECT_EQ( \
|
|
builder->getStringPrimitive()->getStringRef<char>(), \
|
|
createASCIIRef(expected)); \
|
|
}
|
|
|
|
#define EXPECT_ENCODED_ASCII_AND_UTF16(original, expected) \
|
|
{ \
|
|
ASCIIRef asciiRef = createASCIIRef(original); \
|
|
EXPECT_ENCODED(asciiRef, expected); \
|
|
\
|
|
std::vector<char16_t> converted(asciiRef.size() + 1); \
|
|
uint32_t i = 0; \
|
|
for (i = 0; i < asciiRef.size(); i++) { \
|
|
converted[i] = asciiRef[i]; \
|
|
} \
|
|
converted[i] = '\0'; \
|
|
EXPECT_ENCODED(createUTF16Ref(converted.data()), expected); \
|
|
}
|
|
|
|
#define EXPECT_DECODED(original, expected) \
|
|
{ \
|
|
hermes::OptValue<uint32_t> expectedLength = \
|
|
base64DecodeOutputLength(original); \
|
|
EXPECT_TRUE(expectedLength.hasValue()); \
|
|
CallResult<StringBuilder> builder = StringBuilder::createStringBuilder( \
|
|
runtime, hermes::SafeUInt32(*expectedLength)); \
|
|
EXPECT_NE(builder, ExecutionStatus::EXCEPTION); \
|
|
\
|
|
bool success = base64Decode(original, *builder); \
|
|
EXPECT_TRUE(success); \
|
|
EXPECT_EQ( \
|
|
builder->getStringPrimitive()->getStringRef<char16_t>(), \
|
|
createUTF16Ref(expected)); \
|
|
}
|
|
|
|
#define EXPECT_DECODED_ASCII_AND_UTF16(original, expected) \
|
|
{ \
|
|
ASCIIRef asciiRef = createASCIIRef(original); \
|
|
EXPECT_DECODED(asciiRef, expected); \
|
|
\
|
|
std::vector<char16_t> converted(asciiRef.size() + 1); \
|
|
uint32_t i = 0; \
|
|
for (i = 0; i < asciiRef.size(); i++) { \
|
|
converted[i] = asciiRef[i]; \
|
|
} \
|
|
converted[i] = '\0'; \
|
|
EXPECT_DECODED(createUTF16Ref(converted.data()), expected); \
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, EdgeCases) {
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("", "");
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, EncodePaddingRequired) {
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("a", "YQ==");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("ab", "YWI=");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("abcd", "YWJjZA==");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("abcde", "YWJjZGU=");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16(
|
|
"less is more than more", "bGVzcyBpcyBtb3JlIHRoYW4gbW9yZQ==");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("<>?su", "PD4/c3U=");
|
|
|
|
EXPECT_ENCODED(UTF16Ref(std::array<char16_t, 1>{1}), "AQ==");
|
|
EXPECT_ENCODED(ASCIIRef(std::array<char, 1>{1}), "AQ==");
|
|
EXPECT_ENCODED(UTF16Ref(std::array<char16_t, 2>{1, 0}), "AQA=");
|
|
EXPECT_ENCODED(ASCIIRef(std::array<char, 2>{1, 0}), "AQA=");
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, EncodePaddingNotNeeded) {
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("abc", "YWJj");
|
|
EXPECT_ENCODED_ASCII_AND_UTF16("abcdef", "YWJjZGVm");
|
|
|
|
EXPECT_ENCODED(UTF16Ref(std::array<char16_t, 3>{0, 0, 0}), "AAAA");
|
|
EXPECT_ENCODED(ASCIIRef(std::array<char, 3>{0, 0, 0}), "AAAA");
|
|
EXPECT_ENCODED(UTF16Ref(std::array<char16_t, 3>{1, 0, 0}), "AQAA");
|
|
EXPECT_ENCODED(ASCIIRef(std::array<char, 3>{1, 0, 0}), "AQAA");
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, EncodeInvalid) {
|
|
// Just a long enough buffer. All calls in this function are expected to fail.
|
|
hermes::SafeUInt32 outputLength{20};
|
|
CallResult<StringBuilder> builder =
|
|
StringBuilder::createStringBuilder(runtime, outputLength, true);
|
|
EXPECT_NE(builder, ExecutionStatus::EXCEPTION);
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"\U0001F600"), *builder));
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"a\U0001F600"), *builder));
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"ab\U0001F600"), *builder));
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"abc\U0001F600"), *builder));
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"\U0001F600xyz"), *builder));
|
|
EXPECT_FALSE(base64Encode(createUTF16Ref(u"abc\U0001F600xyz"), *builder));
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, DecodeValid) {
|
|
EXPECT_DECODED_ASCII_AND_UTF16("", u"");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YQ==", u"a");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YR==", u"a");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWI=", u"ab");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJj", u"abc");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJjZA==", u"abcd");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJjZA", u"abcd");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJjZGU=", u"abcde");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJjZGU", u"abcde");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YWJjZGVm", u"abcdef");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("0w==", u"\xD3");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("000=", u"\xD3M");
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, DecodeWithWhitespace) {
|
|
EXPECT_DECODED_ASCII_AND_UTF16(" ", u"");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("\x09\x0A\x0C\x0D\x20", u"");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("Y Q = =", u"a");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("\x09Y\x0AQ\x0C=\x0D=\x20", u"a");
|
|
EXPECT_DECODED_ASCII_AND_UTF16(" YR==", u"a");
|
|
EXPECT_DECODED_ASCII_AND_UTF16("YR== ", u"a");
|
|
}
|
|
|
|
TEST_F(Base64UtilTest, DecodeInvalid) {
|
|
// Just a long enough buffer. All calls in this function are expected to fail.
|
|
hermes::SafeUInt32 outputLength{50};
|
|
CallResult<StringBuilder> builder =
|
|
StringBuilder::createStringBuilder(runtime, outputLength);
|
|
|
|
std::array<char, 5> hasNegative = {'A', 'b', 'c', -15, '\0'};
|
|
EXPECT_FALSE(base64Decode(createASCIIRef(hasNegative.data()), *builder));
|
|
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("==="), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("0==="), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("aa=0"), *builder));
|
|
EXPECT_FALSE(
|
|
base64Decode(createASCIIRef("$aaaaaaaaaaaaaaaaaaaaaaa"), *builder));
|
|
EXPECT_FALSE(
|
|
base64Decode(createASCIIRef("aaaaaa$aaaaaaaaaaaaaaaaa"), *builder));
|
|
EXPECT_FALSE(base64Decode(
|
|
createASCIIRef("bbbbbbbbbddddddddddddddddddddaaaaaaadddddddb="),
|
|
*builder));
|
|
|
|
// Strings that are the wrong length to be a valid base64 encoded string
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("A"), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("B="), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("ba="), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("aaaaa"), *builder));
|
|
|
|
// Non-Base64 ASCII , i.e., not [a-z]|[A-Z]|[0-p]|\+|\/
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("a*"), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("YQ*"), *builder));
|
|
|
|
// Out of ASCII range.
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("a\xFF"), *builder));
|
|
|
|
// Padding where it's not expected
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("="), *builder));
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("=="), *builder));
|
|
|
|
// Padding in the middle
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("YQ==YQ=="), *builder));
|
|
|
|
// Extra padding
|
|
EXPECT_FALSE(base64Decode(createASCIIRef("YQ==="), *builder));
|
|
|
|
EXPECT_FALSE(base64Decode(createUTF16Ref(u"a\uff20=="), *builder));
|
|
EXPECT_FALSE(
|
|
base64Decode(createUTF16Ref(u"\u0065\u0065\u0065\u03A9"), *builder));
|
|
}
|
|
|
|
} // end anonymous namespace
|