-- 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 drive_collection = require 'drive.drive_collection'
local c_drive = require 'drive.drive_object'
local lu = require 'luaunit'

TestDriveCollection = {}

function TestDriveCollection:test_init()
    local drive_collection_obj = drive_collection.new()
    local ret = pcall(drive_collection_obj.init, drive_collection_obj)
    lu.assertEquals(ret, true)
end

local function stub_collection_fold(drives)
    local orig = c_drive.collection
    c_drive.collection = {
        fold = function(_, cb, acc)
            for key, obj in pairs(drives) do
                acc = cb(acc, obj, key)
            end
            return acc
        end
    }
    return orig
end

function TestDriveCollection:test_get_drives_by_controller_id_empty()
    local orig = stub_collection_fold({})
    local dc = drive_collection.new()
    local result = dc:get_drives_by_controller_id(0)
    lu.assertEquals(result, {})
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drives_by_controller_id_filters_correctly()
    local drives = {
        { Name = 'Disk0', RefControllerId = 0, identify_pd = true, presence = 1 },
        { Name = 'Disk1', RefControllerId = 1, identify_pd = true, presence = 1 },
        { Name = 'Disk2', RefControllerId = 0, identify_pd = false, presence = 1 },
        { Name = 'Disk3', RefControllerId = 0, identify_pd = true, presence = 0 },
        { Name = 'Disk4', RefControllerId = 0, identify_pd = true, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    local result = dc:get_drives_by_controller_id(0)
    table.sort(result)
    lu.assertEquals(result, { 'Disk0', 'Disk4' })
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drives_by_controller_id_identify_pd_nil_included()
    local drives = {
        { Name = 'Disk0', RefControllerId = 0, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    local result = dc:get_drives_by_controller_id(0)
    lu.assertEquals(result, { 'Disk0' })
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drives_by_controller_id_no_match()
    local drives = {
        { Name = 'Disk0', RefControllerId = 1, identify_pd = true, presence = 1 },
        { Name = 'Disk1', RefControllerId = 2, identify_pd = true, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    local result = dc:get_drives_by_controller_id(0)
    lu.assertEquals(result, {})
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drives_by_controller_id_returns_independent_tables()
    local drives = {
        { Name = 'Disk0', RefControllerId = 0, identify_pd = true, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    local r1 = dc:get_drives_by_controller_id(0)
    local r2 = dc:get_drives_by_controller_id(0)
    lu.assertNotIs(r1, r2)
    lu.assertEquals(r1, r2)
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drive_objs_by_controller_id_filters_and_returns_objects()
    local drives = {
        { Name = 'Disk0', RefControllerId = 0, identify_pd = true, presence = 1 },
        { Name = 'Disk1', RefControllerId = 1, identify_pd = true, presence = 1 },
        { Name = 'Disk2', RefControllerId = 0, identify_pd = false, presence = 1 },
        { Name = 'Disk3', RefControllerId = 0, identify_pd = true, presence = 0 },
        { Name = 'Disk4', RefControllerId = 0, identify_pd = true, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    local result = dc:get_drive_objs_by_controller_id(0)
    table.sort(result, function(a, b) return a.Name < b.Name end)
    lu.assertEquals(#result, 2)
    lu.assertEquals(result[1].Name, 'Disk0')
    lu.assertEquals(result[2].Name, 'Disk4')
    c_drive.collection = orig
end

function TestDriveCollection:test_get_drive_objs_by_controller_id_invalid_controller_id_returns_empty()
    local drives = {
        { Name = 'Disk0', RefControllerId = 0, identify_pd = true, presence = 1 },
    }
    local orig = stub_collection_fold(drives)
    local dc = drive_collection.new()
    lu.assertEquals(dc:get_drive_objs_by_controller_id(nil), {})
    lu.assertEquals(dc:get_drive_objs_by_controller_id('0'), {})
    c_drive.collection = orig
end