-- 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 bios_app = require 'bios_app'
local bios_factory = require 'factory.bios_factory'
local alarm_manager = require 'domain.alarm.alarm_manager'
local fructl_handler = require 'infrastructure.fructl'
local flash = require 'libmgmt_protocol.bios.domain.pfr.flash'
local defs = require 'libmgmt_protocol.bios.domain.pfr.defs'
local gold_package = require 'domain.bios_firmware.gold.gold_package'
local client = require 'bios.client'
local lu = require 'luaunit'
local _, mtd_api = pcall(require, 'mtd.drv')

local SECURE_BOOT_PATH<const>   = '/bmc/kepler/Managers/1/SecureBoot'

test_flash = {}

local function construct_format(name, offset, size, type)
    return {
        ['name'] = name,
        ['offset'] = offset,
        ['size'] = size,
        ['type'] = type
    }
end

function test_flash:test_parse_format_data()
    local flash_instance = flash.new()
    local data = flash_instance:parse_format_data('\x01\x00\x00\x00\x56\x56\x56\x56',
        {
            construct_format('Magic', 0, 4, defs.NUM_TYPE),
            construct_format('Tag', 4, 8, defs.STRING_TYPE)
        }
    )
    lu.assertEquals(data.Magic, 1)
    lu.assertEquals(data.Tag, 'VVVV')
end

function test_flash:test_switch_to_bmc()
    local flash_instance = flash.new()
    local ok = pcall(flash_instance.switch_to_bmc, flash_instance)
    lu.assertEquals(ok, false)

    local _, result = pcall(flash_instance.retry_switch_to_bmc, flash_instance)
    lu.assertEquals(result, false)
end

function test_flash:test_switch_to_os()
    local flash_instance = flash.new()
    local ok = pcall(flash_instance.switch_to_os, flash_instance)
    lu.assertEquals(ok, false)

    ok = pcall(flash_instance.retry_switch_to_os, flash_instance)
    lu.assertEquals(ok, true)
end

function test_flash:test_read_from_flash()
    mtd_api.read = function(device_fd, address, length)
        return 'ab', length
    end
    local flash_instance = flash.new()
    flash_instance.device_fd = {}
    local flash_data = flash_instance:read_from_flash({
        Address = 1,
        Length = 2
    })
    lu.assertEquals(flash_data, 'ab')

    flash_data = flash_instance:read({
        Address = 1,
        Length = 2
    })
    lu.assertEquals(flash_data, 'ab')

    flash_data = flash_instance:read_by_type(defs.RegionType.HEADER_DESC)
    lu.assertEquals(flash_data, 'ab')

    flash_data = flash_instance:read_by_type('h')
    lu.assertEquals(flash_data, nil)

    flash_data = flash_instance:read_by_offset(1, 2)
    lu.assertEquals(flash_data, 'ab')
end

function test_flash:test_get_section_info()
    local flash_instance = flash.new()
    local ok = pcall(flash_instance.get_section_info, flash_instance)
    lu.assertEquals(ok, false)

    flash_instance.firmware_desc_info = {}
    flash_instance.firmware_desc_info.FirmwareInfo = '\x01\x01\x01\x00'
    local ok, res = pcall(flash_instance.get_section_info, flash_instance)
    lu.assertEquals(ok, true)
    lu.assertEquals(res.InfoType, 1)
    lu.assertEquals(res.FirmwareNum, 1)
    lu.assertEquals(res.SectionOffset, 1)
end

function test_flash:test_read_firmware_info()
    local flash_instance = flash.new()

    local ok = pcall(flash_instance.read_firmware_info, flash_instance)
    lu.assertEquals(ok, false)

    flash_instance.firmware_section_info ={
        SectionOffset = 1,
        FirmwareNum = 1
    }
    local read = flash_instance.read
    flash_instance.read = function()
        return true
    end
    local ok = pcall(flash_instance.read_firmware_info, flash_instance)
    lu.assertEquals(ok, true)
    flash_instance.read = read
end

function test_flash:test_verify()
    local flash_instance = flash.new()
    local ok = pcall(flash_instance.verify, flash_instance)
    lu.assertEquals(ok, true)
end

function test_flash:test_get_cms_region()
    local flash_instance = flash.new()
    local ok = pcall(flash_instance.get_cms_region, flash_instance)
    lu.assertEquals(ok, false)
end

function test_flash:test_insure_action()
    local ok, _ = pcall(function ()
        bios_app:init_insure_action()
    end)
    lu.assertEquals(ok, true)
    local get_power_status = fructl_handler.get_power_status
    fructl_handler.get_power_status = function ()
        return 'OFF'
    end
    local get_service = bios_factory.get_service
    bios_factory.get_service = function ()
        local obj = {}
        function obj:try_unlock_forever()
            return true
        end
        return obj
    end
    local get_instance = alarm_manager.get_instance
    alarm_manager.get_instance = function ()
        local obj = {}
        function obj:recover()
            return true
        end
        return obj
    end
    ok, _ = pcall(function ()
        bios_app:init_insure_action()
    end)
    fructl_handler.get_power_status = get_power_status
    bios_factory.get_service = get_service
    alarm_manager.get_instance = get_instance
    lu.assertEquals(ok, true)
end

function test_flash:test_set_secure_boot_info()
    local package = gold_package.new(1)
    client.GetSecureBootObjects = function ()
        error('')
    end
    local ok = pcall(function ()
        package:set_secure_boot_info()
    end)
    lu.assertEquals(ok, true)

    package.secure_boot_info = ''
    client.GetSecureBootObjects = function ()
        local objects = {}
        objects[SECURE_BOOT_PATH] = {
            SetBiosSignature = function ()
                error('')
            end
        }
        return objects
    end
    ok = pcall(function ()
        package:set_secure_boot_info()
    end)
    lu.assertEquals(ok, true)
end

function test_flash:test_get_secure_boot_info()
    local package = gold_package.new(1)
    local flash_instance = flash.new()
    flash_instance.get_secure_boot_info = function ()
        return 'abc123'
    end
    local ok = pcall(function ()
        package:get_secure_boot_info(flash_instance)
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(package.secure_boot_info, 'abc123')
end

function test_flash:test_mtd_api()
    local fd = mtd_api.open('/dev/mtd0', 4098)
    lu.assertEquals(fd < 0, true)
    local _, length = mtd_api.read(fd, 0x0, 96)
    lu.assertEquals(length < 0, true)
end