blob: 8de80c4fed409a06770c0b5a88e12dd2033eed07 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "iceberg/util/base64.h"
#include <gtest/gtest.h>
#include "iceberg/test/matchers.h"
namespace iceberg {
TEST(Base64Test, Encode) {
// Empty string
EXPECT_EQ("", Base64::Encode(""));
// Single character
EXPECT_EQ("YQ==", Base64::Encode("a"));
EXPECT_EQ("YWI=", Base64::Encode("ab"));
EXPECT_EQ("YWJj", Base64::Encode("abc"));
// Multiple of 3 characters
EXPECT_EQ("YWJjZGU=", Base64::Encode("abcde"));
EXPECT_EQ("YWJjZGVm", Base64::Encode("abcdef"));
// Common strings
EXPECT_EQ("U29tZSBkYXRhIHdpdGggY2hhcmFjdGVycw==",
Base64::Encode("Some data with characters"));
EXPECT_EQ("aGVsbG8=", Base64::Encode("hello"));
EXPECT_EQ("dGVzdCBzdHJpbmc=", Base64::Encode("test string"));
// Unicode
EXPECT_EQ("8J+EgA==", Base64::Encode("\xF0\x9F\x84\x80"));
// Null byte
EXPECT_EQ("AA==", Base64::Encode({"\x00", 1}));
}
TEST(Base64Test, Decode) {
// Empty string
ICEBERG_UNWRAP_OR_FAIL(auto empty, Base64::Decode(""));
EXPECT_EQ("", empty);
// Round-trip with Base64::Encode
ICEBERG_UNWRAP_OR_FAIL(auto a, Base64::Decode("YQ=="));
EXPECT_EQ("a", a);
ICEBERG_UNWRAP_OR_FAIL(auto ab, Base64::Decode("YWI="));
EXPECT_EQ("ab", ab);
ICEBERG_UNWRAP_OR_FAIL(auto abc, Base64::Decode("YWJj"));
EXPECT_EQ("abc", abc);
ICEBERG_UNWRAP_OR_FAIL(auto abcde, Base64::Decode("YWJjZGU="));
EXPECT_EQ("abcde", abcde);
ICEBERG_UNWRAP_OR_FAIL(auto abcdef, Base64::Decode("YWJjZGVm"));
EXPECT_EQ("abcdef", abcdef);
ICEBERG_UNWRAP_OR_FAIL(auto hello, Base64::Decode("aGVsbG8="));
EXPECT_EQ("hello", hello);
ICEBERG_UNWRAP_OR_FAIL(auto test_str, Base64::Decode("dGVzdCBzdHJpbmc="));
EXPECT_EQ("test string", test_str);
// Without padding (should still work)
ICEBERG_UNWRAP_OR_FAIL(auto a2, Base64::Decode("YQ"));
EXPECT_EQ("a", a2);
ICEBERG_UNWRAP_OR_FAIL(auto ab2, Base64::Decode("YWI"));
EXPECT_EQ("ab", ab2);
// Invalid characters return error
EXPECT_THAT(Base64::Decode("!!!"), IsError(ErrorKind::kInvalidArgument));
// Invalid padding and impossible unpadded lengths return error
for (const auto* invalid :
{"=", "====", "Y=Q=", "YQ=", "YQ===", "YWJj=", "aGVsbG8==", "A", "AAAAA"}) {
EXPECT_THAT(Base64::Decode(invalid), IsError(ErrorKind::kInvalidArgument)) << invalid;
}
}
TEST(Base64Test, UrlEncode) {
// Empty string
EXPECT_EQ("", Base64::UrlEncode(""));
// No padding is emitted (unlike standard base64)
EXPECT_EQ("YQ", Base64::UrlEncode("a"));
EXPECT_EQ("YWI", Base64::UrlEncode("ab"));
EXPECT_EQ("YWJj", Base64::UrlEncode("abc"));
EXPECT_EQ("aGVsbG8", Base64::UrlEncode("hello"));
// URL-safe characters: '-' and '_' instead of '+' and '/'
// bytes {0xFB, 0xFF, 0xFE} encode to "+//+" in standard base64, "-__-" in base64url
EXPECT_EQ("-__-", Base64::UrlEncode("\xFB\xFF\xFE"));
// Round-trip with UrlDecode
ICEBERG_UNWRAP_OR_FAIL(auto decoded, Base64::UrlDecode(Base64::UrlEncode("hello")));
EXPECT_EQ("hello", decoded);
}
TEST(Base64Test, UrlDecode) {
// Empty string
ICEBERG_UNWRAP_OR_FAIL(auto empty, Base64::UrlDecode(""));
EXPECT_EQ("", empty);
// Standard cases (same as Base64::Decode for alphanumeric)
ICEBERG_UNWRAP_OR_FAIL(auto hello, Base64::UrlDecode("aGVsbG8"));
EXPECT_EQ("hello", hello);
ICEBERG_UNWRAP_OR_FAIL(auto abc, Base64::UrlDecode("YWJj"));
EXPECT_EQ("abc", abc);
// URL-safe characters: '-' and '_' instead of '+' and '/'
// bytes {0xFB, 0xFF, 0xFE} encode to "+//+" in standard base64, "-__-" in base64url
ICEBERG_UNWRAP_OR_FAIL(auto decoded, Base64::UrlDecode("-__-"));
EXPECT_EQ(3u, decoded.size());
EXPECT_EQ('\xFB', decoded[0]);
EXPECT_EQ('\xFF', decoded[1]);
EXPECT_EQ('\xFE', decoded[2]);
// Standard base64 chars '+' and '/' should be invalid in base64url
EXPECT_THAT(Base64::UrlDecode("+//+"), IsError(ErrorKind::kInvalidArgument));
// With padding (should handle gracefully)
ICEBERG_UNWRAP_OR_FAIL(auto hello2, Base64::UrlDecode("aGVsbG8="));
EXPECT_EQ("hello", hello2);
// Invalid characters return error
EXPECT_THAT(Base64::UrlDecode("!!!invalid!!!"), IsError(ErrorKind::kInvalidArgument));
// Invalid padding and impossible unpadded lengths return error
for (const auto* invalid :
{"=", "====", "Y=Q=", "YQ=", "YQ===", "YWJj=", "aGVsbG8==", "A", "AAAAA"}) {
EXPECT_THAT(Base64::UrlDecode(invalid), IsError(ErrorKind::kInvalidArgument))
<< invalid;
}
}
} // namespace iceberg