-- 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 ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_socket = require 'ncsi.ncsi_protocol.ncsi_socket'
local ncsi_protocol_intf = require 'ncsi_protocol_intf'
local ncsi_utils = require 'ncsi.ncsi_protocol.ncsi_utils'
local ncsi_aen = require 'ncsi.ncsi_protocol.ncsi_aen'
local ncsi_parameter = require 'ncsi.ncsi_protocol.ncsi_parameter'

-- 测试套件
TestNCSISocket = {}

-- AEN包常量
local AEN_PACKET_TYPE = 0xff
local AEN_PACKET_IID = 0

-- 初始化函数，在每个测试用例前执行
function TestNCSISocket:setUp()
    ncsi_parameter.get_instance():init_ncsi_parameter()

    -- 保存原始函数
    self.original_ncsi_recv_packet = ncsi_protocol_intf.ncsi_recv_packet
    self.original_ncsi_aen_packet_proc = ncsi_aen.ncsi_aen_packet_proc
    self.original_get_ncsi_parameter = ncsi_parameter.get_instance().get_ncsi_parameter

    -- 初始化测试变量
    self.mock_recv_data = ""
    self.recv_call_count = 0
    self.aen_proc_call_count = 0
    self.aen_proc_result = 0
    self.is_aen_packet = false
    self.last_fd = nil
    self.last_aen_data = nil
    self.last_aen_eth_name = nil

    -- 模拟NCSI参数
    self.mock_ncsi_parameter = {current_channel = 0, iid = 1, channel_cnt = 4, recv_buf = ''}
            ncsi_parameter.get_instance().get_ncsi_parameter = function() 
        return self.mock_ncsi_parameter
    end

    -- 模拟接收数据包函数
    ncsi_protocol_intf.ncsi_recv_packet = function(fd)
        self.recv_call_count = self.recv_call_count + 1
        self.last_fd = fd
        return self.mock_recv_data
    end

    -- 模拟AEN处理函数 - 现在返回两个值 (is_aen_pkt, aen_oem_status)
    ncsi_aen.ncsi_aen_packet_proc = function(data, eth_name)
        self.aen_proc_call_count = self.aen_proc_call_count + 1
        self.last_aen_data = data
        self.last_aen_eth_name = eth_name
        return self.is_aen_packet, self.aen_proc_result
    end
end

-- 清理函数，在每个测试用例后执行
function TestNCSISocket:tearDown()
    -- 恢复原始函数
    ncsi_protocol_intf.ncsi_recv_packet = self.original_ncsi_recv_packet
    ncsi_aen.ncsi_aen_packet_proc = self.original_ncsi_aen_packet_proc
            ncsi_parameter.get_instance().get_ncsi_parameter = self.original_get_ncsi_parameter
end

-- 创建模拟数据包的辅助函数
local function create_mock_packet(packet_type, iid, mc_id, package_id, channel_id, payload_data)
    local packet = {
        frame_head = {
            des_addr = '\xff\xff\xff\xff\xff\xff',
            src_addr = '\xA8\x50\x81\xA9\xBF\xE8',
            ether_type = 0x88f8
        },
        packet_head = {
            mc_id = mc_id,
            header_revision = 0x01,
            reserved = 0,
            iid = iid,
            packet_type = packet_type,
            channel_id = channel_id,
            package_id = package_id,
            payload_len_hi = 0,
            payload_len_lo = #payload_data,
            reserved1 = 0,
            reserved2 = 0,
            reserved3 = 0
        },
        payload = payload_data
    }
    return ncsi_utils.ncsi_packet_bs:pack(packet)
end

-- 测试无数据包接收
function TestNCSISocket:test_no_packet_received()
    -- 设置空数据
    self.mock_recv_data = ""

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertNil(new_data)  -- 无数据时应返回nil
    lu.assertEquals(self.recv_call_count, 1)
    lu.assertEquals(self.last_fd, fd)
    lu.assertEquals(self.aen_proc_call_count, 0)  -- 没有数据，不应调用AEN处理
