text: // 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 "base/bind.h"
  #include "base/message_loop/message_loop.h"
  #include "base/run_loop.h"
  #include "device/battery/battery_status_manager.h"
  #include "device/battery/battery_status_service.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace device {
  
  namespace {
  
  class FakeBatteryManager : public BatteryStatusManager {
   public:
    explicit FakeBatteryManager(
        const BatteryStatusService::BatteryUpdateCallback& callback)
        : callback_(callback), start_invoked_count_(0), stop_invoked_count_(0) {}
    ~FakeBatteryManager() override {}
  
    // Methods from Battery Status Manager
    bool StartListeningBatteryChange() override {
      start_invoked_count_++;
      return true;
    }
  
    void StopListeningBatteryChange() override { stop_invoked_count_++; }
  
    void InvokeUpdateCallback(const BatteryStatus& status) {
      callback_.Run(status);
    }
  
    int start_invoked_count() const { return start_invoked_count_; }
    int stop_invoked_count() const { return stop_invoked_count_; }
  
   private:
    BatteryStatusService::BatteryUpdateCallback callback_;
    int start_invoked_count_;
    int stop_invoked_count_;
  
    DISALLOW_COPY_AND_ASSIGN(FakeBatteryManager);
  };
  
  class BatteryStatusServiceTest : public testing::Test {
   public:
      BatteryStatusServiceTest()
          : battery_service_(NULL),
            battery_manager_(NULL),
            callback1_invoked_count_(0),
            callback2_invoked_count_(0) {
      }
      ~BatteryStatusServiceTest() override {}
  
   protected:
    typedef BatteryStatusService::BatteryUpdateSubscription BatterySubscription;
  
    void SetUp() override {
      callback1_ = base::Bind(&BatteryStatusServiceTest::Callback1,
                              base::Unretained(this));
      callback2_ = base::Bind(&BatteryStatusServiceTest::Callback2,
                              base::Unretained(this));
      battery_service_ = BatteryStatusService::GetInstance();
  
      // We keep a raw pointer to the FakeBatteryManager, which we expect to
      // remain valid for the lifetime of the BatteryStatusService.
      scoped_ptr<FakeBatteryManager> battery_manager(new FakeBatteryManager(
          battery_service_->GetUpdateCallbackForTesting()));
      battery_manager_ = battery_manager.get();
  
      battery_service_->SetBatteryManagerForTesting(battery_manager.Pass());
    }
  
    void TearDown() override {
      base::RunLoop().RunUntilIdle();
      battery_service_->SetBatteryManagerForTesting(
          scoped_ptr<BatteryStatusManager>());
    }
  
    FakeBatteryManager* battery_manager() {
      return battery_manager_;
    }
  
    scoped_ptr<BatterySubscription> AddCallback(
        const BatteryStatusService::BatteryUpdateCallback& callback) {
      return battery_service_->AddCallback(callback);
    }
  
    int callback1_invoked_count() const {
      return callback1_invoked_count_;
    }
  
    int callback2_invoked_count() const {
      return callback2_invoked_count_;
    }
  
    const BatteryStatus& battery_status() const {
      return battery_status_;
    }
  
    const BatteryStatusService::BatteryUpdateCallback& callback1() const {
      return callback1_;
    }
  
    const BatteryStatusService::BatteryUpdateCallback& callback2() const {
      return callback2_;
    }
  
   private:
    void Callback1(const BatteryStatus& status) {
      callback1_invoked_count_++;
      battery_status_ = status;
    }
  
    void Callback2(const BatteryStatus& status) {
      callback2_invoked_count_++;
      battery_status_ = status;
    }
  
    base::MessageLoop message_loop_;
    BatteryStatusService* battery_service_;
    FakeBatteryManager* battery_manager_;
    BatteryStatusService::BatteryUpdateCallback callback1_;
    BatteryStatusService::BatteryUpdateCallback callback2_;
    int callback1_invoked_count_;
    int callback2_invoked_count_;
    BatteryStatus battery_status_;
  
    DISALLOW_COPY_AND_ASSIGN(BatteryStatusServiceTest);
  };
  
  TEST_F(BatteryStatusServiceTest, AddFirstCallback) {
    scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
    EXPECT_EQ(1, battery_manager()->start_invoked_count());
    EXPECT_EQ(0, battery_manager()->stop_invoked_count());
    subscription1.reset();
    EXPECT_EQ(1, battery_manager()->start_invoked_count());
    EXPECT_EQ(1, battery_manager()->stop_invoked_count());
  }
  
  // Fails on Windows. http://crbug.com/429942.
  #if defined(OS_WIN)
  #define MAYBE_AddCallbackAfterUpdate DISABLED_AddCallbackAfterUpdate
  #else
  #define MAYBE_AddCallbackAfterUpdate AddCallbackAfterUpdate
  #endif
  TEST_F(BatteryStatusServiceTest, MAYBE_AddCallbackAfterUpdate) {
    scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
    BatteryStatus status;
    battery_manager()->InvokeUpdateCallback(status);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, callback1_invoked_count());
    EXPECT_EQ(0, callback2_invoked_count());
  
    scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
    EXPECT_EQ(1, callback1_invoked_count());
    EXPECT_EQ(1, callback2_invoked_count());
  }
  
  // Fails on Windows. http://crbug.com/429942.
  #if defined(OS_WIN)
  #define MAYBE_TwoCallbacksUpdate DISABLED_TwoCallbacksUpdate
  #else
  #define MAYBE_TwoCallbacksUpdate TwoCallbacksUpdate
  #endif
  TEST_F(BatteryStatusServiceTest, MAYBE_TwoCallbacksUpdate) {
    scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
    scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
  
    BatteryStatus status;
    status.charging = true;
    status.charging_time = 100;
    status.discharging_time = 200;
    status.level = 0.5;
    battery_manager()->InvokeUpdateCallback(status);
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(1, callback1_invoked_count());
    EXPECT_EQ(1, callback2_invoked_count());
    EXPECT_EQ(status.charging, battery_status().charging);
    EXPECT_EQ(status.charging_time, battery_status().charging_time);
    EXPECT_EQ(status.discharging_time, battery_status().discharging_time);
    EXPECT_EQ(status.level, battery_status().level);
  }
  
  // Fails on Windows. http://crbug.com/429942.
  #if defined(OS_WIN)
  #define MAYBE_RemoveOneCallback DISABLED_RemoveOneCallback
  #else
  #define MAYBE_RemoveOneCallback RemoveOneCallback
  #endif
  TEST_F(BatteryStatusServiceTest, MAYBE_RemoveOneCallback) {
    scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
    scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
  
    BatteryStatus status;
    battery_manager()->InvokeUpdateCallback(status);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, callback1_invoked_count());
    EXPECT_EQ(1, callback2_invoked_count());
  
    subscription1.reset();
    battery_manager()->InvokeUpdateCallback(status);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, callback1_invoked_count());
    EXPECT_EQ(2, callback2_invoked_count());
  }
  
  }  // namespace
  
  }  // namespace device
  