-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under 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 luaunit = require 'luaunit'
local ncsi_protocol_intf = require 'ncsi_protocol_intf'
local ncsi_utils = require 'ncsi.ncsi_protocol.ncsi_utils'
local ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_init = require 'ncsi.ncsi_protocol.ncsi_init'
local ncsi_package = require 'ncsi.ncsi_protocol.ncsi_package'
local ncsi_clear_state = require 'ncsi.ncsi_protocol.ncsi_clear_state'
local ncsi_version = require 'ncsi.ncsi_protocol.ncsi_version'
local ncsi_capabilities = require 'ncsi.ncsi_protocol.ncsi_capabilities'
local ncsi_mac = require 'ncsi.ncsi_protocol.ncsi_mac'
local ncsi_broadcast_filter = require 'ncsi.ncsi_protocol.ncsi_broadcast_filter'
local ncsi_multicast_filter = require 'ncsi.ncsi_protocol.ncsi_multicast_filter'
local ncsi_vlan_mode = require 'ncsi.ncsi_protocol.ncsi_vlan_mode'
local ncsi_aen = require 'ncsi.ncsi_protocol.ncsi_aen'
local ncsi_channel = require 'ncsi.ncsi_protocol.ncsi_channel'
local ncsi_parameter = require 'ncsi.ncsi_protocol.ncsi_parameter'

TestNCSIInit = {}

-- 常量定义
local NCSI_ENABLED = 1
local NCSI_PACKAGE_MAX_ID = 8
local PACKAGE_SUPPORT = 1
local CHANNEL_SUPPORT = 1
local INTEL_MANUFACTURE_ID = 0x57010000
local BCM_MANUFACTURE_ID = 0x3d110000
local MULEX__MANUFACTURE_ID = 0x6c00000

-- 存储原始函数
local original_functions = {}