end

-- 测试接收AEN数据包
function TestNCSISocket:test_receive_aen_packet()
    -- 创建AEN数据包
    local aen_payload = string.rep('\x00', 8)  -- 8字节的AEN payload
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)

    -- 设置AEN处理结果
    self.is_aen_packet = true
    self.aen_proc_result = 1

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 1)
    lu.assertNil(new_data)  -- AEN包处理时不返回新数据
    lu.assertEquals(self.recv_call_count, 1)
    lu.assertEquals(self.aen_proc_call_count, 1)
    lu.assertEquals(self.last_aen_eth_name, eth_name)
    lu.assertNotNil(self.last_aen_data)
    lu.assertEquals(self.last_aen_data, self.mock_recv_data)
end

-- 测试接收AEN数据包（返回0）
function TestNCSISocket:test_receive_aen_packet_return_zero()
    -- 创建AEN数据包
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)

    -- 设置AEN处理结果为0
    self.is_aen_packet = true
    self.aen_proc_result = 0

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertNil(new_data)  -- AEN包处理时不返回新数据
    lu.assertEquals(self.aen_proc_call_count, 1)
end

-- 测试接收非AEN数据包（长度小于限制）
function TestNCSISocket:test_receive_normal_packet_short()
    -- 创建普通数据包（非AEN）
    local normal_payload = string.rep('\x00', 100)
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)  -- 应该返回原始数据
    lu.assertEquals(self.aen_proc_call_count, 1)  -- AEN处理函数会被调用来判断是否为AEN包
end

-- 测试接收非AEN数据包（长度超过限制）
function TestNCSISocket:test_receive_normal_packet_long()
    -- 创建长数据包（超过PACKET_ALL_LEN）
    local normal_payload = string.rep('\x00', 2000)  -- 超过1160字节的payload
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(self.aen_proc_call_count, 1)  -- AEN处理函数会被调用来判断是否为AEN包
    -- 验证数据被截断到PACKET_ALL_LEN
    lu.assertEquals(#new_data, ncsi_def.PACKET_ALL_LEN)
    lu.assertEquals(new_data, string.sub(self.mock_recv_data, 1, ncsi_def.PACKET_ALL_LEN))
end

-- 测试接收AEN数据包但MC_ID不匹配
function TestNCSISocket:test_receive_aen_packet_wrong_mc_id()
    -- 创建AEN数据包但MC_ID不匹配
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, 0x99, 0, 1, aen_payload)  -- 错误的MC_ID

    -- 设置为非AEN包（因为MC_ID不匹配）
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)  -- 应该返回原始数据
    lu.assertEquals(self.aen_proc_call_count, 1)  -- AEN处理函数会被调用
end

-- 测试接收AEN数据包但IID不匹配
function TestNCSISocket:test_receive_aen_packet_wrong_iid()
    -- 创建AEN数据包但IID不匹配
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, 0x99, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)  -- 错误的IID

    -- 设置为非AEN包（因为IID不匹配）
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)  -- 应该返回原始数据
    lu.assertEquals(self.aen_proc_call_count, 1)  -- AEN处理函数会被调用
end

-- 测试接收AEN数据包但packet_type不匹配
function TestNCSISocket:test_receive_aen_packet_wrong_type()
    -- 创建非AEN类型数据包
    local payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(0x50, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, payload)  -- 非AEN类型

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)  -- 应该返回原始数据
    lu.assertEquals(self.aen_proc_call_count, 1)  -- AEN处理函数会被调用
end

-- 测试边界条件：fd为0
function TestNCSISocket:test_boundary_fd_zero()
    -- 设置正常数据
    local normal_payload = string.rep('\x00', 50)
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = 0
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)
    lu.assertEquals(self.last_fd, 0)
    lu.assertEquals(self.recv_call_count, 1)
end

