#include "metrics/MetricSample.hpp"

#include "catch2/catch_test_macros.hpp"

using tw::metrics::MetricField;
using tw::metrics::MetricSample;
using tw::metrics::value_of;

TEST_CASE("Empty sample reports zero", "[metric_sample]") {
    MetricSample sample;

    REQUIRE(sample.is_empty());
    REQUIRE(sample.count == 0);
    REQUIRE(sample.sum == 0.0);
    REQUIRE(sample.min == 0.0);
    REQUIRE(sample.max == 0.0);
    REQUIRE(sample.avg() == 0.0);
}

TEST_CASE("Sample tracks sum, average and extremes", "[metric_sample]") {
    MetricSample sample;

    sample.add(4.0);
    sample.add(1.0);
    sample.add(7.0);

    REQUIRE(sample.count == 3);
    REQUIRE(sample.sum == 12.0);
    REQUIRE(sample.min == 1.0);
    REQUIRE(sample.max == 7.0);
    REQUIRE(sample.avg() == 4.0);
}

TEST_CASE("First value sets both extremes", "[metric_sample]") {
    MetricSample sample;

    sample.add(-5.0);

    REQUIRE(sample.min == -5.0);
    REQUIRE(sample.max == -5.0);
}

TEST_CASE("Merge folds one sample into another", "[metric_sample]") {
    MetricSample left;
    left.add(2.0);
    left.add(4.0);

    MetricSample right;
    right.add(10.0);
    right.add(0.5);

    left.merge(right);

    REQUIRE(left.count == 4);
    REQUIRE(left.sum == 16.5);
    REQUIRE(left.min == 0.5);
    REQUIRE(left.max == 10.0);
}

TEST_CASE("Merging with an empty sample changes nothing", "[metric_sample]") {
    MetricSample sample;
    sample.add(3.0);

    sample.merge(MetricSample{});

    REQUIRE(sample.count == 1);
    REQUIRE(sample.min == 3.0);
    REQUIRE(sample.max == 3.0);
}

TEST_CASE("Merging into an empty sample adopts the other", "[metric_sample]") {
    MetricSample other;
    other.add(3.0);
    other.add(9.0);

    MetricSample sample;
    sample.merge(other);

    REQUIRE(sample.count == 2);
    REQUIRE(sample.sum == 12.0);
    REQUIRE(sample.min == 3.0);
    REQUIRE(sample.max == 9.0);
}

TEST_CASE("Field selects the statistic to read", "[metric_sample]") {
    MetricSample sample;
    sample.add(2.0);
    sample.add(6.0);

    REQUIRE(value_of(sample, MetricField::Avg) == 4.0);
    REQUIRE(value_of(sample, MetricField::Min) == 2.0);
    REQUIRE(value_of(sample, MetricField::Max) == 6.0);
    REQUIRE(value_of(sample, MetricField::Sum) == 8.0);
    REQUIRE(value_of(sample, MetricField::Count) == 2.0);
}

TEST_CASE("Reset empties the sample", "[metric_sample]") {
    MetricSample sample;
    sample.add(5.0);

    sample.reset();

    REQUIRE(sample.is_empty());
    REQUIRE(sample.max == 0.0);
}
