-- 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 c_drive = require 'drive.drive_object'
local nvme = require 'nvme.nvme_object'
local sff = require 'nvme.sff_protocol.ssd_form_factor'

TEST_NVME_RAID = {}

function TEST_NVME_RAID:test_update_raid_nvme_info_error()
    -- prepare
    nvme.protocol = common_def.INVALID_U8
    nvme.pcie_nvme_get_protocol_type = function() return common_def.INVALID_U8 end
    ret = nvme:update_raid_nvme_info()
    lu.assertNil(ret)
end

function TEST_NVME_RAID:test_update_raid_nvme_info()
    -- case 1
    local prefunc = nvme.vpd_raid_nvme_mi_get_info
    nvme.protocol = common_def.NVME_VPD_PROTOCOL_NVME_MI
    nvme.vpd_raid_nvme_mi_get_info = function() return { Manufacturer = 'NNN' } end
    info = nvme:update_raid_nvme_info()
    lu.assertEquals(info.Manufacturer, 'NNN')
    nvme.vpd_raid_nvme_mi_get_info = prefunc
    
    -- case 2
    local prefunc2 = sff.vpd_raid_ssd_form_get_info
    nvme.protocol = 100
    nvme.ssd_form_factor = sff
    sff.vpd_raid_ssd_form_get_info = function() return { Manufacturer = 'NNN' } end
    info = nvme:update_raid_nvme_info()
    lu.assertEquals(info.Manufacturer, 'NNN')
    sff.vpd_raid_ssd_form_get_info = prefunc2
end

function TEST_NVME_RAID:test_update_drive_property_by_specific_obj_variants()
    -- case: nil obj -> no error
    ret = c_drive.update_drive_property_by_specific_obj(nil)
    lu.assertNil(ret)

    -- case: obj.update_raid_nvme_info returns nil
    local obj1 = {
        update_raid_nvme_info = function() return nil end
    }
    ret = c_drive.update_drive_property_by_specific_obj(obj1)
    lu.assertNil(ret)

    -- case: returns info with Manufacturer
    local obj2 = {
        update_raid_nvme_info = function()
            return { Manufacturer = 'MYMANU' }
        end
    }
    c_drive.update_drive_property_by_specific_obj(c_drive, obj2)
    lu.assertEquals(c_drive.Manufacturer, 'MYMANU')
end

function TEST_NVME_RAID:test_update_raid_nvme_static_prop()
    local nvme_obj = {
        Manufacturer = common_def.INVALID_STRING,
        Model = common_def.INVALID_STRING,
        vpd_nvme_mi_get_product_info = function(self, item) return nil end
    }
    setmetatable(nvme_obj, { __index = nvme })

    -- case 1: both Manufacturer and Model are INVALID_STRING, vpd_nvme_mi_get_product_info returns valid values
    nvme_obj.Manufacturer = common_def.INVALID_STRING
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj.vpd_nvme_mi_get_product_info = function(self, item)
        if item == common_def.RECORD_ITEM_MANUFACTURER_NAME then
            return 'MyManufacturer'
        elseif item == common_def.RECORD_ITEM_MODEL_NUMBER then
            return 'MyModel123'
        end
        return nil
    end
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'MyManufacturer')
    lu.assertEquals(nvme_obj.Model, 'MyModel123')

    -- case 2: Manufacturer already has value, Model is INVALID_STRING
    nvme_obj.Manufacturer = 'ExistingManufacturer'
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'ExistingManufacturer')
    lu.assertEquals(nvme_obj.Model, 'MyModel123')

    -- case 3: Manufacturer is INVALID_STRING, Model already has value
    nvme_obj.Manufacturer = common_def.INVALID_STRING
    nvme_obj.Model = 'ExistingModel'
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'MyManufacturer')
    lu.assertEquals(nvme_obj.Model, 'ExistingModel')

    -- case 4: vpd_nvme_mi_get_product_info returns nil for Manufacturer
    nvme_obj.Manufacturer = common_def.INVALID_STRING
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj.vpd_nvme_mi_get_product_info = function(self, item)
        if item == common_def.RECORD_ITEM_MANUFACTURER_NAME then
            return nil
        elseif item == common_def.RECORD_ITEM_MODEL_NUMBER then
            return 'MyModel123'
        end
        return nil
    end
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, common_def.INVALID_STRING)
    lu.assertEquals(nvme_obj.Model, 'MyModel123')

    -- case 5: vpd_nvme_mi_get_product_info returns nil for Model
    nvme_obj.Manufacturer = common_def.INVALID_STRING
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj.vpd_nvme_mi_get_product_info = function(self, item)
        if item == common_def.RECORD_ITEM_MANUFACTURER_NAME then
            return 'MyManufacturer'
        elseif item == common_def.RECORD_ITEM_MODEL_NUMBER then
            return nil
        end
        return nil
    end
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'MyManufacturer')
    lu.assertEquals(nvme_obj.Model, common_def.INVALID_STRING)

    -- case 6: Model returns non-string type (number)
    nvme_obj.Manufacturer = common_def.INVALID_STRING
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj.vpd_nvme_mi_get_product_info = function(self, item)
        if item == common_def.RECORD_ITEM_MANUFACTURER_NAME then
            return 'MyManufacturer'
        elseif item == common_def.RECORD_ITEM_MODEL_NUMBER then
            return 12345
        end
        return nil
    end
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'MyManufacturer')
    lu.assertEquals(nvme_obj.Model, common_def.INVALID_STRING)

    -- case 7: Model returns non-string type (table)
    nvme_obj.Model = common_def.INVALID_STRING
    nvme_obj.vpd_nvme_mi_get_product_info = function(self, item)
        if item == common_def.RECORD_ITEM_MODEL_NUMBER then
            return {}
        end
        return nil
    end
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Model, common_def.INVALID_STRING)

    -- case 8: both already have values, should not change
    nvme_obj.Manufacturer = 'ExistingManufacturer'
    nvme_obj.Model = 'ExistingModel'
    nvme_obj:update_raid_nvme_static_prop()
    lu.assertEquals(nvme_obj.Manufacturer, 'ExistingManufacturer')
    lu.assertEquals(nvme_obj.Model, 'ExistingModel')
end

return TEST_NVME_RAID
