/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "video/stats_counter.h"

#include "system_wrappers/include/clock.h"
#include "test/gtest.h"

namespace webrtc {
namespace {
const int kDefaultProcessIntervalMs = 2000;
const uint32_t kStreamId = 123456;

class StatsCounterObserverImpl : public StatsCounterObserver {
 public:
  StatsCounterObserverImpl() : num_calls_(0), last_sample_(-1) {}
  void OnMetricUpdated(int sample) override {
    ++num_calls_;
    last_sample_ = sample;
  }
  int num_calls_;
  int last_sample_;
};
}  // namespace

class StatsCounterTest : public ::testing::Test {
 protected:
  StatsCounterTest() : clock_(1234) {}

  void AddSampleAndAdvance(int sample, int interval_ms, AvgCounter* counter) {
    counter->Add(sample);
    clock_.AdvanceTimeMilliseconds(interval_ms);
  }

  void SetSampleAndAdvance(int sample,
                           int interval_ms,
                           RateAccCounter* counter) {
    counter->Set(sample, kStreamId);
    clock_.AdvanceTimeMilliseconds(interval_ms);
  }

  void VerifyStatsIsNotSet(const AggregatedStats& stats) {
    EXPECT_EQ(0, stats.num_samples);
    EXPECT_EQ(-1, stats.min);
    EXPECT_EQ(-1, stats.max);
    EXPECT_EQ(-1, stats.average);
  }

  SimulatedClock clock_;
};

TEST_F(StatsCounterTest, NoSamples) {
  AvgCounter counter(&clock_, nullptr, false);
  VerifyStatsIsNotSet(counter.GetStats());
}

TEST_F(StatsCounterTest, TestRegisterObserver) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  const int kSample = 22;
  AvgCounter counter(&clock_, observer, false);
  AddSampleAndAdvance(kSample, kDefaultProcessIntervalMs, &counter);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  EXPECT_EQ(1, observer->num_calls_);
}

TEST_F(StatsCounterTest, HasSample) {
  AvgCounter counter(&clock_, nullptr, false);
  EXPECT_FALSE(counter.HasSample());
  counter.Add(1);
  EXPECT_TRUE(counter.HasSample());
}

TEST_F(StatsCounterTest, VerifyProcessInterval) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, false);
  counter.Add(4);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 1);
  // Try trigger process (interval has not passed).
  counter.Add(8);
  EXPECT_EQ(0, observer->num_calls_);
  VerifyStatsIsNotSet(counter.GetStats());
  // Make process interval pass.
  clock_.AdvanceTimeMilliseconds(1);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
}

TEST_F(StatsCounterTest, TestMetric_AvgCounter) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, false);
  counter.Add(4);
  counter.Add(8);
  counter.Add(9);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  // Average per interval.
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(7, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(7, stats.min);
  EXPECT_EQ(7, stats.max);
  EXPECT_EQ(7, stats.average);
}

