-- 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 enums = require 'macros.power_mgmt_enums'

local MAX_BLACK_BOX_RECORD_NUM <const> = 30
local ONE_BLACK_BOX_RECORD_LEN <const> = 120

TestCanbusTPSUMonitor = {}

-- 获取黑匣子数据无效
function TestCanbusTPSUMonitor:test_get_black_box_data_case_1()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    -- 打桩黑匣子数据无效
    canbus_tpsu_monitor.protocol = {
        get_event_log = function ()
            return MAX_BLACK_BOX_RECORD_NUM * ONE_BLACK_BOX_RECORD_LEN,
                string.rep("\xFF", MAX_BLACK_BOX_RECORD_NUM * ONE_BLACK_BOX_RECORD_LEN)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:get_black_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 0)
end

-- 获取黑匣子数据有效
function TestCanbusTPSUMonitor:test_get_black_box_data_case_2()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    -- 打桩两条有效的黑匣子数据
    local valid_black_box_record1 = "\x01\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    local valid_black_box_record2 = "\x02\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    canbus_tpsu_monitor.protocol = {
        get_event_log = function ()
            return MAX_BLACK_BOX_RECORD_NUM * ONE_BLACK_BOX_RECORD_LEN, valid_black_box_record1 ..
                valid_black_box_record2 .. string.rep("\xFF", ONE_BLACK_BOX_RECORD_LEN * 28)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:get_black_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event_time, 1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].black_box_data, valid_black_box_record1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event_time, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event, 1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].black_box_data, valid_black_box_record2)
end

local mock_black_box_data1 = {
    {
        event_time = 2,
        event = 2,
        black_box_data = "\x02\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    },
    {
        event_time = 2,
        event = 1,
        black_box_data = "\x02\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    },
    {
        event_time = 1,
        event = 2,
        black_box_data = "\x01\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    },
    {
        event_time = 1,
        event = 1,
        black_box_data = "\x01\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    }
}

-- 黑匣子数据未满，成功刷新黑匣子数据
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_1()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data1
    local black_box_record4 = "\x04\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    local black_box_record3 = "\x03\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 0 then
                return black_box_record4
            end
            if idx == 1 then
                return black_box_record3
            end
            if idx == 5 then
                return "\x01\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 6)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event_time, 4)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].black_box_data, black_box_record4)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event_time, 3)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event, 1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].black_box_data, black_box_record3)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[3].event_time, mock_black_box_data1[1].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[3].event, mock_black_box_data1[1].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[4].event_time, mock_black_box_data1[2].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[4].event, mock_black_box_data1[2].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[5].event_time, mock_black_box_data1[3].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[5].event, mock_black_box_data1[3].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[6].event_time, mock_black_box_data1[4].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[6].event, mock_black_box_data1[4].event)
end

-- 黑匣子数据未满，刷新黑匣子数据失败
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_2()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data1
    -- 打桩黑匣子无效数据
    local black_box_record4 = string.rep("\xFF", 120)
    local black_box_record3 = string.rep("\xFF", 120)
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 0 then
                return black_box_record4
            end
            if idx == 1 then
                return black_box_record3
            end
            if idx == 5 then
                return "\x01\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 4)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event_time, mock_black_box_data1[1].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event, mock_black_box_data1[1].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event_time, mock_black_box_data1[2].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event, mock_black_box_data1[2].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[3].event_time, mock_black_box_data1[3].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[3].event, mock_black_box_data1[3].event)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[4].event_time, mock_black_box_data1[4].event_time)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[4].event, mock_black_box_data1[4].event)
end

local mock_black_box_data2 = {}

for i = 30, 1, -1 do
    table.insert(mock_black_box_data2, {
        event_time = i,
        event = i,
        black_box_data = string.char(i) .. "\x00\x00\x00" .. string.char(i) .. string.rep("\x00", 7) ..
            string.rep("\xFF", 108)
    })
end

-- 黑匣子数据满，成功刷新黑匣子数据
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_3()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data2
    local black_box_record32 = "\x20\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    local black_box_record31 = "\x1F\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 0 then
                return black_box_record32
            end
            if idx == 1 then
                return black_box_record31
            end
            if idx == 29 then
                return mock_black_box_data2[28].black_box_data
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 30)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event_time, 32)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].black_box_data, black_box_record32)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event_time, 31)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event, 1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].black_box_data, black_box_record31)
    for i = 1, 28, 1 do
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i + 2].event_time, mock_black_box_data2[i].event_time)
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i + 2].event, mock_black_box_data2[i].event)
    end
