/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "BatteryDefender.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <utils/Timers.h>

#include <android-base/file.h>
#include <android-base/properties.h>

#define MIN_TIME_BETWEEN_FILE_UPDATES (WRITE_DELAY_SECS + 1)

class HealthInterface {
  public:
    virtual ~HealthInterface() {}
    virtual bool ReadFileToString(const std::string &path, std::string *content,
                                  bool follow_symlinks);
    virtual int GetIntProperty(const std::string &key, int default_value, int min, int max);
    virtual bool GetBoolProperty(const std::string &key, bool default_value);
    virtual bool SetProperty(const std::string &key, const std::string &value);
    virtual bool WriteStringToFile(const std::string &content, const std::string &path,
                                   bool follow_symlinks);
};

class HealthInterfaceMock : public HealthInterface {
  public:
    virtual ~HealthInterfaceMock() {}

    MOCK_METHOD3(ReadFileToString,
                 bool(const std::string &path, std::string *content, bool follow_symlinks));
    MOCK_METHOD4(GetIntProperty, int(const std::string &key, int default_value, int min, int max));
    MOCK_METHOD2(GetBoolProperty, bool(const std::string &key, bool default_value));
    MOCK_METHOD2(SetProperty, bool(const std::string &key, const std::string &value));
    MOCK_METHOD3(WriteStringToFile,
                 bool(const std::string &content, const std::string &path, bool follow_symlinks));
};

HealthInterfaceMock *mock;

namespace android {
namespace base {

bool ReadFileToString(const std::string &path, std::string *content, bool follow_symlinks) {
    return mock->ReadFileToString(path, content, follow_symlinks);
}

bool WriteStringToFile(const std::string &content, const std::string &path, bool follow_symlinks) {
    return mock->WriteStringToFile(content, path, follow_symlinks);
}

template <typename T>
T GetIntProperty(const std::string &key, T default_value, T min, T max) {
    return (T)(mock->GetIntProperty(key, default_value, min, max));
}

bool GetBoolProperty(const std::string &key, bool default_value) {
    return mock->GetBoolProperty(key, default_value);
}

template int8_t GetIntProperty(const std::string &, int8_t, int8_t, int8_t);
template int16_t GetIntProperty(const std::string &, int16_t, int16_t, int16_t);
template int32_t GetIntProperty(const std::string &, int32_t, int32_t, int32_t);
template int64_t GetIntProperty(const std::string &, int64_t, int64_t, int64_t);

bool SetProperty(const std::string &key, const std::string &value) {
    return mock->SetProperty(key, value);
}

}  // namespace base
}  // namespace android

nsecs_t testvar_systemTimeSecs = 0;
nsecs_t systemTime(int clock) {
    UNUSED(clock);
    return seconds_to_nanoseconds(testvar_systemTimeSecs);
}

namespace hardware {
namespace google {
namespace pixel {
namespace health {

using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Return;
using ::testing::SetArgPointee;

struct android::BatteryProperties props;
BatteryDefender *battDefender;

const char *kPathWiredChargerPresent = "/sys/class/power_supply/usb/present";
const char *kPathWirelessChargerPresent = "/sys/class/power_supply/wireless/present";
const char *kPathPersistChargerPresentTime = "/mnt/vendor/persist/battery/defender_charger_time";
const char *kPathPersistDefenderActiveTime = "/mnt/vendor/persist/battery/defender_active_time";
const char *kPathStartLevel = "/sys/devices/platform/soc/soc:google,charger/charge_start_level";
const char *kPathStopLevel = "/sys/devices/platform/soc/soc:google,charger/charge_stop_level";

const char *kPropChargeLevelVendorStart = "persist.vendor.charge.start.level";
const char *kPropChargeLevelVendorStop = "persist.vendor.charge.stop.level";
const char *kPropBatteryDefenderState = "vendor.battery.defender.state";
const char *kPropBatteryDefenderDisable = "vendor.battery.defender.disable";
const char *kPropBatteryDefenderThreshold = "vendor.battery.defender.threshold";

const char *kPropBatteryDefenderCtrlEnable = "vendor.battery.defender.ctrl.enable";
const char *kPropBatteryDefenderCtrlActivateTime = "vendor.battery.defender.ctrl.trigger_time";
const char *kPropBatteryDefenderCtrlResumeTime = "vendor.battery.defender.ctrl.resume_time";
const char *kPropBatteryDefenderCtrlStartSOC = "vendor.battery.defender.ctrl.recharge_soc_start";
const char *kPropBatteryDefenderCtrlStopSOC = "vendor.battery.defender.ctrl.recharge_soc_stop";
const char *kPropBatteryDefenderCtrlTriggerSOC = "vendor.battery.defender.ctrl.trigger_soc";

class BatteryDefenderTest : public ::testing::Test {
  public:
    BatteryDefenderTest()
        : defender(kPathWirelessChargerPresent, DEFAULT_START_LEVEL_PATH, DEFAULT_STOP_LEVEL_PATH,
                   DEFAULT_TIME_TO_ACTIVATE_SECONDS, DEFAULT_TIME_TO_CLEAR_SECONDS, false) {}