-- Mock函数定义
local function mock_send_ncsi_cmd(data, len, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock ncsi_parameter.get_instance().get_ncsi_parameter
local function mock_get_ncsi_parameter()
    return g_ncsi_parameter
end

-- Mock package selection
local function mock_select_package(package_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock package deselection
local function mock_deselect_package(package_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock clear state
local function mock_clear_initial_state(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock version get
local function mock_get_version_id(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock capabilities get
local function mock_get_capabilities(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock channel enable
local function mock_enable_channel(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock MAC filter set
local function mock_set_phy_mac_filter(package_id, channel_id, eth_name, filter_num)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock broadcast filter enable
local function mock_enable_brdcast_filter(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock multicast filter enable
local function mock_enable_multicast_filter(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock VLAN mode disable
local function mock_disable_vlan_req(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

-- Mock AEN enable
local function mock_aen_enable(package_id, channel_id, eth_name)
    return ncsi_def.NCSI_SUCCESS
end

local function mock_cmd_ctrl(_, _, _, _, _)
    return ncsi_def.NCSI_SUCCESS
end

-- Setup and teardown
function TestNCSIInit:setUp()
    ncsi_parameter.get_instance():init_ncsi_parameter()
    -- Store original functions
    original_functions.send_ncsi_cmd = ncsi_protocol_intf.send_ncsi_cmd
    original_functions.get_ncsi_parameter = ncsi_parameter.get_instance().get_ncsi_parameter
    original_functions.select_package = ncsi_package.ncsi_select_package
    original_functions.deselect_package = ncsi_package.ncsi_deselect_package
    original_functions.clear_initial_state = ncsi_clear_state.ncsi_clear_initial_state
    original_functions.get_version_id = ncsi_version.ncsi_get_version_id
    original_functions.get_capabilities = ncsi_capabilities.ncsi_get_capabilities
    original_functions.enable_channel = ncsi_channel.ncsi_enable_channel
    original_functions.set_phy_mac_filter = ncsi_mac.ncsi_set_phy_mac_filter
    original_functions.enable_brdcast_filter = ncsi_broadcast_filter.ncsi_enable_brdcast_filter
    original_functions.ncsi_enable_multicast_filter = ncsi_multicast_filter.ncsi_enable_multicast_filter
    original_functions.disable_vlan_req = ncsi_vlan_mode.ncsi_disable_vlan_req
    original_functions.aen_enable = ncsi_aen.ncsi_aen_enable
    original_functions.ncsi_cmd_ctrl = ncsi_utils.ncsi_cmd_ctrl

    -- Mock all necessary functions
    ncsi_protocol_intf.send_ncsi_cmd = mock_send_ncsi_cmd
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    ncsi_package.ncsi_select_package = mock_select_package
    ncsi_package.ncsi_deselect_package = mock_deselect_package
    ncsi_clear_state.ncsi_clear_initial_state = mock_clear_initial_state
    ncsi_version.ncsi_get_version_id = mock_get_version_id
    ncsi_capabilities.ncsi_get_capabilities = mock_get_capabilities
    ncsi_channel.ncsi_enable_channel = mock_enable_channel
    ncsi_mac.ncsi_set_phy_mac_filter = mock_set_phy_mac_filter
    ncsi_broadcast_filter.ncsi_enable_brdcast_filter = mock_enable_brdcast_filter
    ncsi_multicast_filter.ncsi_enable_multicast_filter = mock_enable_multicast_filter
    ncsi_vlan_mode.ncsi_disable_vlan_req = mock_disable_vlan_req
    ncsi_aen.ncsi_aen_enable = mock_aen_enable
    ncsi_utils.ncsi_cmd_ctrl = mock_cmd_ctrl

    -- Reset ncsi_parameter
    g_ncsi_parameter = {
        package_exist = {},
        channel_exist = {},
        manufacture_id = 0,
        iid = 1,
        channel_cnt = 4,  -- 添加channel_cnt字段，设置为常见的通道数量
        recv_buf = ''     -- 添加recv_buf字段，初始化为空字符串
    }
    for i = 0, NCSI_PACKAGE_MAX_ID - 1 do
        g_ncsi_parameter.package_exist[i] = 0
        g_ncsi_parameter.channel_exist[i] = {}
        for j = 0, 3 do
            g_ncsi_parameter.channel_exist[i][j] = 0
        end
    end
    -- Reset the initialization flag before each test
    ncsi_init.reset_init_flag()
end

function TestNCSIInit:tearDown()
    -- Restore original functions
    ncsi_protocol_intf.send_ncsi_cmd = original_functions.send_ncsi_cmd
    ncsi_parameter.get_instance().get_ncsi_parameter = original_functions.get_ncsi_parameter
    ncsi_package.ncsi_select_package = original_functions.select_package
    ncsi_package.ncsi_deselect_package = original_functions.deselect_package
    ncsi_clear_state.ncsi_clear_initial_state = original_functions.clear_initial_state
    ncsi_version.ncsi_get_version_id = original_functions.get_version_id
    ncsi_capabilities.ncsi_get_capabilities = original_functions.get_capabilities
    ncsi_channel.ncsi_enable_channel = original_functions.enable_channel
    ncsi_mac.ncsi_set_phy_mac_filter = original_functions.set_phy_mac_filter
    ncsi_broadcast_filter.ncsi_enable_brdcast_filter = original_functions.enable_brdcast_filter
    ncsi_multicast_filter.ncsi_enable_multicast_filter = original_functions.ncsi_enable_multicast_filter
    ncsi_vlan_mode.ncsi_disable_vlan_req = original_functions.disable_vlan_req
    ncsi_aen.ncsi_aen_enable = original_functions.aen_enable
end

-- 测试用例：测试NCSI参数初始化
-- 验证iid的初始化和后续调用不会改变iid
function TestNCSIInit:test_parameter_init()
    -- Test successful initialization
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.iid, 1)
    luaunit.assertEquals(package_id, 0)  -- 成功时返回找到的第一个支持的包ID
    
    -- Test that subsequent calls don't change iid
    local ret2, package_id2 = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret2, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.iid, 1)
    luaunit.assertEquals(package_id2, 0)  -- 成功时返回找到的第一个支持的包ID
end

-- 测试用例：测试Intel网卡的配置设置
-- 验证Intel网卡特有的包选择和通道初始化
function TestNCSIInit:test_configuration_setting()
    -- Mock deselect package to test Intel specific behavior
    local deselect_called = false
    ncsi_package.ncsi_deselect_package = function(package_id, eth_name)
        deselect_called = true
        return ncsi_def.NCSI_SUCCESS
    end
    
    -- Test with Intel NIC - need to set manufacture_id after init, but before calling the actual function
    -- This is tricky because ncsi_paramter_init calls init_ncsi_parameter which resets manufacture_id
    -- We need to use a different approach - mock the parameter getter to return Intel ID when accessed
    local original_mock = mock_get_ncsi_parameter
    mock_get_ncsi_parameter = function()
        g_ncsi_parameter.manufacture_id = INTEL_MANUFACTURE_ID
        return g_ncsi_parameter
    end
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.iid, 1)
    luaunit.assertEquals(package_id, 0)  -- 成功时返回找到的第一个支持的包ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)
    luaunit.assertTrue(deselect_called)  -- Intel网卡应该调用deselect_package
    
    -- Restore original mock
    mock_get_ncsi_parameter = original_mock
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    ncsi_package.ncsi_deselect_package = original_functions.deselect_package
end

-- 测试用例：测试Broadcom网卡的通道初始化
-- 验证Broadcom网卡的通道初始化和包支持
function TestNCSIInit:test_initial_channel()
    -- Test channel initialization with BCM NIC
    local original_mock = mock_get_ncsi_parameter
    mock_get_ncsi_parameter = function()
        g_ncsi_parameter.manufacture_id = BCM_MANUFACTURE_ID
        return g_ncsi_parameter
    end
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.iid, 1)
    luaunit.assertEquals(package_id, 0)  -- 成功时返回找到的第一个支持的包ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)
    
    -- Restore original mock
    mock_get_ncsi_parameter = original_mock
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
end

-- 测试用例：测试NCSI禁用状态
-- 验证当NCSI被禁用时，通道和包的状态设置
function TestNCSIInit:test_disabled_state()
    -- Test with NCSI disabled
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", 0)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.iid, 1)
    luaunit.assertEquals(package_id, 0)  -- 成功时返回找到的第一个支持的包ID
    -- Channel should not be enabled
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)
end

-- 测试用例：测试多包场景
-- 验证不同初始package_id值下的包选择行为
function TestNCSIInit:test_multiple_packages()
    -- Test with multiple packages
    local ret, updated_package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)
    luaunit.assertEquals(updated_package_id, 0)  -- 成功时返回找到的第一个支持的包ID

    ret, updated_package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(updated_package_id, 0)  -- 成功时返回找到的第一个支持的包ID
end

-- 测试用例：测试Mulex网卡的配置
-- 验证Mulex网卡的通道初始化和包支持
function TestNCSIInit:test_mulex_configuration()
    local original_mock = mock_get_ncsi_parameter
    mock_get_ncsi_parameter = function()
        g_ncsi_parameter.manufacture_id = MULEX__MANUFACTURE_ID
        return g_ncsi_parameter
    end
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, 0)  -- 成功时返回找到的第一个支持的包ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)
    
    -- Restore original mock
    mock_get_ncsi_parameter = original_mock
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
end

