#include "validate.h"

#include <kernel/search_types/search_types.h>

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

#include <util/random/random.h>


namespace {
    TString GetRandString(ui32 length) {
        TString str;
        for (ui32 i = 0; i < length; ++i) {
            str.push_back('a' + RandomNumber<ui32>('z' - 'a' + 1));
        }
        return str;
    }
}


namespace NSaas {

NRTYServer::TAttribute GetAttr(
    const TString& name,
    const TString& value,
    NRTYServer::TAttribute::TAttributeType type
) {
    NRTYServer::TAttribute attr;
    attr.SetName(name);
    attr.SetValue(value);
    attr.SetType(type);
    return attr;
}

Y_UNIT_TEST_SUITE(TestValidateSearchAttrs) {
    Y_UNIT_TEST(TestSearchAttrs) {
        const TString correctName =  "APZ_adz_069";
        const TString correctStrValue = "some value";
        const TString correctIntValue = "123490";

        {
            auto attr = GetAttr(correctName, correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "correct literal attribute");
        }
        {
            auto attr = GetAttr(correctName, correctIntValue, NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
            UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "correct integer attribute");
        }
        {
            auto attr = GetAttr(correctName, correctIntValue, NRTYServer::TAttribute::FLOAT_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "unsupported attribute type");
        }
        {
            TString name = GetRandString(NRTYServer::TSearchAttrLimits::MAX_NAME_LENGTH + 1);
            auto attr = GetAttr(name, correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "attribute name is more then limit");
        }
        {
            TString name = GetRandString(NRTYServer::TSearchAttrLimits::MAX_NAME_LENGTH);
            TString key = GetRandString(NRTYServer::TSearchAttrLimits::MAX_TOTAL_LENGTH - name.size() + 1);
            auto attr = GetAttr(name, key, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "attribute name+key is more then limit");
        }
        {
            auto attr = GetAttr("", correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "empty attribute name");
        }
        {
            auto attr = GetAttr(correctName, "", NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "empty attribute value");
        }
        {
            TString someIncorrectCharsForName = "\1 -/!:@[^`{";
            for (ui32 i = 0; i < someIncorrectCharsForName.size(); ++i) {
                TString name = correctName;
                name[i % name.size()] = someIncorrectCharsForName[i];

                auto attr = GetAttr(name, correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
                UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "incorrect char in name");
            }
        }
        {
            TVector<i64> correctIntValues = {0, 12345, i64(Max<ui32>())};
            TVector<i64> incorrectIntValues = {-1234, -1, i64(Max<ui32>()) + 1};
            for (i64 value : correctIntValues) {
                auto attr = GetAttr(correctName, ToString(value), NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
                UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "correct integer attribute");
            }
            for (i64 value : incorrectIntValues) {
                auto attr = GetAttr(correctName, ToString(value), NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
                UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateSearchAttribute(attr), yexception, "incorrect value for integer attribute");
            }
        }
    }
    Y_UNIT_TEST(TestGroupAttrs) {
        const TString correctName =  "APZ_adz_069";
        const TString correctStrValue = "some value";
        const TString correctIntValue = "123490";

        {
            auto attr = GetAttr(correctName, correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "correct literal attribute");
        }
        {
            auto attr = GetAttr(correctName, correctIntValue, NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
            UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "correct integer attribute");
        }
        {
            auto attr = GetAttr(correctName, correctStrValue, NRTYServer::TAttribute::FLOAT_ATTRIBUTE);
            UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "correct float type?");
        }
        {
            auto attr = GetAttr("", correctStrValue, NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "empty attribute name");
        }
        {
            auto attr = GetAttr(correctName, "", NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "empty attribute value");
        }
        {
            TVector<i64> correctIntValues = {0, 12345, i64(Max<TCateg>() - 1)};
            TVector<i64> incorrectIntValues = {-1234, -1, i64(Max<TCateg>()), i64(Max<TCateg>()) + 1};
            for (i64 value : correctIntValues) {
                auto attr = GetAttr(correctName, ToString(value), NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
                UNIT_CHECK_GENERATED_NO_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "correct integer attribute");
            }
            for (i64 value : incorrectIntValues) {
                auto attr = GetAttr(correctName, ToString(value), NRTYServer::TAttribute::INTEGER_ATTRIBUTE);
                UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "incorrect value for integer attribute");
            }
        }
        {
            auto attr = GetAttr(correctName, "some\nvalue", NRTYServer::TAttribute::LITERAL_ATTRIBUTE);
            UNIT_CHECK_GENERATED_EXCEPTION_C(ValidateGroupAttribute(attr), yexception, "\\n in attribute value");
        }
    }
}

}
