-- Copyright (c) 2025 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 parse_hex = require 'independent_vrd.tool.parse_hex'
local utils = require 'mc.utils'
local file_sec = require 'utils.file'

TestParseHex = {}

local function calculate_checksum(bytes)
    local sum = 0
    for _, b in ipairs(bytes) do
        sum = (sum + b) % 256
    end
    return (0x100 - sum) % 0x100
end

local function create_data_record(length, address, record_type, data)
    local high = (address >> 8) & 0xFF
    local low = address & 0xFF
    local bytes = { length, high, low, record_type }
    for _, value in ipairs(data) do
        table.insert(bytes, value)
    end
    local checksum = calculate_checksum(bytes)
    local hex_line = ':'
    for _, value in ipairs(bytes) do
        hex_line = hex_line .. string.format('%02X', value)
    end
    hex_line = hex_line .. string.format('%02X', checksum)
    return hex_line
end

local function create_temp_file(content)
    local path = os.tmpname()
    local file = assert(file_sec.open_s(path, 'w+'))
    file:write(content)
    file:close()
    return path
end

local function remove_temp_file(path)
    if path then
        utils.remove_file(path)
    end
end

function TestParseHex:test_parse_single_record()
    local data_record = create_data_record(0x04, 0x0000, 0x00, { 0xAA, 0xBB, 0xCC, 0xDD })
    local end_record = ':00000001FF'
    local temp_path = create_temp_file(data_record .. '\n' .. end_record)

    local result = parse_hex(temp_path, 1024)

    lu.assertEquals(result.ret, 0)
    lu.assertEquals(result.real_len, 4)
    lu.assertEquals(string.byte(result.buffer, 1), 0xAA)
    lu.assertEquals(string.byte(result.buffer, 2), 0xBB)
    lu.assertEquals(string.byte(result.buffer, 3), 0xCC)
    lu.assertEquals(string.byte(result.buffer, 4), 0xDD)

    remove_temp_file(temp_path)
end

function TestParseHex:test_parse_multiple_records()
    local record_one = create_data_record(0x02, 0x0000, 0x00, { 0x11, 0x22 })
    local record_two = create_data_record(0x02, 0x0002, 0x00, { 0x33, 0x44 })
    local end_record = ':00000001FF'
    local temp_path = create_temp_file(table.concat({ record_one, record_two, end_record }, '\n'))

    local result = parse_hex(temp_path, 1024)

    lu.assertEquals(result.ret, 0)
    lu.assertEquals(result.real_len, 4)
    lu.assertEquals(string.byte(result.buffer, 1), 0x11)
    lu.assertEquals(string.byte(result.buffer, 2), 0x22)
    lu.assertEquals(string.byte(result.buffer, 3), 0x33)
    lu.assertEquals(string.byte(result.buffer, 4), 0x44)

    remove_temp_file(temp_path)
end

function TestParseHex:test_parse_checksum_error()
    local record = create_data_record(0x02, 0x0000, 0x00, { 0x01, 0x02 })
    record = record:sub(1, -3) .. '00'
    local end_record = ':00000001FF'
    local temp_path = create_temp_file(record .. '\n' .. end_record)

    local result = parse_hex(temp_path, 1024)

    lu.assertEquals(result.ret, -1)

    remove_temp_file(temp_path)
end

function TestParseHex:test_fp_read_single_byte()
    local data_record = create_data_record(0x01, 0x0000, 0x00, { 0x41 })
    local end_record = ':00000001FF'
    local temp_path = create_temp_file(data_record .. '\n' .. end_record)

    local fp = assert(file_sec.open_s(temp_path, 'rb'))
    lu.assertEquals(fp:read(1), ':')
    lu.assertNotNil(fp:read(1))
    fp:close()

    local result = parse_hex(temp_path, 1024)
    lu.assertEquals(result.ret, 0)
    lu.assertEquals(result.real_len, 1)
    lu.assertEquals(string.byte(result.buffer, 1), 0x41)

    remove_temp_file(temp_path)
end

function TestParseHex:test_parse_buffer_overflow()
    local valid_record = create_data_record(0x02, 0x0000, 0x00, { 0x11, 0x22 })
    local overflow_record = create_data_record(0x01, 0x0010, 0x00, { 0xAB })
    local end_record = ':00000001FF'
    local temp_path = create_temp_file(table.concat({ valid_record, overflow_record, end_record }, '\n'))

    local result = parse_hex(temp_path, 8)

    lu.assertEquals(result.ret, -1)

    remove_temp_file(temp_path)
end