-- 测试用例：测试包选择失败场景
-- 验证当包选择失败时的行为
function TestNCSIInit:test_package_selection_failure()
    -- Mock包选择失败
    ncsi_package.ncsi_select_package = function(package_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, NCSI_PACKAGE_MAX_ID)  -- 失败时返回NCSI_PACKAGE_MAX_ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], 0)  -- 包不应该被标记为支持
    luaunit.assertEquals(g_ncsi_parameter.package_exist[1], 0)  -- 包1也不应该被标记为支持
    
    -- 恢复mock
    ncsi_package.ncsi_select_package = original_functions.select_package
end

-- 测试用例：测试通道初始化失败场景
-- 验证当通道初始化失败时的行为
function TestNCSIInit:test_channel_initialization_failure()
    -- Mock通道初始化失败
    ncsi_clear_state.ncsi_clear_initial_state = function(package_id, channel_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    ncsi_utils.ncsi_cmd_ctrl = function(_, _, _, _, _)
        return ncsi_def.NCSI_FAIL
    end
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, 0)  -- 包选择成功但通道初始化失败，仍返回包ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)  -- 包被标记为支持
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], 0)  -- 通道不应该被标记为支持
    
    -- 恢复mock
    ncsi_clear_state.ncsi_clear_initial_state = original_functions.clear_initial_state
    ncsi_utils.ncsi_cmd_ctrl = original_functions.ncsi_cmd_ctrl
