#include "tile/base/encoding/base64.h"

#include "gtest/gtest.h"

#include "tile/base/random.h"
#include "tile/testing/internal/random_string.h"

#include <string>

namespace tile {

static constexpr auto kText        = ".<>@????????";
static constexpr auto kBase64Text  = "Ljw+QD8/Pz8/Pz8/";
static constexpr auto kText2       = ".<>@???????";
static constexpr auto kBase64Text2 = "Ljw+QD8/Pz8/Pz8=";

TEST(Base64, Default)
{
    EXPECT_EQ(kBase64Text, EncodeBase64(kText));
    auto decoded = DecodeBase64(kBase64Text);
    ASSERT_TRUE(decoded);
    EXPECT_EQ(kText, *decoded);
    EXPECT_FALSE(DecodeBase64("some-invalid-base64-encoded!!"));
}

TEST(Base64, Padding)
{
    EXPECT_EQ(kBase64Text2, EncodeBase64(kText2));

    auto decoded = DecodeBase64(kBase64Text2);
    ASSERT_TRUE(decoded);
    EXPECT_EQ(kText2, *decoded);
}

TEST(Base64, Empty)
{
    EXPECT_EQ("", EncodeBase64(""));
    auto decoded = DecodeBase64("");
    ASSERT_TRUE(decoded);
    EXPECT_EQ("", *decoded);
}

TEST(Base64, AutoPadding)
{
    static constexpr auto kChar = "A";

    EXPECT_EQ("QQ==", EncodeBase64(kChar));

    {
        auto decoded = DecodeBase64("QQ==");
        ASSERT_TRUE(decoded);
        EXPECT_EQ(kChar, *decoded);
    }

    // auto padding, 1
    {
        auto decoded1 = DecodeBase64("QQ=");
        ASSERT_TRUE(decoded1);
        EXPECT_EQ(kChar, *decoded1);
    }

    // auto padding, 2
    {
        auto decoded2 = DecodeBase64("QQ");
        ASSERT_TRUE(decoded2);
        EXPECT_EQ(kChar, *decoded2);
    }
}

TEST(Base64, Torture)
{
    std::string random_str;
    std::string encoded;
    std::string decoded;
    for (int i = 0; i != 1000; ++i) {
        testing::RandomString(&random_str, 10000, 10000);
        EncodeBase64(random_str, &encoded);
        ASSERT_TRUE(DecodeBase64(encoded, &decoded));
        EXPECT_EQ(random_str, decoded);
    }
}

}// namespace tile