    void SetUp() {
        mock = &mockFixture;

        props = {};
        battDefender = &defender;

        EXPECT_CALL(*mock, SetProperty(_, _)).Times(AnyNumber());
        EXPECT_CALL(*mock, ReadFileToString(_, _, _)).Times(AnyNumber());
        EXPECT_CALL(*mock, GetIntProperty(_, _, _, _)).Times(AnyNumber());
        EXPECT_CALL(*mock, GetBoolProperty(_, _)).Times(AnyNumber());
        EXPECT_CALL(*mock, WriteStringToFile(_, _, _)).Times(AnyNumber());

        ON_CALL(*mock, ReadFileToString(_, _, _))
                .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true)));

        ON_CALL(*mock, WriteStringToFile(_, _, _)).WillByDefault(Return(true));
    }

    void TearDown() {}

  private:
    HealthInterfaceMock mockFixture;
    BatteryDefender defender;
};

static void enableDefender(void) {
    ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStart, _, _, _)).WillByDefault(Return(0));
    ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillByDefault(Return(100));
    ON_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillByDefault(Return(false));

    ON_CALL(*mock, GetBoolProperty(kPropBatteryDefenderCtrlEnable, _)).WillByDefault(Return(true));
}

static void usbPresent(void) {
    ON_CALL(*mock, ReadFileToString(kPathWiredChargerPresent, _, _))
            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
}

static void wirelessPresent(void) {
    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerPresent, _, _))
            .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true)));
}

static void wirelessNotPresent(void) {
    ON_CALL(*mock, ReadFileToString(kPathWirelessChargerPresent, _, _))
            .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true)));
}

static void powerAvailable(void) {
    wirelessPresent();
    usbPresent();
}

static void defaultThresholds(void) {
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));

    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));

    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
            .WillByDefault(Return(70));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
            .WillByDefault(Return(80));

    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlTriggerSOC, _, _, _))
            .WillByDefault(Return(100));
}

static void capacityReached(void) {
    props.batteryLevel = 100;
}

static void initTo1000sConnectedCapacityReached(void) {
    ON_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
            .WillByDefault(DoAll(SetArgPointee<1>(std::to_string(1000)), Return(true)));
}

static void initToActive(void) {
    ON_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
            .WillByDefault(
                    DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1)),
                          Return(true)));
}

