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

#include "content/browser/power_usage_monitor_impl.h"

#include "content/public/browser/notification_types.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "device/battery/battery_monitor.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace content {

// Dummy ID to identify a phantom RenderProcessHost in tests.
const int kDummyRenderProcessHostID = 1;

class SystemInterfaceForTest : public PowerUsageMonitor::SystemInterface {
 public:
  SystemInterfaceForTest()
      : num_pending_histogram_reports_(0),
        discharge_percent_per_hour_(0),
        now_(base::Time::FromInternalValue(1000)) {}
  ~SystemInterfaceForTest() override {}

  int num_pending_histogram_reports() const {
    return num_pending_histogram_reports_;
  }

  int discharge_percent_per_hour() const {
    return discharge_percent_per_hour_;
  }

  void AdvanceClockSeconds(int seconds) {
    now_ += base::TimeDelta::FromSeconds(seconds);
  }

  void AdvanceClockMinutes(int minutes) {
    now_ += base::TimeDelta::FromMinutes(minutes);
  }

  void ScheduleHistogramReport(base::TimeDelta delay) override {
    num_pending_histogram_reports_++;
  }

  void CancelPendingHistogramReports() override {
    num_pending_histogram_reports_ = 0;
  }

  void RecordDischargePercentPerHour(int percent_per_hour) override {
    discharge_percent_per_hour_ = percent_per_hour;
  }

  base::Time Now() override { return now_; }

 private:
  int num_pending_histogram_reports_;
  int discharge_percent_per_hour_;
  base::Time now_;
};

class PowerUsageMonitorTest : public testing::Test {
 protected:
  void SetUp() override {
    monitor_.reset(new PowerUsageMonitor);
    // PowerUsageMonitor assumes ownership.
    scoped_ptr<SystemInterfaceForTest> test_interface(
        new SystemInterfaceForTest());
    system_interface_ = test_interface.get();
    monitor_->SetSystemInterfaceForTest(test_interface.Pass());

    // Without live renderers, the monitor won't do anything.
    monitor_->OnRenderProcessNotification(NOTIFICATION_RENDERER_PROCESS_CREATED,
                                          kDummyRenderProcessHostID);
  }

  void UpdateBatteryStatus(bool charging, double battery_level) {
    device::BatteryStatus battery_status;
    battery_status.charging = charging;
    battery_status.level = battery_level;
    monitor_->OnBatteryStatusUpdate(battery_status);
  }

  void KillTestRenderer() {
    monitor_->OnRenderProcessNotification(
        NOTIFICATION_RENDERER_PROCESS_CLOSED, kDummyRenderProcessHostID);
  }

  scoped_ptr<PowerUsageMonitor> monitor_;
  SystemInterfaceForTest* system_interface_;
  TestBrowserThreadBundle thread_bundle_;
};

TEST_F(PowerUsageMonitorTest, StartStopQuickly) {
  // Going on battery power.
  UpdateBatteryStatus(false, 1.0);
  int initial_num_histogram_reports =
      system_interface_->num_pending_histogram_reports();
  ASSERT_GT(initial_num_histogram_reports, 0);

  // Battery level goes down a bit.
  system_interface_->AdvanceClockSeconds(1);
  UpdateBatteryStatus(false, 0.9);
  ASSERT_EQ(initial_num_histogram_reports,
            system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());

  // Wall power connected.
  system_interface_->AdvanceClockSeconds(30);
  UpdateBatteryStatus(true, 0);
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
}

TEST_F(PowerUsageMonitorTest, DischargePercentReported) {
  // Going on battery power.
  UpdateBatteryStatus(false, 1.0);
  int initial_num_histogram_reports =
      system_interface_->num_pending_histogram_reports();
  ASSERT_GT(initial_num_histogram_reports, 0);

  // Battery level goes down a bit.
  system_interface_->AdvanceClockSeconds(30);
  UpdateBatteryStatus(false, 0.9);
  ASSERT_EQ(initial_num_histogram_reports,
            system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());

  // Wall power connected.
  system_interface_->AdvanceClockMinutes(31);
  UpdateBatteryStatus(true, 0);
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
  ASSERT_GT(system_interface_->discharge_percent_per_hour(), 0);
}

TEST_F(PowerUsageMonitorTest, NoRenderersDisablesMonitoring) {
  KillTestRenderer();

  // Going on battery power.
  UpdateBatteryStatus(false, 1.0);
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());

  // Wall power connected.
  system_interface_->AdvanceClockSeconds(30);
  UpdateBatteryStatus(true, 0.5);
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
}

TEST_F(PowerUsageMonitorTest, NoRenderersCancelsInProgressMonitoring) {
  // Going on battery power.
  UpdateBatteryStatus(false, 1.0);
  ASSERT_GT(system_interface_->num_pending_histogram_reports(), 0);
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());

  // All renderers killed.
  KillTestRenderer();
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());

  // Wall power connected.
  system_interface_->AdvanceClockMinutes(31);
  UpdateBatteryStatus(true, 0);
  ASSERT_EQ(0, system_interface_->num_pending_histogram_reports());
  ASSERT_EQ(0, system_interface_->discharge_percent_per_hour());
}

}  // namespace content