-- 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 orig_card_manage = package.loaded['device.class.nic_mgmt.card.card_manage']

-- 先打桩card_manage
local called = false
local fake_card_manage = {
    register_listen_callback = function()
        called = true
    end,
    init_asset_data_info = function() end,
    init_id = function() end,
    update_asset_uuid_info = function() end,
    set_attention_on_bios = function() end,
    update_quater_info = function() end,
    update_port_bdf = function() end,
    update_1822_port_bdf = function() end,
    init_npu_proc = function() end,
}
package.loaded['device.class.nic_mgmt.card.card_manage'] = fake_card_manage

local card_init = require 'device.class.nic_mgmt.card.card_init'

-- 构造一个最小可用的orm_obj模拟对象，next_tick用metatable打桩
local function mock_orm_obj(opts)
    opts = opts or {}
    local obj = {
        NodeId = opts.NodeId or 'test_node',
        path = opts.path or '/mock/path/test_node',
        children = opts.children or {},
        na_object_name = nil,
        HotPluggable = opts.HotPluggable or false,
        Name = opts.Name or 'NIC-1',
        Type = opts.Type or 'TestType',
        SpecialPcieCard = opts.SpecialPcieCard or false,
        PfMacInfo = opts.PfMacInfo or {},
        sleep_ms = function() end,
        ports_count = 0,
        register_mdb_objects = function() obj._register_mdb_called = true end,
        listen = function(self, prop, cb)
            self._listen = self._listen or {}
            self._listen[prop] = cb
        end,
        connect_signal = function(self, event, cb)
            self._connect_signal_called = true
            self._connect_signal_args = {event, cb}
        end,
        tasks = { sleep_ms = function() end },
    }
    -- mock port
    local port = {
        PortID = 1,
        NetDevFuncType = 1,
        mac_change = { on = function() end },
        get_optical_module = function() return { TemperatureCelsius = 0 } end,
        WorkloadType = 1,
        MACAddress = '00:00:00:00:00:01',
        PermanentMACAddress = '00:00:00:00:00:00',
    }
    obj.children[1] = port
    setmetatable(obj, {
        __index = function(t, k)
            if k == "next_tick" then
                return function(self, func, ...)
                    t._next_tick_calls = t._next_tick_calls or {}
                    table.insert(t._next_tick_calls, {func=func, args={...}})
                end
            else
                return rawget(t, k)
            end
        end
    })
    return obj
end

TestCardInit = {}

function TestCardInit:tearDown()
    package.loaded['device.class.nic_mgmt.card.card_manage'] = orig_card_manage
end

function TestCardInit:test_init_should_not_error_and_set_fields()
    called = false
    local orm_obj = mock_orm_obj()
    card_init.init(orm_obj)
    lu.assertEquals(orm_obj.na_object_name, 'test_node')
    lu.assertEquals(orm_obj.ports_count, 1)
    lu.assertTrue(called)
    lu.assertNotNil(orm_obj._next_tick_calls)
    lu.assertTrue(#orm_obj._next_tick_calls > 0)
end

function TestCardInit:test_init_virtual_port_should_return()
    called = false
    local orm_obj = mock_orm_obj{ Type = 6 }
    card_init.init(orm_obj)
    lu.assertEquals(orm_obj.na_object_name, 'test_node')
    lu.assertTrue(called)
    lu.assertNotNil(orm_obj._next_tick_calls)
end

function TestCardInit:test_init_with_multiple_ports()
    called = false
    local port2 = {
        PortID = 2,
        NetDevFuncType = 2,
        mac_change = { on = function() end },
        get_optical_module = function() return { TemperatureCelsius = 0 } end,
        WorkloadType = 1,
        MACAddress = '00:00:00:00:00:02',
        PermanentMACAddress = '00:00:00:00:00:02',
    }
    local orm_obj = mock_orm_obj()
    orm_obj.children[2] = port2
    card_init.init(orm_obj)
    lu.assertEquals(orm_obj.ports_count, 2)
    lu.assertTrue(called)
    lu.assertNotNil(orm_obj._next_tick_calls)
    lu.assertTrue(#orm_obj._next_tick_calls > 0)
end