TEST_F(BatteryDefenderTest, EnableAndDisconnected) {
    enableDefender();
    // No power

    InSequence s;

    // Enable Battery Defender
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, DisableNonDefaultLevels) {
    InSequence s;

    // Enable Battery Defender
    EXPECT_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStart, _, _, _)).WillOnce(Return(30));
    EXPECT_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillOnce(Return(35));

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, DisableExplicit) {
    InSequence s;

    // Enable Battery Defender
    EXPECT_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillOnce(Return(true));

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, InitActive) {
    enableDefender();
    powerAvailable();
    defaultThresholds();

    InSequence s;

    EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1)),
                            Return(true)));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, InitConnectedCapacityReached) {
    enableDefender();
    powerAvailable();
    defaultThresholds();

    InSequence s;

    int time_expected = DEFAULT_TIME_TO_ACTIVATE_SECONDS - 1;
    EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(time_expected)), Return(true)));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    time_expected += MIN_TIME_BETWEEN_FILE_UPDATES;
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(time_expected),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, InitConnected) {
    enableDefender();
    powerAvailable();
    defaultThresholds();

    InSequence s;

    EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _))
            .WillOnce(DoAll(SetArgPointee<1>(std::to_string(0)), Return(true)));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    // mHasReachedHighCapacityLevel shall be false
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    // Would be active if mHasReachedHighCapacityLevel was true
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, TriggerTime) {
    enableDefender();
    powerAvailable();
    defaultThresholds();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    // Reached 100% capacity at least once
    capacityReached();
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS +
                                                        MIN_TIME_BETWEEN_FILE_UPDATES),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ChargeLevels) {
    enableDefender();
    powerAvailable();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    // No expectations needed; default values already set
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += 0;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ActiveTime) {
    enableDefender();
    powerAvailable();
    defaultThresholds();
    initToActive();

    InSequence s;

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ActiveTime_NonDefaultLevels) {
    enableDefender();
    powerAvailable();
    initToActive();
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));

    // Non-default
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
            .WillByDefault(Return(50));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
            .WillByDefault(Return(60));

    InSequence s;

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(50), kPathStartLevel, _));
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStopLevel, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ActiveTime_NonDefaultLevels_invalid) {
    enableDefender();
    powerAvailable();
    initToActive();
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_CLEAR_SECONDS));

    // Non-default
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStartSOC, _, _, _))
            .WillByDefault(Return(30));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlStopSOC, _, _, _))
            .WillByDefault(Return(10));

    InSequence s;

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStartLevel, _));
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(80), kPathStopLevel, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ConnectDisconnectCycle) {
    enableDefender();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    // Power ON
    wirelessPresent();

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000), kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000 + MIN_TIME_BETWEEN_FILE_UPDATES),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    // Power OFF
    wirelessNotPresent();

    // Maintain kPathPersistChargerPresentTime = 1000 + MIN_TIME_BETWEEN_FILE_UPDATES
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    // Maintain kPathPersistChargerPresentTime = 1000 + MIN_TIME_BETWEEN_FILE_UPDATES
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += DEFAULT_TIME_TO_CLEAR_SECONDS - MIN_TIME_BETWEEN_FILE_UPDATES - 1;
    battDefender->update(&props);

    testvar_systemTimeSecs += 1;
    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(0), kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    // Power ON
    wirelessPresent();

    // Maintain kPathPersistChargerPresentTime = 0
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    capacityReached();
    // Maintain kPathPersistChargerPresentTime = 0
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(MIN_TIME_BETWEEN_FILE_UPDATES),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, ConnectDisconnectResumeTimeThreshold) {
    enableDefender();
    initTo1000sConnectedCapacityReached();
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlActivateTime, _, _, _))
            .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS));

    // Non-default thresholds
    ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderCtrlResumeTime, _, _, _))
            .WillByDefault(Return(0));

    InSequence s;

    // Power ON
    wirelessPresent();

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000), kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000 + MIN_TIME_BETWEEN_FILE_UPDATES),
                                         kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);

    // Power OFF
    wirelessNotPresent();

    EXPECT_CALL(*mock, WriteStringToFile(std::to_string(0), kPathPersistChargerPresentTime, _));
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
    testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES;
    battDefender->update(&props);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitActive_allOnlineFalse) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initToActive();

    InSequence s;

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitActive_usbOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initToActive();

    InSequence s;

    props.chargerAcOnline = false;
    props.chargerUsbOnline = true;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitActive_acOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initToActive();

    InSequence s;

    props.chargerAcOnline = true;
    props.chargerUsbOnline = false;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, false);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, false);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitActive_allOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initToActive();

    InSequence s;

    props.chargerAcOnline = true;
    props.chargerUsbOnline = true;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_allOnlineFalse) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_usbOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = true;
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, false);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_acOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    props.chargerAcOnline = true;
    props.chargerUsbOnline = false;
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, false);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, false);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_allOnline) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);

    props.chargerAcOnline = true;
    props.chargerUsbOnline = true;
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")).Times(2);
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_overrideHealth) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    props.batteryHealth = android::BATTERY_HEALTH_UNKNOWN;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED"));
    battDefender->update(&props);
    ASSERT_EQ(props.batteryHealth, android::BATTERY_HEALTH_UNKNOWN);

    props.batteryHealth = android::BATTERY_HEALTH_UNKNOWN;
    testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1;
    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE"));
    battDefender->update(&props);
    ASSERT_EQ(props.batteryHealth, android::BATTERY_HEALTH_OVERHEAT);
}

TEST_F(BatteryDefenderTest, PropsOverride_InitConnected_kernelDefend) {
    enableDefender();
    usbPresent();
    defaultThresholds();
    initTo1000sConnectedCapacityReached();

    InSequence s;

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")).Times(3);
    battDefender->update(&props);

    props.chargerAcOnline = true;
    props.chargerUsbOnline = true;
    props.batteryHealth = android::BATTERY_HEALTH_OVERHEAT;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);

    props.chargerAcOnline = false;
    props.chargerUsbOnline = false;
    battDefender->update(&props);
    ASSERT_EQ(props.chargerAcOnline, true);
    ASSERT_EQ(props.chargerUsbOnline, true);
}

TEST_F(BatteryDefenderTest, WirelessPathUnsupported) {
    enableDefender();
    wirelessPresent();
    defaultThresholds();

    InSequence s;

    battDefender->setWirelessNotSupported();

    EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED"));
    battDefender->update(&props);
}

}  // namespace health
}  // namespace pixel
}  // namespace google
}  // namespace hardware
