#include <balancer/kernel/regexp/regexp_re2.h>

#include <library/cpp/testing/unittest/registar.h>

Y_UNIT_TEST_SUITE(TBalancerRegexpRE2Test) {
    Y_UNIT_TEST(TestInvalid) {
        using namespace NSrvKernel;
        UNIT_ASSERT_EXCEPTION(TRegexp("("), TRE2Error);
    }

    Y_UNIT_TEST(TestMatch) {
        using namespace NSrvKernel;

        TRegexp regexp("[?&]id=([^&]+)");
        UNIT_ASSERT(regexp.Match("?id=111"));
        UNIT_ASSERT(regexp.Match("&id=111"));
        UNIT_ASSERT(!regexp.Match("test=ololo&id=45"));
        UNIT_ASSERT(!regexp.Match("&id="));
    }

    Y_UNIT_TEST(TestExtractAll) {
        using namespace NSrvKernel;

        TRegexp regexp("[?&]id=([^&]+)");
        TVector<TStringBuf> out;
        UNIT_ASSERT(regexp.ExtractAll("/?id=1&test=ololo&id=45", &out, false));
        UNIT_ASSERT_EQUAL(out.size(), 2);
        UNIT_ASSERT(out.front() == "1");
        UNIT_ASSERT(out.back() == "45");
    }


    Y_UNIT_TEST(TestExtractZeroWidth) {
        using namespace NSrvKernel;
        // hdrcgi module relies on this behavior
        TRegexp regexp(TString("[?&]").append("foo").append("=([^&]*)(?:&|$)"),
                       TRegexp::TOpts().SetPosixSyntax(false));
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.Extract("/?foo=", &out, true));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 2);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "?foo=");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "");
        }
    }

    Y_UNIT_TEST(TestExtractRepeated) {
        using namespace NSrvKernel;
        TRegexp regexp(TString("[?&]").append("foo").append("=([^&]*)(?:&|$)"),
                       TRegexp::TOpts().SetPosixSyntax(false));
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.Extract("/?foo=bar&foo=baz&foo=xxx", &out, true));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 2);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "?foo=bar&");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "bar");
        }
    }

    Y_UNIT_TEST(TestExtractAllRepeatedSkipZeroGroup) {
        using namespace NSrvKernel;
        TRegexp regexp(TString("[?&]").append("foo").append("=([^&]*)(?:&|$)"),
                       TRegexp::TOpts().SetPosixSyntax(false));
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.ExtractAll("/?foo=bar&foo=baz&foo=xxx", &out, false));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 3);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "bar");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "baz");
            UNIT_ASSERT_VALUES_EQUAL(out[2], "xxx");
        }
    }

    Y_UNIT_TEST(TestExtractAllRepeatedKeepZeroGroup) {
        using namespace NSrvKernel;
        TRegexp regexp(TString("[?&]").append("foo").append("=([^&]*)(?:&|$)"),
                       TRegexp::TOpts().SetPosixSyntax(false));
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.ExtractAll("/?foo=bar&foo=baz&foo=xxx", &out, true));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 6);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "?foo=bar&");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "bar");
            UNIT_ASSERT_VALUES_EQUAL(out[2], "&foo=baz&");
            UNIT_ASSERT_VALUES_EQUAL(out[3], "baz");
            UNIT_ASSERT_VALUES_EQUAL(out[4], "&foo=xxx");
            UNIT_ASSERT_VALUES_EQUAL(out[5], "xxx");
        }
    }

    Y_UNIT_TEST(TestExtractAllEmptyMatch) {
        using namespace NSrvKernel;
        TRegexp regexp(TString("(f?)"), TRegexp::TOpts().SetPosixSyntax(false));
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(!regexp.ExtractAll("", &out, true));
        }
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.ExtractAll("x", &out, true));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 2);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "");
        }
        {
            TVector<TStringBuf> out;
            UNIT_ASSERT(regexp.ExtractAll("xx", &out, true));
            UNIT_ASSERT_VALUES_EQUAL(out.size(), 2);
            UNIT_ASSERT_VALUES_EQUAL(out[0], "");
            UNIT_ASSERT_VALUES_EQUAL(out[1], "");
        }
    }
};