TEST_F(StatsCounterTest, TestMetric_MaxCounter) {
  const int64_t kProcessIntervalMs = 1000;
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  MaxCounter counter(&clock_, observer, kProcessIntervalMs);
  counter.Add(4);
  counter.Add(9);
  counter.Add(8);
  clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  // Average per interval.
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(9, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(9, stats.min);
  EXPECT_EQ(9, stats.max);
  EXPECT_EQ(9, stats.average);
}

TEST_F(StatsCounterTest, TestMetric_PercentCounter) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  PercentCounter counter(&clock_, observer);
  counter.Add(true);
  counter.Add(false);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Add(false);
  // Percentage per interval.
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(50, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(50, stats.min);
  EXPECT_EQ(50, stats.max);
}

TEST_F(StatsCounterTest, TestMetric_PermilleCounter) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  PermilleCounter counter(&clock_, observer);
  counter.Add(true);
  counter.Add(false);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Add(false);
  // Permille per interval.
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(500, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(500, stats.min);
  EXPECT_EQ(500, stats.max);
}

TEST_F(StatsCounterTest, TestMetric_RateCounter) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateCounter counter(&clock_, observer, true);
  counter.Add(186);
  counter.Add(350);
  counter.Add(22);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  // Rate per interval, (186 + 350 + 22) / 2 sec = 279 samples/sec
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(279, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(279, stats.min);
  EXPECT_EQ(279, stats.max);
}

TEST_F(StatsCounterTest, TestMetric_RateAccCounter) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  counter.Set(175, kStreamId);
  counter.Set(188, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Set(192, kStreamId);
  // Rate per interval: (188 - 0) / 2 sec = 94 samples/sec
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(94, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(94, stats.min);
  EXPECT_EQ(94, stats.max);
}

TEST_F(StatsCounterTest, TestMetric_RateAccCounterWithSetLast) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  counter.SetLast(98, kStreamId);
  counter.Set(175, kStreamId);
  counter.Set(188, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Set(192, kStreamId);
  // Rate per interval: (188 - 98) / 2 sec = 45 samples/sec
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(45, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestMetric_RateAccCounterWithMultipleStreamIds) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  counter.Set(175, kStreamId);
  counter.Set(188, kStreamId);
  counter.Set(100, kStreamId + 1);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Set(150, kStreamId + 1);
  // Rate per interval: ((188 - 0) + (100 - 0)) / 2 sec = 144 samples/sec
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(144, observer->last_sample_);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Set(198, kStreamId);
  // Rate per interval: (0 + (150 - 100)) / 2 sec = 25 samples/sec
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(25, observer->last_sample_);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process (sample included in next interval).
  counter.Set(200, kStreamId);
  // Rate per interval: ((198 - 188) + (0)) / 2 sec = 5 samples/sec
  EXPECT_EQ(3, observer->num_calls_);
  EXPECT_EQ(5, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(3, stats.num_samples);
  EXPECT_EQ(5, stats.min);
  EXPECT_EQ(144, stats.max);
}

TEST_F(StatsCounterTest, TestGetStats_MultipleIntervals) {
  AvgCounter counter(&clock_, nullptr, false);
  const int kSample1 = 1;
  const int kSample2 = 5;
  const int kSample3 = 8;
  const int kSample4 = 11;
  const int kSample5 = 50;
  AddSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter);
  AddSampleAndAdvance(kSample2, kDefaultProcessIntervalMs, &counter);
  AddSampleAndAdvance(kSample3, kDefaultProcessIntervalMs, &counter);
  AddSampleAndAdvance(kSample4, kDefaultProcessIntervalMs, &counter);
  AddSampleAndAdvance(kSample5, kDefaultProcessIntervalMs, &counter);
  // Trigger process (sample included in next interval).
  counter.Add(111);
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(5, stats.num_samples);
  EXPECT_EQ(kSample1, stats.min);
  EXPECT_EQ(kSample5, stats.max);
  EXPECT_EQ(15, stats.average);
}

TEST_F(StatsCounterTest, TestGetStatsTwice) {
  const int kSample1 = 4;
  const int kSample2 = 7;
  AvgCounter counter(&clock_, nullptr, false);
  AddSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter);
  // Trigger process (sample included in next interval).
  counter.Add(kSample2);
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(1, stats.num_samples);
  EXPECT_EQ(kSample1, stats.min);
  EXPECT_EQ(kSample1, stats.max);
  // Trigger process (sample included in next interval).
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.Add(111);
  stats = counter.GetStats();
  EXPECT_EQ(2, stats.num_samples);
  EXPECT_EQ(kSample1, stats.min);
  EXPECT_EQ(kSample2, stats.max);
  EXPECT_EQ(6, stats.average);
}

TEST_F(StatsCounterTest, TestRateAccCounter_NegativeRateIgnored) {
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  const int kSample1 = 200;  //  200 / 2 sec
  const int kSample2 = 100;  // -100 / 2 sec - negative ignored
  const int kSample3 = 700;  //  600 / 2 sec
  RateAccCounter counter(&clock_, observer, true);
  SetSampleAndAdvance(kSample1, kDefaultProcessIntervalMs, &counter);
  SetSampleAndAdvance(kSample2, kDefaultProcessIntervalMs, &counter);
  SetSampleAndAdvance(kSample3, kDefaultProcessIntervalMs, &counter);
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(100, observer->last_sample_);
  // Trigger process (sample included in next interval).
  counter.Set(2000, kStreamId);
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(300, observer->last_sample_);
  // Aggregated stats.
  AggregatedStats stats = counter.GetStats();
  EXPECT_EQ(2, stats.num_samples);
  EXPECT_EQ(100, stats.min);
  EXPECT_EQ(300, stats.max);
  EXPECT_EQ(200, stats.average);
}

TEST_F(StatsCounterTest, TestAvgCounter_IntervalsWithoutSamplesIncluded) {
  // Samples: | 6 | x | x | 8 |  // x: empty interval
  // Stats:   | 6 | 6 | 6 | 8 |  // x -> last value reported
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, true);
  AddSampleAndAdvance(6, kDefaultProcessIntervalMs * 4 - 1, &counter);
  // Trigger process (sample included in next interval).
  counter.Add(8);
  // [6:3], 3 intervals passed (2 without samples -> last value reported).
  AggregatedStats stats = counter.ProcessAndGetStats();
  EXPECT_EQ(3, stats.num_samples);
  EXPECT_EQ(6, stats.min);
  EXPECT_EQ(6, stats.max);
  // Make next interval pass and verify stats: [6:3],[8:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(4, observer->num_calls_);
  EXPECT_EQ(8, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestAvgCounter_WithPause) {
  // Samples: | 6 | x | x | x | - | 22 | x  |  // x: empty interval, -: paused
  // Stats:   | 6 | 6 | 6 | 6 | - | 22 | 22 |  // x -> last value reported
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, true);
  // Add sample and advance 3 intervals (2 w/o samples -> last value reported).
  AddSampleAndAdvance(6, kDefaultProcessIntervalMs * 4 - 1, &counter);
  // Trigger process and verify stats: [6:3]
  counter.ProcessAndGetStats();
  EXPECT_EQ(3, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Make next interval pass (1 without samples).
  // Process and pause. Verify stats: [6:4].
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndPause();
  EXPECT_EQ(4, observer->num_calls_);  // Last value reported.
  EXPECT_EQ(6, observer->last_sample_);
  // Make next interval pass (1 without samples -> ignored while paused).
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - 1);
  counter.Add(22);  // Stops pause.
  EXPECT_EQ(4, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Make next interval pass, [6:4][22:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(5, observer->num_calls_);
  EXPECT_EQ(22, observer->last_sample_);
  // Make 1 interval pass (1 w/o samples -> pause stopped, last value reported).
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(6, observer->num_calls_);
  EXPECT_EQ(22, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateAccCounter_AddSampleStopsPause) {
  // Samples: | 12 | 24 |  // -: paused
  // Stats:   | 6  | 6  |
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  // Add sample and advance 1 intervals.
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process and verify stats: [6:1]
  counter.ProcessAndPause();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Add sample and advance 1 intervals.
  counter.Set(24, kStreamId);  // Pause stopped.
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateAccCounter_AddSameSampleDoesNotStopPause) {
  // Samples: | 12 | 12 | 24 |  // -: paused
  // Stats:   | 6  | -  | 6  |
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  // Add sample and advance 1 intervals.
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process and verify stats: [6:1]
  counter.ProcessAndPause();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Add same sample and advance 1 intervals.
  counter.Set(12, kStreamId);  // Pause not stopped.
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Add new sample and advance 1 intervals.
  counter.Set(24, kStreamId);  // Pause stopped.
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateAccCounter_PauseAndStopPause) {
  // Samples: | 12 | 12 | 12 |  // -: paused
  // Stats:   | 6  | -  | 0  |
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  // Add sample and advance 1 intervals.
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  // Trigger process and verify stats: [6:1]
  counter.ProcessAndPause();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Add same sample and advance 1 intervals.
  counter.Set(12, kStreamId);  // Pause not stopped.
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Stop pause, add sample and advance 1 intervals.
  counter.ProcessAndStopPause();
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(0, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestAvgCounter_WithoutMinPauseTimePassed) {
  // Samples: | 6 | 2 | - |  // x: empty interval, -: paused
  // Stats:   | 6 | 2 | - |  // x -> last value reported
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, true);
  // Add sample and advance 1 intervals.
  AddSampleAndAdvance(6, kDefaultProcessIntervalMs, &counter);
  // Process and pause. Verify stats: [6:1].
  const int64_t kMinMs = 500;
  counter.ProcessAndPauseForDuration(kMinMs);
  EXPECT_EQ(1, observer->num_calls_);  // Last value reported.
  EXPECT_EQ(6, observer->last_sample_);
  // Min pause time has not pass.
  clock_.AdvanceTimeMilliseconds(kMinMs - 1);
  counter.Add(2);  // Pause not stopped.
  // Make two intervals pass (1 without samples -> ignored while paused).
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - (kMinMs - 1));
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(2, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestAvgCounter_WithMinPauseTimePassed) {
  // Samples: | 6 | 2 | x |  // x: empty interval, -: paused
  // Stats:   | 6 | 2 | 2 |  // x -> last value reported
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  AvgCounter counter(&clock_, observer, true);
  // Add sample and advance 1 intervals.
  AddSampleAndAdvance(6, kDefaultProcessIntervalMs, &counter);
  // Process and pause. Verify stats: [6:1].
  const int64_t kMinMs = 500;
  counter.ProcessAndPauseForDuration(kMinMs);
  EXPECT_EQ(1, observer->num_calls_);  // Last value reported.
  EXPECT_EQ(6, observer->last_sample_);
  // Make min pause time pass.
  clock_.AdvanceTimeMilliseconds(kMinMs);
  counter.Add(2);  // Stop pause.
  // Make two intervals pass (1 without samples -> last value reported).
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 2 - kMinMs);
  counter.ProcessAndGetStats();
  EXPECT_EQ(3, observer->num_calls_);
  EXPECT_EQ(2, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateCounter_IntervalsWithoutSamplesIgnored) {
  // Samples: | 50 | x | 20 |  // x: empty interval
  // Stats:   | 25 | x | 10 |  // x -> ignored
  const bool kIncludeEmptyIntervals = false;
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  const int kSample1 = 50;  //  50 / 2 sec
  const int kSample2 = 20;  //  20 / 2 sec
  RateCounter counter(&clock_, observer, kIncludeEmptyIntervals);
  counter.Add(kSample1);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 3 - 1);
  // Trigger process (sample included in next interval).
  counter.Add(kSample2);
  // [25:1], 2 intervals passed (1 without samples -> ignored).
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(25, observer->last_sample_);
  // Make next interval pass and verify stats: [10:1],[25:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(10, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateCounter_IntervalsWithoutSamplesIncluded) {
  // Samples: | 50 | x | 20 |  // x: empty interval
  // Stats:   | 25 | 0 | 10 |  // x -> zero reported
  const bool kIncludeEmptyIntervals = true;
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  const int kSample1 = 50;  //  50 / 2 sec
  const int kSample2 = 20;  //  20 / 2 sec
  RateCounter counter(&clock_, observer, kIncludeEmptyIntervals);
  counter.Add(kSample1);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 3 - 1);
  // Trigger process (sample included in next interval).
  counter.Add(kSample2);
  // [0:1],[25:1], 2 intervals passed (1 without samples -> zero reported).
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(0, observer->last_sample_);
  // Make last interval pass and verify stats: [0:1],[10:1],[25:1]
  clock_.AdvanceTimeMilliseconds(1);
  AggregatedStats stats = counter.ProcessAndGetStats();
  EXPECT_EQ(25, stats.max);
  EXPECT_EQ(3, observer->num_calls_);
  EXPECT_EQ(10, observer->last_sample_);
}

TEST_F(StatsCounterTest, TestRateAccCounter_IntervalsWithoutSamplesIncluded) {
  // Samples: | 12 | x | x | x | 60 |  // x: empty interval
  // Stats:   | 6  | 0 | 0 | 0 | 24 |  // x -> zero reported
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, true);
  VerifyStatsIsNotSet(counter.ProcessAndGetStats());
  // Advance one interval and verify stats.
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs);
  VerifyStatsIsNotSet(counter.ProcessAndGetStats());
  // Add sample and advance 3 intervals (2 w/o samples -> zero reported).
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 4 - 1);
  // Trigger process and verify stats: [0:2][6:1]
  counter.ProcessAndGetStats();
  EXPECT_EQ(3, observer->num_calls_);
  EXPECT_EQ(0, observer->last_sample_);
  // Make next interval pass (1 w/o samples -> zero reported), [0:3][6:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(4, observer->num_calls_);
  EXPECT_EQ(0, observer->last_sample_);
  // Insert sample and advance non-complete interval, no change, [0:3][6:1]
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 1);
  counter.Set(60, kStreamId);
  EXPECT_EQ(4, observer->num_calls_);
  // Make next interval pass, [0:3][6:1][24:1]
  clock_.AdvanceTimeMilliseconds(1);
  AggregatedStats stats = counter.ProcessAndGetStats();
  EXPECT_EQ(5, observer->num_calls_);
  EXPECT_EQ(24, observer->last_sample_);
  EXPECT_EQ(6, stats.average);
}

