-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local log = require 'mc.logging'

TestPmbus = {}

local psu_slot = {
    ['SlotNumber'] = 1,
    ['PsuChip'] = {
        ['bmc.kepler.Chip.BlockIO'] = {}
    }
}

function TestPmbus:test_status_input()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩
    pmbus.get_status_input = function()
        return 0x90
    end
    pmbus.get_status_temperature = function()
        return 0x00
    end
    pmbus.get_status_fans = function()
        return 0x00
    end
    pmbus.get_status_vout = function()
        return 0x00
    end
    pmbus.get_status_iout = function()
        return 0x00
    end

    local health_event = pmbus:get_health_event()
    lu.assertEquals(0x10, health_event.event)
    lu.assertEquals(1, pmbus:check_input_loss(health_event.event))
end

function TestPmbus:test_status_temperature()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩
    pmbus.get_status_input = function()
        return 0x00
    end
    pmbus.get_status_temperature = function()
        return 0xf0
    end
    pmbus.get_status_fans = function()
        return 0x00
    end
    pmbus.get_status_vout = function()
        return 0x00
    end
    pmbus.get_status_iout = function()
        return 0x00
    end

    local health_event = pmbus:get_health_event()
    lu.assertEquals(health_event.event, 0x08)
    lu.assertEquals(pmbus:check_input_loss(health_event.event), 0)
    lu.assertEquals(health_event.temper_fault, 0xf0)
end

function TestPmbus:test_status_fans()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩
    pmbus.get_status_input = function()
        return 0x00
    end
    pmbus.get_status_temperature = function()
        return 0x00
    end
    pmbus.get_status_fans = function()
        return 0xc0
    end
    pmbus.get_status_vout = function()
        return 0x00
    end
    pmbus.get_status_iout = function()
        return 0x00
    end

    local health_event = pmbus:get_health_event()
    lu.assertEquals(health_event.event, 0xc0)
    lu.assertEquals(pmbus:check_input_loss(health_event.event), 0)
end

function TestPmbus:test_status_output()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩
    pmbus.get_status_input = function()
        return 0x00
    end
    pmbus.get_status_temperature = function()
        return 0x00
    end
    pmbus.get_status_fans = function()
        return 0x00
    end
    pmbus.get_status_vout = function()
        return 0xa0
    end
    pmbus.get_status_iout = function()
        return 0x80
    end

    local health_event = pmbus:get_health_event()
    lu.assertEquals(health_event.output_voltage_fault, 0xa0)
    lu.assertEquals(health_event.output_current_fault, 0x80)
    lu.assertEquals(pmbus:check_input_loss(health_event.event), 0)
end

function TestPmbus:test_update_mfr_specific_status_success()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    pmbus.get_specific = function()
        return 0x5a
    end
    pmbus:update_mfr_specific_status()
    lu.assertEquals(pmbus.health_event.mfr_specific_status, 0x5a)
end

function TestPmbus:test_update_mfr_specific_status_failed()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    pmbus.get_specific = function()
        error('chip read failed')
    end
    pmbus:update_mfr_specific_status()
    lu.assertEquals(pmbus.health_event.mfr_specific_status, 255)
end

function TestPmbus:test_check_input_loss()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    lu.assertEquals(pmbus:check_input_loss(0x00), 0)
    lu.assertEquals(pmbus:check_input_loss(0x10), 1)
end

function TestPmbus:test_get_normal_and_redundancy_supported()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)
    -- 打桩
    pmbus.chip_read = function()
        return string.pack('H', 0xce)
    end
    lu.assertEquals(pmbus:get_normal_and_redundancy_supported(), false)
end


function TestPmbus:test_get_work_mode_Enabled()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)
    -- 打桩
    pmbus.chip_read = function()
        return string.pack('H', 0x00)
    end
    local work_mode = pmbus:get_work_mode()
    lu.assertEquals(work_mode, 'Enabled')
end

function TestPmbus:test_get_work_mode_StandbySpare()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)
    -- 打桩
    pmbus.chip_read = function()
        return string.pack('H', 0x80)
    end
    local work_mode = pmbus:get_work_mode()
    lu.assertEquals(work_mode, 'StandbySpare')
end

function TestPmbus:test_get_sleep_mode()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩
    pmbus.chip_read = function()
        return string.pack('H', 0x800)
    end
    local work_mode = pmbus:get_sleep_mode()
    lu.assertEquals(work_mode, 'DeepSleep')
end

function TestPmbus:test_get_soft_version_with_return_nil()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)

    -- 打桩 utils，避免访问真实 frequency_limit_log
    pmbus.utils = {
        frequency_limit_log = function(...) end
    }

    lu.assertEquals(pmbus:get_soft_version(nil), nil)
end

function TestPmbus:test_get_line_input_voltage_type()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)
    -- 打桩
    pmbus.get_line_input_voltage_type = function()
        return "ACandDCWideRange"
    end
    lu.assertEquals(pmbus:get_line_input_voltage_type(), 'ACandDCWideRange')
end

function TestPmbus:test_get_direct_data()
    local pmbus = require 'device_tree.adapters.power_mgmt.protocol.pmbus'.new(psu_slot)
    -- 打桩
    pmbus.chip_wordread = function()
        return 0x0010
    end

    lu.assertEquals(pmbus:get_direct(40, 0xfe, 0xfff8, 0x8b), 40.2)
    lu.assertEquals(pmbus:get_direct(0, 0xfe, 0xfff8, 0x8b), nil)
end