-- 测试边界条件：fd为负数
function TestNCSISocket:test_boundary_fd_negative()
    -- 设置正常数据
    local normal_payload = string.rep('\x00', 50)
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = -1
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(new_data, self.mock_recv_data)
    lu.assertEquals(self.last_fd, -1)
    lu.assertEquals(self.recv_call_count, 1)
end

-- 测试空网卡名称
function TestNCSISocket:test_empty_eth_name()
    -- 创建AEN数据包
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)

    -- 设置AEN处理结果
    self.is_aen_packet = true
    self.aen_proc_result = 0

    -- 测试参数
    local fd = 5
    local eth_name = ""  -- 空网卡名称

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertNil(new_data)  -- AEN包处理时不返回新数据
    lu.assertEquals(self.last_aen_eth_name, "")
    lu.assertEquals(self.aen_proc_call_count, 1)
end

-- 测试长网卡名称
function TestNCSISocket:test_long_eth_name()
    -- 创建AEN数据包
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)

    -- 设置AEN处理结果
    self.is_aen_packet = true
    self.aen_proc_result = 1

    -- 测试参数
    local fd = 5
    local eth_name = "very_long_ethernet_interface_name_with_many_characters"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 1)
    lu.assertNil(new_data)  -- AEN包处理时不返回新数据
    lu.assertEquals(self.last_aen_eth_name, eth_name)
    lu.assertEquals(self.aen_proc_call_count, 1)
end

-- 测试连续接收多个数据包
function TestNCSISocket:test_multiple_packets()
    local fd = 5
    local eth_name = "eth0"

    -- 第一次接收：普通数据包
    local normal_payload = string.rep('\x00', 50)
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)
    self.is_aen_packet = false
    local aen_oem_status1, new_data1 = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 第二次接收：AEN数据包
    local aen_payload = string.rep('\x00', 8)
    self.mock_recv_data = create_mock_packet(AEN_PACKET_TYPE, AEN_PACKET_IID, ncsi_def.NCSI_MC_ID, 0, 1, aen_payload)
    self.is_aen_packet = true
    self.aen_proc_result = 1
    local aen_oem_status2, new_data2 = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 第三次接收：无数据
    self.mock_recv_data = ""
    local aen_oem_status3, new_data3 = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status1, 0)  -- 普通包
    lu.assertNotNil(new_data1)
    lu.assertEquals(aen_oem_status2, 1)  -- AEN包返回1
    lu.assertNil(new_data2)  -- AEN包不返回数据
    lu.assertEquals(aen_oem_status3, 0)  -- 无数据
    lu.assertNil(new_data3)
    lu.assertEquals(self.recv_call_count, 3)
    lu.assertEquals(self.aen_proc_call_count, 2)  -- 前两次有数据的调用
end

-- 测试数据包正好等于限制长度
function TestNCSISocket:test_packet_exact_limit_length()
    -- 创建正好等于PACKET_ALL_LEN长度的数据包
    local payload_len = ncsi_def.PACKET_ALL_LEN - 32  -- 减去头部长度
    local normal_payload = string.rep('\x00', payload_len)
    self.mock_recv_data = create_mock_packet(0x50, 1, ncsi_def.NCSI_MC_ID, 0, 1, normal_payload)

    -- 将数据截断到正好PACKET_ALL_LEN长度
    self.mock_recv_data = string.sub(self.mock_recv_data, 1, ncsi_def.PACKET_ALL_LEN)

    -- 设置为非AEN包
    self.is_aen_packet = false

    -- 测试参数
    local fd = 5
    local eth_name = "eth0"

    -- 执行测试
    local aen_oem_status, new_data = ncsi_socket.ncsi_receive_packet(fd, eth_name)

    -- 验证结果
    lu.assertEquals(aen_oem_status, 0)
    lu.assertEquals(#new_data, ncsi_def.PACKET_ALL_LEN)
    lu.assertEquals(new_data, self.mock_recv_data)
end

return TestNCSISocket