#include <glog/logging.h>
#include <gtest/gtest.h>
+#include "folly/Foreach.h"
+
using std::chrono::seconds;
using std::string;
using std::vector;
EXPECT_NEAR(1.5, ts.countRate(), 0.005);
}
+TEST(BucketedTimeSeries, avgTypeConversion) {
+ // Make sure the computed average values are accurate regardless
+ // of the input type and return type.
+
+ {
+ // Simple sanity tests for small positive integer values
+ BucketedTimeSeries<int64_t> ts(60, seconds(600));
+ ts.addValue(seconds(0), 4, 100);
+ ts.addValue(seconds(0), 10, 200);
+ ts.addValue(seconds(0), 16, 100);
+
+ EXPECT_DOUBLE_EQ(10.0, ts.avg());
+ EXPECT_DOUBLE_EQ(10.0, ts.avg<float>());
+ EXPECT_EQ(10, ts.avg<uint64_t>());
+ EXPECT_EQ(10, ts.avg<int64_t>());
+ EXPECT_EQ(10, ts.avg<int32_t>());
+ EXPECT_EQ(10, ts.avg<int16_t>());
+ EXPECT_EQ(10, ts.avg<int8_t>());
+ EXPECT_EQ(10, ts.avg<uint8_t>());
+ }
+
+ {
+ // Test signed integer types with negative values
+ BucketedTimeSeries<int64_t> ts(60, seconds(600));
+ ts.addValue(seconds(0), -100);
+ ts.addValue(seconds(0), -200);
+ ts.addValue(seconds(0), -300);
+ ts.addValue(seconds(0), -200, 65535);
+
+ EXPECT_DOUBLE_EQ(-200.0, ts.avg());
+ EXPECT_DOUBLE_EQ(-200.0, ts.avg<float>());
+ EXPECT_EQ(-200, ts.avg<int64_t>());
+ EXPECT_EQ(-200, ts.avg<int32_t>());
+ EXPECT_EQ(-200, ts.avg<int16_t>());
+ }
+
+ {
+ // Test uint64_t values that would overflow int64_t
+ BucketedTimeSeries<uint64_t> ts(60, seconds(600));
+ ts.addValueAggregated(seconds(0),
+ std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+
+ EXPECT_DOUBLE_EQ(1.0, ts.avg());
+ EXPECT_DOUBLE_EQ(1.0, ts.avg<float>());
+ EXPECT_EQ(1, ts.avg<uint64_t>());
+ EXPECT_EQ(1, ts.avg<int64_t>());
+ EXPECT_EQ(1, ts.avg<int8_t>());
+ }
+
+ {
+ // Test doubles with small-ish values that will fit in integer types
+ BucketedTimeSeries<double> ts(60, seconds(600));
+ ts.addValue(seconds(0), 4.0, 100);
+ ts.addValue(seconds(0), 10.0, 200);
+ ts.addValue(seconds(0), 16.0, 100);
+
+ EXPECT_DOUBLE_EQ(10.0, ts.avg());
+ EXPECT_DOUBLE_EQ(10.0, ts.avg<float>());
+ EXPECT_EQ(10, ts.avg<uint64_t>());
+ EXPECT_EQ(10, ts.avg<int64_t>());
+ EXPECT_EQ(10, ts.avg<int32_t>());
+ EXPECT_EQ(10, ts.avg<int16_t>());
+ EXPECT_EQ(10, ts.avg<int8_t>());
+ EXPECT_EQ(10, ts.avg<uint8_t>());
+ }
+
+ {
+ // Test doubles with huge values
+ BucketedTimeSeries<double> ts(60, seconds(600));
+ ts.addValue(seconds(0), 1e19, 100);
+ ts.addValue(seconds(0), 2e19, 200);
+ ts.addValue(seconds(0), 3e19, 100);
+
+ EXPECT_DOUBLE_EQ(ts.avg(), 2e19);
+ EXPECT_NEAR(ts.avg<float>(), 2e19, 1e11);
+ }
+
+ {
+ // Test doubles where the sum adds up larger than a uint64_t,
+ // but the average fits in an int64_t
+ BucketedTimeSeries<double> ts(60, seconds(600));
+ uint64_t value = 0x3fffffffffffffff;
+ FOR_EACH_RANGE(i, 0, 16) {
+ ts.addValue(seconds(0), value);
+ }
+
+ EXPECT_DOUBLE_EQ(value, ts.avg());
+ EXPECT_DOUBLE_EQ(value, ts.avg<float>());
+ // Some precision is lost here due to the huge sum, so the
+ // integer average returned is off by one.
+ EXPECT_NEAR(value, ts.avg<uint64_t>(), 1);
+ EXPECT_NEAR(value, ts.avg<int64_t>(), 1);
+ }
+
+ {
+ // Test BucketedTimeSeries with a smaller integer type
+ BucketedTimeSeries<int16_t> ts(60, seconds(600));
+ FOR_EACH_RANGE(i, 0, 101) {
+ ts.addValue(seconds(0), i);
+ }
+
+ EXPECT_DOUBLE_EQ(50.0, ts.avg());
+ EXPECT_DOUBLE_EQ(50.0, ts.avg<float>());
+ EXPECT_EQ(50, ts.avg<uint64_t>());
+ EXPECT_EQ(50, ts.avg<int64_t>());
+ EXPECT_EQ(50, ts.avg<int16_t>());
+ EXPECT_EQ(50, ts.avg<int8_t>());
+ }
+
+ {
+ // Test BucketedTimeSeries with long double input
+ BucketedTimeSeries<long double> ts(60, seconds(600));
+ ts.addValueAggregated(seconds(0), 1000.0L, 7);
+
+ long double expected = 1000.0L / 7.0L;
+ EXPECT_DOUBLE_EQ(static_cast<double>(expected), ts.avg());
+ EXPECT_DOUBLE_EQ(static_cast<float>(expected), ts.avg<float>());
+ EXPECT_DOUBLE_EQ(expected, ts.avg<long double>());
+ EXPECT_EQ(static_cast<uint64_t>(expected), ts.avg<uint64_t>());
+ EXPECT_EQ(static_cast<int64_t>(expected), ts.avg<int64_t>());
+ }
+
+ {
+ // Test BucketedTimeSeries with int64_t values,
+ // but using an average that requires a fair amount of precision.
+ BucketedTimeSeries<int64_t> ts(60, seconds(600));
+ ts.addValueAggregated(seconds(0), 1000, 7);
+
+ long double expected = 1000.0L / 7.0L;
+ EXPECT_DOUBLE_EQ(static_cast<double>(expected), ts.avg());
+ EXPECT_DOUBLE_EQ(static_cast<float>(expected), ts.avg<float>());
+ EXPECT_DOUBLE_EQ(expected, ts.avg<long double>());
+ EXPECT_EQ(static_cast<uint64_t>(expected), ts.avg<uint64_t>());
+ EXPECT_EQ(static_cast<int64_t>(expected), ts.avg<int64_t>());
+ }
+}
+
TEST(BucketedTimeSeries, forEachBucket) {
typedef BucketedTimeSeries<int64_t>::Bucket Bucket;
struct BucketInfo {