-- 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 file_service = require 'service.file_service'
local bs_util = require 'util.base_util'
local prop_def = require 'macros.property_def'
local chk_strategy = require 'util.check.check_strategy'
local opt_strategy = require 'util.operator.operation_strategy'
local cfg = require 'pojo.config.basic.configure'
local setting = require 'pojo.config.file.setting'
local registry = require 'pojo.config.file.registry'
local registry_service = require 'service.registry_service'
local bios_service = require 'service.bios_service'
local prop_method_app = require 'macros.property_method_app'
local bios_factory = require 'factory.bios_factory'
local open_db = require 'bios.db'
local project_dir = os.getenv('PROJECT_DIR')

local test_common = require 'test_common.utils'
local bus = test_common.dbus_launch('../.dbus', nil, true)

test_export_bios_config = {}

local function construct_db()
    local ok, datas = pcall(require, 'bios.datas')
    if not ok then
        -- 如果没有datas配置，证明当前组件不需要datas，仅打开数据库
        datas = nil
    end
    local db = open_db(':memory:', datas)
    return db
end

function test_export_bios_config:test_bean()
    local bios_ser = bios_service.get_instance(bus, construct_db())
    bios_ser:add_object({
        get_system_id = function()
            return 1
        end,
        register_mdb_objects = function ()
        end,
        unregister_mdb_objects = function ()
        end,
        PcieCardBDF = '',
        PcieDiskBDF = '',
        OCPCardBDF = '',
        Slot = 1
    })
    bios_factory.register_bean('bios_service', bios_ser)
    assert(bios_ser ~= nil)
end

-- 测试base_util
function test_export_bios_config:test_clone()
    local data = {}
    data['a'] = 1
    local clone_data = bs_util.clone(data)
    assert(clone_data['a'] == 1)

    clone_data['a'] = 2
    assert(clone_data['a'] == 2)
    assert(data['a'] == 1)
end

function test_export_bios_config:test_err_msg()
    local data = bs_util.err_msg(prop_def.E_OK, prop_def.RESPONSE_OK)
    assert(data.ErrCode == prop_def.E_OK)
    assert(data.Data == prop_def.RESPONSE_OK)
end

function test_export_bios_config:test_calc_checksum()
    local data = bs_util.calc_checksum('12345')
    assert(data == 255)
end

local function load_attribute()
    local values = {}
    values[1] = {}
    values[2] = {}
    values[3] = {}
    values[1]['ValueName'] = 'HardDiskDrive'
    values[1]['DisplayName'] = 'Hard Disk Drive'
    values[2]['ValueName'] = 'DVDROMDrive'
    values[2]['DisplayName'] = 'CD/DVD-ROM Drive'
    values[3]['ValueName'] = 'PXE'
    values[3]['DisplayName'] = 'PXE'

    local cfgs = {}
    cfgs['AttributeName'] = 'BootTypeOrder0'
    cfgs['Type'] = 'Enumeration'
    cfgs['DisplayName'] = 'First Boot Device'
    cfgs['HelpText'] = 'BootTypeOrder0'
    cfgs['Value'] = values
    cfgs['CurrentValue'] = nil
    cfgs['ReadOnly'] = false
    cfgs['WriteOnly'] = false
    cfgs['GrayOut'] = false
    cfgs['Hidden'] = false
    cfgs['Immutable'] = false
    cfgs['MaxLength'] = 1
    cfgs['Minlength'] = 0
    cfgs['ScalarIncrement'] = 0
    cfgs['UpperBound'] = 10
    cfgs['LowerBound'] = 0
    cfgs['ValueExpression'] = nil

    return cfg.Attribute.new(cfgs)
end

local function load_dependency()
    local map_from = {}
    map_from[1] = {}
    map_from[1]['MapFromAttribute'] = 'HardDiskDrive'
    map_from[1]['MapFromProperty'] = 'CurrentValue'
    map_from[1]['MapFromCondition'] = 'EQU'
    map_from[1]['MapFromValue'] = 'Disabled'
    map_from[1]['MapTerms'] = 'AND'

    local depend = {}
    depend['MapFrom'] = map_from
    depend['MapToAttribute'] = 'DdrRefreshRate'
    depend['MapToProperty'] = 'Hidden'
    depend['MapToValue'] = true

    local cfgs = {}
    cfgs['Dependency'] = depend
    cfgs['DependencyFor'] = 'DdrRefreshSupport'
    cfgs['Type'] = 'Map'

    return cfg.Dependency.new(cfgs)