end

-- 黑匣子数据满，刷新黑匣子数据失败
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_4()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data2
    local black_box_record32 = string.rep("\xFF", 120)
    local black_box_record31 = string.rep("\xFF", 120)
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 0 then
                return black_box_record32
            end
            if idx == 1 then
                return black_box_record31
            end
            if idx == 29 then
                return mock_black_box_data2[28].black_box_data
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 30)
    for i = 1, 30, 1 do
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i].event_time, mock_black_box_data2[i].event_time)
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i].event, mock_black_box_data2[i].event)
    end
end

local mock_black_box_data3 = {}

for i = 28, 1, -1 do
    table.insert(mock_black_box_data3, {
        event_time = i,
        event = i,
        black_box_data = string.char(i) .. "\x00\x00\x00" .. string.char(i) .. string.rep("\x00", 7) ..
            string.rep("\xFF", 108)
    })
end

-- 黑匣子数据未满，刷新黑匣子数据后刚好满
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_5()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data3
    local black_box_record30 = "\x1E\x00\x00\x00" .. "\02" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    local black_box_record29 = "\x1D\x00\x00\x00" .. "\01" .. string.rep("\x00", 7) .. string.rep("\xFF", 108)
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 0 then
                return black_box_record30
            end
            if idx == 1 then
                return black_box_record29
            end
            if idx == 29 then
                return mock_black_box_data3[28].black_box_data
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 30)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event_time, 30)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].event, 2)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[1].black_box_data, black_box_record30)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event_time, 29)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].event, 1)
    lu.assertEquals(canbus_tpsu_monitor.black_box_data[2].black_box_data, black_box_record29)
    for i = 1, 28, 1 do
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i + 2].event_time, mock_black_box_data3[i].event_time)
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i + 2].event, mock_black_box_data3[i].event)
    end
end

-- 黑匣子无变更，刷新黑匣子数据
function TestCanbusTPSUMonitor:test_refresh_blask_box_data_case_6()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data3
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 28 then
                return mock_black_box_data3[28].black_box_data
            end
            return string.rep("\xFF", 120)
        end
    }
    local ok, _ = pcall(function (...)
        canbus_tpsu_monitor:refresh_blask_box_data()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(#canbus_tpsu_monitor.black_box_data, 28)
    for i = 1, 28, 1 do
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i].event_time, mock_black_box_data3[i].event_time)
        lu.assertEquals(canbus_tpsu_monitor.black_box_data[i].event, mock_black_box_data3[i].event)
    end
end

function TestCanbusTPSUMonitor:test_get_event_log()
    local canbus_tpsu_monitor = require 'device_tree.adapters.power_mgmt.protocol.monitor.canbus_tpsu'({})
    canbus_tpsu_monitor.black_box_data = mock_black_box_data3
    canbus_tpsu_monitor.protocol = {
        get_black_box_data = function (_, idx)
            if idx == 28 then
                return mock_black_box_data3[28].black_box_data
            end
            return string.rep("\xFF", 120)
        end,
        protocol = {
            CANBUS_BLACK_BOX_MAX_LEN = 3600
        }
    }
    local ok, len, rsp = pcall(function (...)
        return canbus_tpsu_monitor:get_event_log()
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(len, 3600)
    lu.assertEquals(#rsp, 3600)
    lu.assertEquals(rsp:sub(3361, 3600), string.rep("\xFF", 240))
end