chromium/chrome/browser/ash/power/auto_screen_brightness/als_samples_unittest.cc

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

#include "chrome/browser/ash/power/auto_screen_brightness/als_samples.h"

#include <cmath>
#include <vector>

#include "base/check_op.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace power {
namespace auto_screen_brightness {

namespace {

// Checks |result.avg| and |result.stddev| are the same as that
// calculated from the |expected_data| vector.
void CheckAverageAndStdDev(const AlsAvgStdDev& result,
                           const std::vector<double>& expected_data) {
  const size_t count = expected_data.size();
  CHECK_NE(count, 0u);
  double expected_avg = 0;
  double expected_stddev = 0;

  for (const auto& i : expected_data) {
    expected_avg += i;
    expected_stddev += i * i;
  }

  expected_avg = expected_avg / count;
  expected_stddev =
      std::sqrt(expected_stddev / count - expected_avg * expected_avg);
  EXPECT_DOUBLE_EQ(result.avg, expected_avg);
  EXPECT_DOUBLE_EQ(result.stddev, expected_stddev);
}

}  // namespace

TEST(AmbientLightSampleBufferTest, Basic) {
  base::SimpleTestTickClock tick_clock;
  AmbientLightSampleBuffer buffer(base::Seconds(5));
  std::vector<double> expected_data;
  for (int i = 1; i < 6; ++i) {
    tick_clock.Advance(base::Seconds(1));
    const AmbientLightSampleBuffer::Sample sample = {static_cast<double>(i),
                                                     tick_clock.NowTicks()};
    expected_data.push_back(i);
    buffer.SaveToBuffer(sample);
    EXPECT_EQ(buffer.NumberOfSamplesForTesting(), static_cast<size_t>(i));
    const AlsAvgStdDev avg_std =
        buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value();

    CheckAverageAndStdDev(avg_std, expected_data);

    EXPECT_EQ(buffer.NumberOfSamplesForTesting(), static_cast<size_t>(i));
  }

  // Add another two items that will push out the oldest.
  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({10, tick_clock.NowTicks()});

  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 5u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(),
      {2, 3, 4, 5, 10});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 5u);

  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({20, tick_clock.NowTicks()});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 5u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(),
      {3, 4, 5, 10, 20});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 5u);

  // Add another item but it doesn't push out the oldest.
  tick_clock.Advance(base::Milliseconds(1));
  buffer.SaveToBuffer({100, tick_clock.NowTicks()});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 6u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(),
      {3, 4, 5, 10, 20, 100});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 6u);
}

TEST(AmbientLightSampleBufferTest, LargeSampleTimeGap) {
  base::SimpleTestTickClock tick_clock;
  AmbientLightSampleBuffer buffer(base::Seconds(5));
  tick_clock.Advance(base::Seconds(1));
  const AmbientLightSampleBuffer::Sample sample = {10, tick_clock.NowTicks()};
  buffer.SaveToBuffer(sample);
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(), {10});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);

  // Another samples arrives sufficiently late so the 1st sample is pushed out.
  tick_clock.Advance(base::Seconds(5));
  buffer.SaveToBuffer({20, tick_clock.NowTicks()});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(), {20});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);
}

TEST(AmbientLightSampleBufferTest, AverageTimeTooLate) {
  base::SimpleTestTickClock tick_clock;
  AmbientLightSampleBuffer buffer(base::Seconds(5));
  tick_clock.Advance(base::Seconds(1));
  const AmbientLightSampleBuffer::Sample sample = {10, tick_clock.NowTicks()};
  buffer.SaveToBuffer(sample);
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);
  CheckAverageAndStdDev(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value(), {10});
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);

  // When average is calculated, all samples are too old, hence average is
  // nullopt.
  tick_clock.Advance(base::Seconds(5));
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 1u);
  EXPECT_FALSE(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).has_value());
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 0u);
}

TEST(AmbientLightSampleBufferTest, BufferCleared) {
  base::SimpleTestTickClock tick_clock;
  AmbientLightSampleBuffer buffer(base::Seconds(5));

  // Save two data points and verify.
  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({10, tick_clock.NowTicks()});

  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({20, tick_clock.NowTicks()});

  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 2u);
  AlsAvgStdDev avg_std =
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value();

  CheckAverageAndStdDev(avg_std, {10, 20});

  // Clear buffer and verify.
  buffer.ClearBuffer();
  EXPECT_EQ(buffer.NumberOfSamplesForTesting(), 0u);
  EXPECT_FALSE(
      buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).has_value());

  // Save another two data points and verify.
  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({30, tick_clock.NowTicks()});

  tick_clock.Advance(base::Seconds(1));
  buffer.SaveToBuffer({40, tick_clock.NowTicks()});
  avg_std = buffer.AverageAmbientWithStdDev(tick_clock.NowTicks()).value();
  CheckAverageAndStdDev(avg_std, {30, 40});
}

}  // namespace auto_screen_brightness
}  // namespace power
}  // namespace ash