end

local function load_menu()
    local menus = {}

    menus['MenuName'] = 'MainMenu'
    menus['DisplayName'] = 'Main'
    menus['DisplayOrder'] = 0
    menus['ReadOnly'] = false
    menus['GrayOut'] = false
    menus['MenuPath'] = './MainMenu'

    return cfg.Menu.new(menus)
end

local function load_setting()
    local cfgs = {}

    cfgs['BootTypeOrder0'] = 'HardDiskDrive'
    cfgs['BootTypeOrder1'] = 'DVDROMDrive'
    cfgs['DdrRefreshSupport'] = 'Enabled'
    cfgs['DdrRefreshRate'] = '32ms'
    cfgs['RankMargin'] = 'Disabled'
    cfgs['RMTPatternLength'] = 1

    return setting.new(cfgs)
end

local function load_registry()
    local cfgs = {}
    local attribute = load_attribute()
    local dependency = load_dependency()
    local menu = load_menu()

    local attr_cfgs = {}
    attr_cfgs[1] = {}
    attr_cfgs[1] = attribute:get_cfgs()

    local dependcy_cfgs = {}
    dependcy_cfgs[1] = {}
    dependcy_cfgs[1] = dependency:get_cfgs()

    local menu_cfgs = {}
    menu_cfgs[1] = {}
    menu_cfgs[1] = menu:get_cfgs()

    cfgs[prop_def.REGRIST_PROP_REGISTRYENTRIES] = {}
    cfgs[prop_def.REGRIST_PROP_REGISTRYENTRIES][prop_def.REGRIST_PROP_ATTRIBUTES] = attr_cfgs
    cfgs[prop_def.REGRIST_PROP_REGISTRYENTRIES][prop_def.REGRIST_PROP_DEPENDENCIES] = dependcy_cfgs
    cfgs[prop_def.REGRIST_PROP_REGISTRYENTRIES][prop_def.REGRIST_PROP_MENUS] = menu_cfgs

    cfgs[prop_def.REGRIST_PROP_REGISTRYVERSIOHN] = 'V2.27'
    cfgs[prop_def.REGRIST_PROP_LANGUAGE] = 'en'

    return registry.new(cfgs)
end

-- 测试util.check
function test_export_bios_config:test_abstract_check_enum()
    local strategy = chk_strategy.get_instance()
    local err_code = strategy:is_config_valid(nil, nil, nil)
    assert(err_code == prop_def.E_FAILURE)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, nil, 1236)
    assert(err_code == prop_def.E_FAILURE)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, 'a', nil)
    assert(err_code == prop_def.E_FAILURE)

    local attr = cfg.Attribute.new()
    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, attr, 1236)
    assert(err_code == prop_def.REGRIST_TYPE_PROP_TYPE_ERROR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, attr, 'abc')
    assert(err_code == prop_def.E_FAILURE)

    attr = load_attribute()
    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, attr, 'abc')
    assert(err_code == prop_def.REGRIST_TYPE_PROP_NOT_LIST)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_ENUM, attr, 'HardDiskDrive')
    assert(err_code == prop_def.E_OK)
end

function test_export_bios_config:test_abstract_check_string()
    local strategy = chk_strategy.get_instance()
    local attr = load_attribute()
    local err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_STRING, attr, 1236)
    assert(err_code == prop_def.REGRIST_TYPE_PROP_TYPE_ERROR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_STRING, attr, '1234')
    assert(err_code == prop_def.REGRIST_TYPE_PROP_LENGTH_ERR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_STRING, attr, '1')
    assert(err_code == prop_def.E_OK)
end

function test_export_bios_config:test_abstract_check_integer()
    local strategy = chk_strategy.get_instance()
    local attr = load_attribute()
    local err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_INTEGER, attr, '1234')
    assert(err_code == prop_def.REGRIST_TYPE_PROP_TYPE_ERROR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_INTEGER, attr, 12)
    assert(err_code == prop_def.REGRIST_TYPE_PROP_NOT_RANGE)

    attr:set_val_by_name('CurrentValue', 1)
    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_INTEGER, attr, 6)
    assert(err_code == prop_def.E_OK)
end

function test_export_bios_config:test_abstract_check_boolean()
    local strategy = chk_strategy.get_instance()
    local attr = load_attribute()
    local err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_BOOLEAN, attr, '1234')
    assert(err_code == prop_def.REGRIST_TYPE_PROP_TYPE_ERROR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_BOOLEAN, attr, false)
    assert(err_code == prop_def.E_OK)
