-- 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 common_def = require('common_def')
local sff = require('nvme.sff_protocol.ssd_form_factor')

TEST_SSD_FORM_FACTOR = {}

--- 构造 67 字节 SSD Form Factor VPD(offset 3 起为 VendorId LE,SN/Model/链路字段对齐 common_def)
local function build_ssd_form_vpd_sample()
    local read_len = common_def.VPD_SSD_FORM_LINK_WIDTH_OFFSET + common_def.VPD_SSD_FORM_LINK_WIDTH_LEN
    -- VendorId 0x144d @ offset 3..4(小端)
    local head = string.rep('\0', common_def.VPD_SSD_FORM_VENDOR_ID_OFFSET) .. '\x4d\x14'
    local sn = '12345678901234567890'
    lu.assertEquals(#sn, common_def.VPD_SSD_FORM_SN_LEN)
    local model40 = ('SAMSUNG MZQLB960HAJR' .. string.rep('\0', common_def.VPD_SSD_FORM_MODEL_NUMBER_LEN)):sub(
        1,
        common_def.VPD_SSD_FORM_MODEL_NUMBER_LEN
    )
    -- LinkSpeed=GEN3(8G) LinkWidth=4 => 8*4=32Gbps => CAPABLE_SPEED 枚举 12
    local tail = string.char(common_def.PCI_EXPRESS_VERSION_GEN_THREE) .. string.char(4)
    local vpd = head .. sn .. model40 .. tail
    lu.assertEquals(#vpd, read_len)
    return vpd, read_len
end

function TEST_SSD_FORM_FACTOR:test_vpd_ssd_form_get_info_single_read_and_parse()
    local vpd, read_len = build_ssd_form_vpd_sample()
    local nread = 0
    local chip = {}
    function chip:Read(ctx, off, len)
        nread = nread + 1
        lu.assertEquals(off, 0)
        lu.assertEquals(len, read_len)
        return vpd
    end

    local inst = sff.new(1, chip)
    local nvme = { NegotiatedSpeedGbs = 7 }
    local info = inst:vpd_ssd_form_get_info(nvme)
    lu.assertEquals(nread, 1)
    lu.assertNotNil(info)
    lu.assertEquals(info.ManufacturerId, common_def.NVME_VPD_VENDOR_ID_FOR_SAMSUNG)
    lu.assertEquals(info.SerialNumber, '12345678901234567890')
    lu.assertEquals(info.Model, 'SAMSUNG MZQLB960HAJR')
    lu.assertEquals(info.NegotiatedSpeedGbs, 7)
    lu.assertEquals(info.CapableSpeedGbs, 12)
    lu.assertNotEquals(info.CapacityMiB, common_def.INVALID_U32)
    lu.assertNil(inst.vpd_raw_data, 'get_info 结束应清除 vpd_raw_data')
end

function TEST_SSD_FORM_FACTOR:test_refresh_vpd_buffer_read_too_short()
    local read_len = common_def.VPD_SSD_FORM_LINK_WIDTH_OFFSET + common_def.VPD_SSD_FORM_LINK_WIDTH_LEN
    local chip = {}
    function chip:Read()
        return string.rep('\0', read_len - 1)
    end
    local inst = sff.new(2, chip)
    inst:refresh_vpd_buffer()
    lu.assertNil(inst.vpd_raw_data)
end

function TEST_SSD_FORM_FACTOR:test_vpd_raid_ssd_form_get_info_single_read()
    local vpd, read_len = build_ssd_form_vpd_sample()
    local nread = 0
    local chip = {}
    function chip:Read(ctx, off, len)
        nread = nread + 1
        lu.assertEquals(off, 0)
        lu.assertEquals(len, read_len)
        return vpd
    end
    local inst = sff.new(3, chip)
    local info = inst:vpd_raid_ssd_form_get_info()
    lu.assertEquals(nread, 1)
    lu.assertNotNil(info)
    lu.assertEquals(info.ManufacturerId, common_def.NVME_VPD_VENDOR_ID_FOR_SAMSUNG)
    lu.assertEquals(info.Model, 'SAMSUNG MZQLB960HAJR')
end

function TEST_SSD_FORM_FACTOR:test_vpd_raid_ssd_form_get_info()
    local prefunc = sff.update_manufacture_id
    local prefunc2 = sff.update_manufacture
    sff.VPDChip = true
    sff.nvme_vpd_info = {
        ManufacturerId = common_def.INVALID_U16,
        Manufacturer = common_def.INVALID_STRING,
    }
    sff.update_manufacture_id = function()
        sff.nvme_vpd_info.ManufacturerId = 1
    end
    sff.update_manufacture = function()
        sff.nvme_vpd_info.Manufacturer = 'NNN'
    end
    local ret = sff.vpd_raid_ssd_form_get_info(sff)
    lu.assertEquals(ret.Manufacturer, 'NNN')
    lu.assertEquals(ret.ManufacturerId, 1)
    sff.update_manufacture_id = prefunc
    sff.update_manufacture = prefunc2
end

function TEST_SSD_FORM_FACTOR:test_vpd_raid_ssd_form_get_info_error()
    sff.VPDChip = false
    local ret = sff.vpd_raid_ssd_form_get_info(sff)
    lu.assertNil(ret)
end

return TEST_SSD_FORM_FACTOR