-- 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 smc_interace = require 'mcu.upgrade.smc_interface'
local cmn = require 'common'
local MCU_ENUMS = require 'mcu.enum.mcu_enums'

TestSmcInterface = {}

local INSYNC <const> = 2    -- 待升级MCU暂不能升级，有可能是在同步主备分区,返回2
local FAIL <const> = 3       -- MCU升级失败,返回3
local SUCCESS<const> = 0     -- MCU升级成功，返回0

local function stub_query_upgrade_status(state)
    smc_interace.query_upgrade_status = function ()
        return state
    end
end

-- 测试查询传输结果失败
function TestSmcInterface:test_get_next_frame_offset_not_support()
    stub_query_upgrade_status(INSYNC)
    local offset = 0
    local retrans = {retry_times = 0, last_2k_pos = 0, total_times = 0}
    local support_query = false
    local params_list = {delay = 1, subsection_size = 2304, smc_data_len = 96}
    _, retrans = smc_interace:get_next_frame_offset(offset, retrans, support_query, params_list)
    lu.assertEquals(retrans['retry_times'], 0)
end

local function stub_get_next_frame_offset_from_mcu()
    smc_interace.get_next_frame_offset_from_mcu = function (_, offset, retrans, _, _)
        return offset, retrans
    end
end

-- 测试发送数据成功
function TestSmcInterface:test_get_next_frame_offset_ok()
    stub_query_upgrade_status(INSYNC)
    stub_get_next_frame_offset_from_mcu()
    local offset = 0
    local retrans = {retry_times = 0, last_2k_pos = 0, total_times = 0}
    local support_query = true
    local params_list = {delay = 1, subsection_size = 2304, smc_data_len = 96}
    _, retrans = smc_interace:get_next_frame_offset(offset, retrans, support_query, params_list)
    lu.assertEquals(retrans['retry_times'], 0)
end

-- 测试发送数据失败
function TestSmcInterface:test_get_next_frame_offset_failed()
    cmn.skynet.sleep = function() end
    stub_query_upgrade_status(FAIL)
    local offset = 0
    local retrans = {retry_times = 0, last_2k_pos = 0, total_times = 0}
    local support_query = true
    local params_list = {delay = 1, subsection_size = 2304, smc_data_len = 96}
    _, retrans = smc_interace:get_next_frame_offset(offset, retrans, support_query, params_list)
    lu.assertEquals(retrans['retry_times'], 0)
end

function TestSmcInterface:test_get_vrd_dump_specification()
    local blkread = smc_interace.blkread
    smc_interace.blkread = function()
        return true, '123'
    end
    local ok, total_len, register_len = pcall(smc_interace.get_vrd_dump_specification, smc_interace)
    lu.assertEquals(ok, true)
    lu.assertEquals(total_len, 12849)
    lu.assertEquals(register_len, 51)
    smc_interace.blkread = blkread
end

function TestSmcInterface:test_get_vrd_dump_data()
    local blkread = smc_interace.blkread
    smc_interace.blkread = function()
        return false
    end
    local g = smc_interace.get_vrd_dump_specification
    smc_interace.get_vrd_dump_specification = function()
        return false, false
    end

    local ok, total_dump_info, total_count= pcall(smc_interace.get_vrd_dump_data, smc_interace)
    lu.assertEquals(ok, true)
    lu.assertEquals(total_dump_info, {})
    lu.assertEquals(total_count, 13)
    smc_interace.blkread = blkread
    smc_interace.get_vrd_dump_specification = g
end

function TestSmcInterface:test_get_vrd_dump_long_data()
    local blkread = smc_interace.blkread
    smc_interace.blkread = function()
        return false
    end
    local g = smc_interace.get_vrd_dump_specification
    smc_interace.get_vrd_dump_specification = function()
        return 546, 21
    end

    local ok, total_dump_info, total_count= pcall(smc_interace.get_vrd_dump_data, smc_interace)
    lu.assertEquals(ok, true)
    lu.assertEquals(total_dump_info, {})
    lu.assertEquals(total_count, 21)
    smc_interace.blkread = blkread
    smc_interace.get_vrd_dump_specification = g
end

-- 测试第一帧传入后状态不为BUSY
function TestSmcInterface:test_send_upgrade_file_not_busy_after_first_frame()
    local test_data = string.rep('B', 200)
    local params_list = {delay = 1, subsection_size = 96, smc_data_len = 96}
    local sub_comp = {Index = 1}
    -- 记录原始函数
    local orig_transfer = smc_interace.transfer_subcomp_upgrade_data
    local orig_next_frame = smc_interace.get_next_frame_offset
    local orig_query_status = smc_interace.query_upgrade_status
    smc_interace.transfer_subcomp_upgrade_data = function(self, file_type, pack_data)
        return true
    end
    smc_interace.get_next_frame_offset = function(self, offset, retrans, support_query, params_list)
        return offset, retrans
    end
    -- query_upgrade_status: 第一次调用返回非BUSY，后续返回BUSY
    local call_count = 0
    smc_interace.query_upgrade_status = function(self)
        call_count = call_count + 1
        if call_count == 1 then
            return MCU_ENUMS.SMC_CALL_STATUS_CODE.SUCCESS -- 非BUSY
        else
            return MCU_ENUMS.SMC_CALL_STATUS_CODE.BUSY
        end
    end

    local ok = smc_interace:send_acu_upgrade_file(sub_comp, test_data, params_list)
    lu.assertEquals(ok, false)
    ok = smc_interace:send_upgrade_file(sub_comp, test_data, params_list)
    lu.assertEquals(ok, true)
    -- 还原被mock的函数
    smc_interace.transfer_subcomp_upgrade_data = orig_transfer
    smc_interace.get_next_frame_offset = orig_next_frame
    smc_interace.query_upgrade_status = orig_query_status
end

function TestSmcInterface:test_query_retimer_upgrade_status()
    local orig_smc_debounce = smc_interace.smc_debounce
    smc_interace.smc_debounce = function(self, cmd, len, times)
        return false
    end
    local ret = smc_interace:query_retimer_upgrade_status()
    lu.assertEquals(ret, nil)
    smc_interace.smc_debounce = function(self, cmd, len, times)
        return {
            byte = function()
                return true
            end
        }
    end
    local ret = smc_interace:query_retimer_upgrade_status()
    lu.assertEquals(ret, true)
    smc_interace.smc_debounce = orig_smc_debounce
end

function TestSmcInterface:test_query_retimer_upgrade_proportion()
    local blkread = smc_interace.blkread
    smc_interace.blkread = function()
        return false
    end
    local ret = smc_interace:query_retimer_upgrade_proportion()
    lu.assertEquals(ret, nil)
    smc_interace.blkread = function()
        return true, {
            byte = function()
                return true
            end
        }
    end
    local ret = smc_interace:query_retimer_upgrade_proportion()
    lu.assertEquals(ret, true)
    smc_interace.blkread = blkread
end

-- 测试发送数据失败
function TestSmcInterface:test_get_retimer_next_frame_offset()
    cmn.skynet.sleep = function() end
    stub_query_upgrade_status(SUCCESS)
    local offset = 0
    local retrans = {retry_times = 0, last_2k_pos = 0, total_times = 0}
    local support_query = true
    local params_list = {delay = 1, subsection_size = 2304, smc_data_len = 96}
    _, retrans = smc_interace:get_next_frame_offset(offset, retrans, support_query, params_list, true)
    lu.assertEquals(retrans['retry_times'], 0)
end