end

function test_export_bios_config:test_abstract_check_password()
    local strategy = chk_strategy.get_instance()
    local attr = load_attribute()
    local err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_PASSWORD, attr, 1234)
    assert(err_code == prop_def.REGRIST_TYPE_PROP_TYPE_ERROR)

    err_code = strategy:is_config_valid(prop_def.REGRIST_PROP_TYPE_PASSWORD, attr, '12334')
    assert(err_code == prop_def.E_OK)
end

function test_export_bios_config:test_abstract_operation()
    local strategy = opt_strategy.get_instance()
    local err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_EQU, nil, 1)
    assert(err_code == false)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_EQU, nil, nil)
    assert(err_code == true)

    err_code = strategy:deal('greater', nil, nil)
    assert(err_code == false)

    -- int类型测试
    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_EQU, 1, 1)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_NEQ, 1, 2)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_GTR, 2, 1)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_GEQ, 1, 1)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_LSS, 1, 2)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_LEQ, 1, 1)
    assert(err_code == true)

    -- boolean测试
    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_EQU, false, false)
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_NEQ, false, true)
    assert(err_code == true)

    -- string测试
    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_EQU, 'aaa', 'aaa')
    assert(err_code == true)

    err_code = strategy:deal(prop_def.REGRIST_PROP_COMPARE_NEQ, 'aa', 'bb')
    assert(err_code == true)
end

-- 测试config
function test_export_bios_config:test_abstract_attribute()
    local attr = load_attribute()
    local cfgs = attr:get_cfgs()
    assert(attr ~= nil)
    assert(cfgs ~= nil)

    local attr_name = attr:get_val_by_name(prop_def.REGRIST_PROP_ATTRIBUTENAME)
    assert(attr_name == 'BootTypeOrder0')

    attr:set_val_by_name(prop_def.REGRIST_PROP_ATTRIBUTENAME, 'BootTypeOrder1')
    attr_name = attr:get_val_by_name(prop_def.REGRIST_PROP_ATTRIBUTENAME)
    assert(attr_name == 'BootTypeOrder1')

    attr:set_cfgs(nil)
    cfgs = attr:get_cfgs()
    assert(cfgs == nil)

    attr:set_val_by_name(prop_def.REGRIST_PROP_ATTRIBUTENAME, 'BootTypeOrder1')
end

