aboutsummaryrefslogblamecommitdiffstats
path: root/tools/enum_parser/parse_enum/parse_enum_ut.cpp
blob: e979f5119a8fc7a8e5d63a64535a45878aa19ba3 (plain) (tree)
1
2
3
4
5
6
7
8



                                                    

                                   


                                   















                                                                                      















































































































































































































































































































                                                                                                                  



































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

#include <tools/enum_parser/parse_enum/parse_enum.h>

#include <util/generic/array_ref.h>
#include <util/generic/maybe.h>

typedef TEnumParser::TEnum TEnum;
typedef TEnumParser::TEnums TEnums;
typedef TEnumParser::TItems TItems;

namespace {
    using TNameValuePair = std::pair<TStringBuf, TMaybe<TStringBuf>>;

    void CompareNameValueItems(TConstArrayRef<TNameValuePair> ref, const TEnum& e) {
        const TItems& it = e.Items;
        for (size_t i = 0; i < Min(ref.size(), it.size()); ++i) {
            const auto& [refCppName, refValue] = ref[i];
            UNIT_ASSERT_VALUES_EQUAL_C(it[i].CppName, refCppName, e.CppName);
            UNIT_ASSERT_EQUAL_C(it[i].Value.Defined(), refValue.Defined(), e.CppName);
            if (refValue.Defined() && it[i].Value.Defined()) {
                UNIT_ASSERT_VALUES_EQUAL_C(*it[i].Value, *refValue, e.CppName);
            }
        }
        UNIT_ASSERT_VALUES_EQUAL_C(it.size(), ref.size(), e.CppName);
    }
}

