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

#include "gtest/gtest.h"

#include "tile/base/string.h"

namespace tile {

TEST(PercentEncoding, Emca262)
{
    // Shamelessly copied from:
    //
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
    Slice set1 = ";,/?:@&=+$"; // Reserved Characters
    Slice set2 = "-_.!~*'()";  // Unescaped Characters
    Slice set3 = "#";          // Number Sign
    Slice set4 = "ABC abc 123";// Alphanumeric Characters + Space

    // Reserved chars are escaped.
    const PercentEncodingOptions ecma262_reversed(PercentEncodingStyle::Ecma262, true);

    EXPECT_EQ("%3B%2C%2F%3F%3A%40%26%3D%2B%24", EncodePercent(set1, ecma262_reversed));
    EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262_reversed));
    EXPECT_EQ("%23", EncodePercent(set3, ecma262_reversed));
    EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262_reversed));

    EXPECT_EQ(set1, DecodePercent("%3B%2C%2F%3F%3A%40%26%3D%2B%24"));
    EXPECT_EQ(set2, DecodePercent("-_.!~*'()"));
    EXPECT_EQ(set3, DecodePercent("%23"));
    EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123"));

    // Reserved chars are kept.
    const PercentEncodingOptions ecma262(PercentEncodingStyle::Ecma262, false);
    EXPECT_EQ(";,/?:@&=+$", EncodePercent(set1, ecma262));
    EXPECT_EQ("-_.!~*'()", EncodePercent(set2, ecma262));
    EXPECT_EQ("#", EncodePercent(set3, ecma262));
    EXPECT_EQ("ABC%20abc%20123", EncodePercent(set4, ecma262));

    EXPECT_EQ(set1, DecodePercent(";,/?:@&=+$"));
    EXPECT_EQ(set2, DecodePercent("-_.!~*'()"));
    EXPECT_EQ(set3, DecodePercent("#"));
    EXPECT_EQ(set4, DecodePercent("ABC%20abc%20123"));
}

TEST(PercentEncoding, Rfc3986)
{
    Slice str = "_-,;:!?.'()[]@*/&#+=~$ABC abc 123";

    const PercentEncodingOptions rfc3986_reversed(PercentEncodingStyle::Rfc3986, true);
    const PercentEncodingOptions rfc3986(PercentEncodingStyle::Rfc3986, false);
    EXPECT_EQ("_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%2B%3D~%24ABC%20abc%"
              "20123",
              EncodePercent(str, rfc3986_reversed));
    EXPECT_EQ("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123", EncodePercent(str, rfc3986));
    EXPECT_EQ(str,
              DecodePercent("_-%2C%3B%3A%21%3F.%27%28%29%5B%5D%40%2A%2F%26%23%"
                            "2B%3D~%24ABC%20abc%20123"));
    EXPECT_EQ(str, DecodePercent("_-,;:!?.'()[]@*/&#+=~$ABC%20abc%20123"));
}

TEST(PercentEncoding, Rfc5987)
{
    // `encodeRFC5987ValueChars from MDN does not seems quite right (in that it
    // does escape `#` `$` ..., which is not required.):
    //
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
    //
    // auto encode_rfc5987_value_chars = [](Slice str) {
    //   auto result =
    //       EncodePercent(str, PercentEncodingOptions{.style =
    //       PercentEncodingStyle::Ecma262});
    //   result = Replace(result, "'", "%" + EncodeHex("'"));
    //   result = Replace(result, "(", "%" + EncodeHex("("));
    //   result = Replace(result, ")", "%" + EncodeHex(")"));
    //   result = Replace(result, "*", "%" + EncodeHex("*"));
    //   result = Replace(result, "%7C", "|");
    //   result = Replace(result, "%60", "`");
    //   result = Replace(result, "%5E", "^");
    //   return result;
    // };
    //
    // EXPECT_EQ(
    //     encode_rfc5987_value_chars(str),
    //     EncodePercent(str, PercentEncodingOptions{.style =
    //     PercentEncodingStyle::Rfc5987}));

    const PercentEncodingOptions rfc5987(PercentEncodingStyle::Rfc5987, false);
    const PercentEncodingOptions rfc5987_reversed(PercentEncodingStyle::Rfc5987, true);

    Slice str = "!123'-!#$&()*,./:;?@[]^_`|~+=ABC abc";

    EXPECT_EQ("!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc", EncodePercent(str, rfc5987));
    EXPECT_EQ(str, DecodePercent("!123%27-!#$&%28%29%2A%2C.%2F%3A%3B%3F%40%5B%5D^_`|~+%3DABC%20abc"));
}

TEST(PercentEncoding, DecodePlusSignAsWhitespace)
{
    EXPECT_EQ("a+b", DecodePercent("a+b"));
    EXPECT_EQ("a b", DecodePercent("a+b", true));
}

}// namespace tile