function test_export_bios_config:test_configure()
    local depenency = load_dependency()
    assert(depenency ~= nil)

    local map_from_list = depenency:get_map_from_list()
    assert(#map_from_list == 1)

    local map_from = map_from_list[1]
    assert(map_from:get_val_by_name(prop_def.REGRIST_PROP_MAPFORMATTRIBUTE) == 'HardDiskDrive')
    assert(map_from:get_val_by_name(prop_def.REGRIST_PROP_MAPTERMS) == 'AND')

    local menu = cfg.Menu.new(nil)
    assert(menu ~= nil)

    local file_setting = setting.new(nil)
    assert(file_setting ~= nil)

    local cfgs = file_setting:get_cfgs()
    assert(cfgs == nil)
    file_setting:set_attributes(nil)
    local data = file_setting:get_val_by_name('h')
    assert(data == nil)
end

-- 测试registry对象
function test_export_bios_config:test_registry()
    local registry = load_registry()
    assert(registry ~= nil)

    local registery_version = registry:get_registry_version()
    assert(registery_version == 'V2.27')

    local attribute_list = registry:get_attribute_list()
    assert(attribute_list ~= nil)
    local attribute = attribute_list['BootTypeOrder0']
    local attr = attribute:get_val_by_name('DisplayName')
    assert(attr == 'First Boot Device')

    local attribute_boot = registry:get_attibute_val('BootTypeOrder0')
    assert(attribute_boot ~= nil)

    local attribute_boot_type = registry:get_attibute_prop_val('BootTypeOrder0', 'Type')
    assert(attribute_boot_type == 'Enumeration')

    registry:set_attibute_prop_val('BootTypeOrder0', 'Type', 'Enumeration')

    local enum_list = attribute:get_enum_list()
    local enum = enum_list[1]
    local val = enum:get_val_by_name('DisplayName')
    assert(#enum_list == 3)
    assert(val == 'Hard Disk Drive')

    local menu_list = registry:get_menu_list()
    assert(menu_list ~= nil)

    local attr_name = registry:get_attibute_val('DisplayName')
    assert(attr_name ~= 'First Boot Device')

    local setting_obj = load_setting()
    local len = setting_obj:get_val_by_name('RMTPatternLength')
    assert(setting ~= nil)
    assert(len == 1)
end

function test_export_bios_config:test_update_registry()
    local registry_path = project_dir .. '/test/test_data/registry.json'
    local registry_json = bs_util.get_file_json(registry_path)
    local current_path = project_dir .. '/test/test_data/currentvalue.json'
    local current_json = bs_util.get_file_json(current_path)

    local current = setting.new(current_json)
    local registry_ser = registry_service.new(registry_json)
    local resp = registry_ser:update_registry(current)
    local err_code = resp.ErrCode
    local config = resp.Data
    assert(err_code == prop_def.E_OK)
    assert(config == nil)
end

function test_export_bios_config:test_get_file_json()
    local bios_ser = bios_service.get_instance(bus, {})
    bios_ser:set_bios_prop('CurrentValueFileName', project_dir .. '/test/test_data/currentvalue.json')
    bios_ser:set_bios_prop('RegistryFileName', project_dir .. '/test/test_data/registry.json')

    local resp_data = file_service.get_file_json(prop_method_app.BIOS_FILE_REGISTRY_NAME)
    assert(resp_data.ErrCode == prop_def.E_OK)
    assert(resp_data.Data ~= nil)
end

function test_export_bios_config:test_read_config_from_jsonfile()
    local bios_ser = bios_service.get_instance(bus, {})
    bios_ser:set_bios_prop(prop_method_app.BIOS_FILE_SETTING_NAME, project_dir .. '/test/test_data/setting.json')

    local file_ser = file_service.new()

    local resp_data = file_ser:contruct_common_service()
    assert(resp_data.ErrCode == prop_def.E_OK)
    assert(resp_data.Data == nil)

    resp_data = file_ser:contruct_setting_service()
    assert(resp_data.ErrCode == prop_def.E_OK)
    assert(resp_data.Data == nil)
end

function test_export_bios_config:test_check_special_character()
    local res = bs_util.check_special_character(';asas')
    assert(res == true)

    res = bs_util.check_special_character('ahsyhda\n')
    assert(res == true)

    res = bs_util.check_special_character('&&')
    assert(res == true)

    res = bs_util.check_special_character('vfd|sds')
    assert(res == true)

    res = bs_util.check_special_character('xsa12&')
    assert(res == true)

    res = bs_util.check_special_character('>xasjbhi>')
    assert(res == true)

    res = bs_util.check_special_character('<nxjs1')
    assert(res == true)

    res = bs_util.check_special_character('`uyh82')
    assert(res == true)

    res = bs_util.check_special_character('\\\\asda')
    assert(res == true)

    res = bs_util.check_special_character('!jfioje09')
    assert(res == true)

    res = bs_util.check_special_character('asugd78g3rh')
    assert(res == false)

    res = bs_util.check_special_character('../test_data/config1.xml')
    assert(res == false)
end

function test_export_bios_config:test_check_path()
    local res = bs_util.check_path('')
    assert(res == false)

    res = bs_util.check_path()
    assert(res == false)

    res = bs_util.check_path('../test_data/config1.xml')
    assert(res == false)
end

function test_export_bios_config:test_strip_path()
    local file_path = bs_util.strip_file_path('../test_data/1/2/config1.xml')
    assert(file_path == '../test_data/1/2')

    file_path = bs_util.strip_file_path('./test_data/1/2/config1.xml')
    assert(file_path == './test_data/1/2')

    file_path = bs_util.strip_file_path('/test_data/1/2/config1.xml')
    assert(file_path == '/test_data/1/2')

    file_path = bs_util.strip_file_path('/test_data/1/2/config1')
    assert(file_path == nil)

    local file_name = bs_util.strip_file_name('../test_data/1/2/config1.xml')
    assert(file_name == 'config1.xml')

    file_name = bs_util.strip_file_name('./test_data/1/2/config1.xml')
    assert(file_name == 'config1.xml')

    file_name = bs_util.strip_file_name('/test_data/1/2/config1.xml')
    assert(file_name == 'config1.xml')

    file_name = bs_util.strip_file_name('/test_data/1/2/config1')
    assert(file_name == nil)

    local extension_name = bs_util.get_extension_name('/test_data/1/2/config1.xml')
    assert(extension_name == 'xml')

    extension_name = bs_util.get_extension_name('/test_data/1/2/config1.json')
    assert(extension_name == 'json')
end
