#include <balancer/kernel/helpers/ranges.h>

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


using namespace NSrvKernel;


Y_UNIT_TEST_SUITE(HelpersRangesUnitTest) {
    Y_UNIT_TEST(EmptyRangesTest) {
        UNIT_ASSERT_EXCEPTION(TDurationRanges(""), TDateTimeParseException);
        UNIT_ASSERT_EXCEPTION(TSizeRanges("", 0), TFromStringException);
    }

    Y_UNIT_TEST(RangesBadInputTest) {
        UNIT_ASSERT_EXCEPTION(TDurationRanges("minute"), TDateTimeParseException);
        UNIT_ASSERT_EXCEPTION(TDurationRanges(",,,"), TDateTimeParseException);
        UNIT_ASSERT_EXCEPTION(TSizeRanges("somewhat", 0), TFromStringException);
        UNIT_ASSERT_EXCEPTION(TSizeRanges(",,,", 0), TFromStringException);
    }

    Y_UNIT_TEST(DurationRangesSingleValTest) {
        TDurationRanges ranges("10ms");
        UNIT_ASSERT_EQUAL(ranges.size(), 2);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], TDuration::Zero());
        UNIT_ASSERT_EQUAL(ranges.Base()[1], TDuration::MilliSeconds(10));
    }

    Y_UNIT_TEST(SizeRangesSingleValTest) {
        TSizeRanges ranges("10", 0);
        UNIT_ASSERT_EQUAL(ranges.size(), 2);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], 0);
        UNIT_ASSERT_EQUAL(ranges.Base()[1], 10);
    }

    Y_UNIT_TEST(DurationRangesMultiValTest) {
        TDurationRanges ranges("10ms,100ms");
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], TDuration::Zero());
        UNIT_ASSERT_EQUAL(ranges.Base()[1], TDuration::MilliSeconds(10));
        UNIT_ASSERT_EQUAL(ranges.Base()[2], TDuration::MilliSeconds(100));
    }

    Y_UNIT_TEST(SizeRangesMultiValTest) {
        TSizeRanges ranges("10,100", 0);
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], 0);
        UNIT_ASSERT_EQUAL(ranges.Base()[1], 10);
        UNIT_ASSERT_EQUAL(ranges.Base()[2], 100);
    }

    Y_UNIT_TEST(DurationRangesUniqueTest) {
        TDurationRanges ranges("10ms,10ms,100ms,100ms");
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], TDuration::Zero());
        UNIT_ASSERT_EQUAL(ranges.Base()[1], TDuration::MilliSeconds(10));
        UNIT_ASSERT_EQUAL(ranges.Base()[2], TDuration::MilliSeconds(100));
    }

    Y_UNIT_TEST(SizeRangesUniqueTest) {
        TSizeRanges ranges("10,10,100,100", 0);
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], 0);
        UNIT_ASSERT_EQUAL(ranges.Base()[1], 10);
        UNIT_ASSERT_EQUAL(ranges.Base()[2], 100);
    }

    Y_UNIT_TEST(DurationRangesSortTest) {
        TDurationRanges ranges("100ms,10ms");
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], TDuration::Zero());
        UNIT_ASSERT_EQUAL(ranges.Base()[1], TDuration::MilliSeconds(10));
        UNIT_ASSERT_EQUAL(ranges.Base()[2], TDuration::MilliSeconds(100));
    }

    Y_UNIT_TEST(SizeRangesSortTest) {
        TSizeRanges ranges("100,10", 0);
        UNIT_ASSERT_EQUAL(ranges.size(), 3);
        UNIT_ASSERT_EQUAL(ranges.Base()[0], 0);
        UNIT_ASSERT_EQUAL(ranges.Base()[1], 10);
        UNIT_ASSERT_EQUAL(ranges.Base()[2], 100);
    }

    Y_UNIT_TEST(RangedDataTest) {
        TDurationRangedData<size_t> data("10ms,100ms");
        UNIT_ASSERT_EQUAL(data.Size(), 3);

        data[TDuration::Zero()] = 1;
        data[TDuration::MilliSeconds(10)] = 2;
        data[TDuration::MilliSeconds(100)] = 3;

        UNIT_ASSERT_EQUAL(data[TDuration::Zero()], data[TDuration::MilliSeconds(2)]);
        UNIT_ASSERT_EQUAL(data[TDuration::Zero()], data[TDuration::MilliSeconds(5)]);
        UNIT_ASSERT_EQUAL(data[TDuration::Zero()], data[TDuration::MilliSeconds(8)]);

        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(10)], data[TDuration::MilliSeconds(25)]);
        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(10)], data[TDuration::MilliSeconds(50)]);
        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(10)], data[TDuration::MilliSeconds(75)]);

        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(100)], data[TDuration::MilliSeconds(250)]);
        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(100)], data[TDuration::MilliSeconds(500)]);
        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(100)], data[TDuration::MilliSeconds(750)]);
        UNIT_ASSERT_EQUAL(data[TDuration::MilliSeconds(100)], data[TDuration::MilliSeconds(100000)]);
    }

    Y_UNIT_TEST(RangedDataFromRangesTest) {
        TDurationRanges ranges("5ms,100ms,1000ms");
        TDurationRangedData<size_t> data(std::move(ranges));
        UNIT_ASSERT_EQUAL(data.Size(), 4);
    }
}