Y_UNIT_TEST_SUITE(TEnumParserTest) {

    Y_UNIT_TEST(MainTest) {
        TString text = NResource::Find("/enums");
        TMemoryInput input(text.data(), text.size());
        TEnumParser parser(input);
        const TEnums& enums = parser.Enums;

        UNIT_ASSERT_VALUES_EQUAL(enums.size(), 16u);

        // check ESimple
        {
            const TEnum& e = enums[0];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ESimple");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);

            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);
            UNIT_ASSERT(!it[0].Value.Defined());

            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Https");
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
            UNIT_ASSERT(!it[1].Value.Defined());

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "ItemCount");
            UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
            UNIT_ASSERT(!it[2].Value.Defined());
        }

        // ESimpleWithComma
        {
            const TEnum& e = enums[1];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ESimpleWithComma");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 4u);

            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "3");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);

            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Http2");
            UNIT_ASSERT(it[1].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "Http");

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "Https");
            UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
            UNIT_ASSERT(!it[2].Value.Defined());

            UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "ItemCount");
            UNIT_ASSERT_VALUES_EQUAL(it[3].Aliases.size(), 0u);
            UNIT_ASSERT(!it[3].Value.Defined());
        }

        // check ECustomAliases
        {
            const TEnum& e = enums[2];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ECustomAliases");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "CAHttp");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "3");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[0], "http");

            UNIT_ASSERT(!it[1].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "CAHttps");
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases[0], "https");

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "CAItemCount");
            UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
        }

        // check EMultipleAliases
        {
            const TEnum& e = enums[3];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EMultipleAliases");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "MAHttp");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "9");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[0], "http://");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[1], "secondary");
            // yes, quoted values are NOT decoded, it is a known (minor) bug
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[2], "old\\nvalue");

            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "MAHttps");
            UNIT_ASSERT(it[1].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases[0], "https://");

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "MAItemCount");
            UNIT_ASSERT(!it[2].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
        }

        // check NEnumNamespace::EInNamespace
        {
            const TEnum& e = enums[4];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NEnumNamespace");
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInNamespace");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
            UNIT_ASSERT(it[0].Value.Defined());
        }

        // check NEnumNamespace::TEnumClass::EInClass
        {
            const TEnum& e = enums[5];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 2u);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NEnumNamespace");
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[1], "TEnumClass");
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInClass");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "9");

            UNIT_ASSERT(it[1].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "NEnumNamespace::Https");

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "Https3");
            UNIT_ASSERT(it[2].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "1  + 2");
        }

        // check unnamed enum (no code should be generated for it)
        {
            const TEnum& e = enums[6];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
        }

        // TEXT_WEIGHT
        {
            const TEnum& e = enums[7];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "TEXT_WEIGHT");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);

            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "WEIGHT_ZERO");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "-1");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);

            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "WEIGHT_LOW");
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
            UNIT_ASSERT(!it[1].Value.Defined());

            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "WEIGHT_NORMAL");
            UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
            UNIT_ASSERT(!it[2].Value.Defined());
        }

        // EDuplicateKeys
        {
            const TEnum& e = enums[8];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EDuplicateKeys");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);

            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Key0");
            UNIT_ASSERT(it[0].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "0");
            UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);

            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Key0Second");
            UNIT_ASSERT(it[1].Value.Defined());
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "Key0");
            UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
        }

        // EEmpty
        {
            const TEnum& e = enums[10];
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 0u);
        }

        // NComposite::NInner::EInCompositeNamespaceSimple
        {
            const TEnum& e = enums[11];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NComposite::NInner");
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInCompositeNamespaceSimple");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "one");
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "2") ;
        }

        // NOuterSimple::NComposite::NMiddle::NInner::NInnerSimple::TEnumClass::EVeryDeep
        {
            const TEnum& e = enums[12];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 4u);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NOuterSimple");
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[1], "NComposite::NMiddle::NInner");
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[2], "NInnerSimple");
            UNIT_ASSERT_VALUES_EQUAL(e.Scope[3], "TEnumClass");
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EVeryDeep");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 2u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Key0");
            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Key1");
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
        }

        // ENonLiteralValues
        {
            const TEnum& e = enums[13];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ENonLiteralValues");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "one");
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "MACRO(1, 2)");
            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "two");
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "2");
            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "three");
            UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "func(3)");
            UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "four");
            UNIT_ASSERT_VALUES_EQUAL(it[3].Value.Defined(), false);
            UNIT_ASSERT_VALUES_EQUAL(it[4].CppName, "five");
            UNIT_ASSERT_VALUES_EQUAL(it[4].Value, "MACRO(MACRO(1, 2), 2)");
        }

        // NotifyingStatus
        {
            const TEnum& e = enums[15];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "NotifyingStatus");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 4u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "NEW");
            UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "0");
            UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "FAILED_WILL_RETRY");
            UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
            UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "FAILED_NO_MORE_TRIALS");
            UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "2");
            UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "SENT");
            UNIT_ASSERT_VALUES_EQUAL(*it[3].Value, "3");
        }
    }

    Y_UNIT_TEST(BadCodeParseTest) {
        TString text = NResource::Find("/badcode");
        TMemoryInput input(text.data(), text.size());
        TEnumParser parser(input);
        const TEnums& enums = parser.Enums;

        UNIT_ASSERT_VALUES_EQUAL(enums.size(), 1u);

        // check <anonymous namespace>::ETest correct parsing
        {
            const TEnum& e = enums[0];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ETest");
            const TItems& it = e.Items;
            UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
            UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
            UNIT_ASSERT(it[0].Value.Defined());
        }

    }

    Y_UNIT_TEST(UnbalancedCodeParseTest) {
        // Thanks gotmanov@ for providing this example
        TString text = NResource::Find("/unbalanced");
        TMemoryInput input(text.data(), text.size());
        try {
            TEnumParser parser(input);
            UNIT_ASSERT(false);
        } catch(...) {
            UNIT_ASSERT(CurrentExceptionMessage().Contains("unbalanced scope. Did you miss a closing"));
        }
    }

    Y_UNIT_TEST(AliasBeforeNameTest) {
        TString text = NResource::Find("/alias_before_name");
        TMemoryInput input(text.data(), text.size());
        try {
            TEnumParser parser(input);
            UNIT_ASSERT(false);
        } catch(...) {
            UNIT_ASSERT(CurrentExceptionMessage().Contains("https://clubs.at.yandex-team.ru/stackoverflow/2603"));
        }
    }

    Y_UNIT_TEST(DigitSeparatorTest) {
        TString text = NResource::Find("/digit_separator");
        TMemoryInput input(text.data(), text.size());
        TEnumParser parser(input);
        const TEnums& enums = parser.Enums;
        UNIT_ASSERT_VALUES_EQUAL(enums.size(), 2u);
        {
            const TEnum& e = enums[0];
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ELiterals");
            static constexpr TNameValuePair ref[]{
                {"Char", "sizeof(u8'.')"},
                {"Int", "123'456'789"},
                {"Float1", "int(456'789.123'456)"},
                {"Float2", "int(1'2e0'1)"},
                {"Float3", "int(0x1'2p4)"},
            };
            CompareNameValueItems(ref, e);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
        }
        {
            const TEnum& e = enums[1];
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
            UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ETimePrecision");
            static constexpr TNameValuePair ref[]{
                {"MicroSeconds", "1"},
                {"MilliSeconds", "1'000"},
                {"Seconds", "1'000'000"},
                {"Minutes", "60'000'000"},
                {"Hours", "3'600'000'000"},
                {"Days", "86'400'000'000"},
                {"Weeks", "604'800'000'000"},
            };
            CompareNameValueItems(ref, e);
            UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
        }
    }
}