chromium/chromecast/base/statistics/weighted_moving_average_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <math.h>

#include "chromecast/base/statistics/weighted_moving_average.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromecast {

TEST(WeightedMovingAverageTest, NoSamples) {
  WeightedMovingAverage averager(0);

  int64_t avg = 12345;
  double error = 12345.0;
  EXPECT_FALSE(averager.Average(&avg, &error));
  EXPECT_EQ(12345, avg);
  EXPECT_EQ(12345.0, error);
}

TEST(WeightedMovingAverageTest, ZeroWeight) {
  WeightedMovingAverage averager(0);
  for (int s = 1; s <= 5; ++s)
    averager.AddSample(0, s, 0.0);

  int64_t avg = 12345;
  double error = 12345.0;
  EXPECT_FALSE(averager.Average(&avg, &error));
  EXPECT_EQ(12345, avg);
  EXPECT_EQ(12345.0, error);
}

TEST(WeightedMovingAverageTest, AverageOneValue) {
  int64_t value = 1;

  WeightedMovingAverage averager(0);
  averager.AddSample(0, value, 1.0);

  int64_t avg = 0;
  double error = 1.0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(value, avg);
  EXPECT_EQ(0.0, error);
}

TEST(WeightedMovingAverageTest, AverageSeveralUnweightedValues) {
  WeightedMovingAverage averager(0);
  for (int s = 1; s <= 5; ++s)
    averager.AddSample(0, s, 1.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(3, avg);
  EXPECT_NEAR(sqrt(2) / sqrt(5), error, 1e-9);
}

TEST(WeightedMovingAverageTest, Clear) {
  WeightedMovingAverage averager(0);
  for (int s = 1; s <= 5; ++s)
    averager.AddSample(0, s, 1.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(3, avg);
  EXPECT_NEAR(sqrt(2) / sqrt(5), error, 1e-9);

  averager.Clear();
  EXPECT_FALSE(averager.Average(&avg, &error));

  for (int s = 1; s <= 5; ++s)
    averager.AddSample(0, s, 1.0);

  avg = 0;
  error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(3, avg);
  EXPECT_NEAR(sqrt(2) / sqrt(5), error, 1e-9);
}

TEST(WeightedMovingAverageTest, AverageSeveralWeightedValues) {
  WeightedMovingAverage averager(0);
  averager.AddSample(0, 1, 2.0);
  averager.AddSample(0, 2, 1.0);
  averager.AddSample(0, 3, 0.0);
  averager.AddSample(0, 4, 1.0);
  averager.AddSample(0, 5, 2.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(3, avg);
  // <sum of weights>^2 / <sum of weights^2>
  double effective_sample_size = 36.0 / 10.0;
  EXPECT_NEAR(sqrt(3) / sqrt(effective_sample_size), error, 1e-9);
}

TEST(WeightedMovingAverageTest, DropOldValues) {
  WeightedMovingAverage averager(1);
  for (int s = 0; s < 10; ++s)
    averager.AddSample(s, 100, 5.0);

  averager.AddSample(10, 1, 1.0);
  averager.AddSample(11, 3, 1.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(2, avg);
  EXPECT_DOUBLE_EQ(1.0 / sqrt(2), error);
}

TEST(WeightedMovingAverageTest, DropOldValuesUneven) {
  WeightedMovingAverage averager(5);
  for (int s = 0; s < 10; ++s)
    averager.AddSample(s * s, 100, 5.0);

  averager.AddSample(100, 1, 1.0);
  averager.AddSample(105, 3, 1.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(2, avg);
  EXPECT_DOUBLE_EQ(1.0 / sqrt(2), error);
}

TEST(WeightedMovingAverageTest, DropOldValuesByAddingZeroWeightValues) {
  WeightedMovingAverage averager(5);
  for (int s = 0; s < 10; ++s)
    averager.AddSample(s, 1, 5.0);

  // Adding values with weight 0 still drops old values.
  for (int s = 11; s < 15; ++s)
    averager.AddSample(s, 100, 0.0);

  averager.AddSample(15, 10, 1.0);

  int64_t avg = 0;
  double error = 0;
  EXPECT_TRUE(averager.Average(&avg, &error));
  EXPECT_EQ(10, avg);
  EXPECT_DOUBLE_EQ(0.0, error);
}

}  // namespace chromecast