TEST_F(StatsCounterTest, TestRateAccCounter_IntervalsWithoutSamplesIgnored) {
  // Samples: | 12 | x | x | x | 60 |  // x: empty interval
  // Stats:   | 6  | x | x | x | 24 |  // x -> ignored
  StatsCounterObserverImpl* observer = new StatsCounterObserverImpl();
  RateAccCounter counter(&clock_, observer, false);
  // Add sample and advance 3 intervals (2 w/o samples -> ignored).
  counter.Set(12, kStreamId);
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs * 4 - 1);
  // Trigger process and verify stats: [6:1]
  counter.ProcessAndGetStats();
  EXPECT_EQ(1, observer->num_calls_);
  EXPECT_EQ(6, observer->last_sample_);
  // Make next interval pass (1 w/o samples -> ignored), [6:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(1, observer->num_calls_);
  // Insert sample and advance non-complete interval, no change, [6:1]
  clock_.AdvanceTimeMilliseconds(kDefaultProcessIntervalMs - 1);
  counter.Set(60, kStreamId);
  counter.ProcessAndGetStats();
  EXPECT_EQ(1, observer->num_calls_);
  // Make next interval pass, [6:1][24:1]
  clock_.AdvanceTimeMilliseconds(1);
  counter.ProcessAndGetStats();
  EXPECT_EQ(2, observer->num_calls_);
  EXPECT_EQ(24, observer->last_sample_);
}

}  // namespace webrtc