end

-- 测试用例：测试版本获取失败场景
-- 验证当版本获取失败时的行为
function TestNCSIInit:test_version_get_failure()
    -- Mock版本获取失败
    ncsi_version.ncsi_get_version_id = function(package_id, channel_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, NCSI_PACKAGE_MAX_ID)  -- 版本获取失败时返回NCSI_PACKAGE_MAX_ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)  -- 包被标记为支持
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)  -- 通道被标记为支持
    
    -- 恢复mock
    ncsi_version.ncsi_get_version_id = original_functions.get_version_id
end

-- 测试用例：测试能力获取失败场景
-- 验证当能力获取失败时的行为
function TestNCSIInit:test_capabilities_get_failure()
    -- Mock能力获取失败
    ncsi_capabilities.ncsi_get_capabilities = function(package_id, channel_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, NCSI_PACKAGE_MAX_ID)  -- 能力获取失败时返回NCSI_PACKAGE_MAX_ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)  -- 包被标记为支持
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)  -- 通道被标记为支持
    
    -- 恢复mock
    ncsi_capabilities.ncsi_get_capabilities = original_functions.get_capabilities
end

-- 测试用例：测试通道启用失败场景
-- 验证当通道启用失败时的行为
function TestNCSIInit:test_channel_enable_failure()
    -- Mock通道启用失败
    ncsi_channel.ncsi_enable_channel = function(package_id, channel_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, 0) 
    
    -- 恢复mock
    ncsi_channel.ncsi_enable_channel = original_functions.enable_channel
end

-- 测试用例：测试Intel网卡deselect失败场景
-- 验证Intel网卡deselect_package失败时的行为
function TestNCSIInit:test_intel_deselect_failure()
    -- Mock deselect package failure for Intel NIC
    ncsi_package.ncsi_deselect_package = function(package_id, eth_name)
        return ncsi_def.NCSI_FAIL
    end
    
    -- Mock parameter getter to return Intel manufacture ID
    local original_mock = mock_get_ncsi_parameter
    mock_get_ncsi_parameter = function()
        g_ncsi_parameter.manufacture_id = INTEL_MANUFACTURE_ID
        return g_ncsi_parameter
    end
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    
    local ret, package_id = ncsi_init.ncsi_paramter_init(0, "eth0", NCSI_ENABLED)
    luaunit.assertEquals(ret, ncsi_def.NCSI_SUCCESS)
    luaunit.assertEquals(package_id, NCSI_PACKAGE_MAX_ID)  -- Intel deselect失败时正确返回NCSI_PACKAGE_MAX_ID
    luaunit.assertEquals(g_ncsi_parameter.package_exist[0], PACKAGE_SUPPORT)  -- 包被标记为支持
    luaunit.assertEquals(g_ncsi_parameter.channel_exist[0][0], CHANNEL_SUPPORT)  -- 通道被标记为支持
    
    -- Restore original mocks
    mock_get_ncsi_parameter = original_mock
    ncsi_parameter.get_instance().get_ncsi_parameter = mock_get_ncsi_parameter
    ncsi_package.ncsi_deselect_package = original_functions.deselect_package
end

return TestNCSIInit