blob: 47b19e615b5742d3f7c36075e02c620f3cef4c96 [file]
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::ElementsAre;
#include "utils.hpp"
#include <sdbusplus/bus.hpp>
TEST(ConvertUUIDToString, testGoodConversionToString)
{
std::vector<uint8_t> intUUID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
// convert intUUID to stringUUID
uuid_t stringUUID = utils::convertUUIDToString(intUUID);
EXPECT_STREQ(stringUUID.c_str(), "00010203-0405-0607-0809-0a0b0c0d0e0f\0");
}
TEST(ConvertUUIDToString, testGBadConversionToString)
{
std::vector<uint8_t> intUUID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
// convert intUUID to stringUUID
uuid_t stringUUID = utils::convertUUIDToString(intUUID);
EXPECT_STREQ(stringUUID.c_str(), "");
}
TEST(convertHexToString, testGoodHexConversionToString)
{
std::vector<uint8_t> data{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
// convert HEX to a string
std::string result = utils::convertHexToString(data, data.size());
EXPECT_STREQ(result.c_str(), "0001020304050607\0");
}
TEST(convertHexToString, testBadHexConversionToString)
{
std::vector<uint8_t> data;
// convert HEX to a string
std::string result = utils::convertHexToString(data, data.size());
EXPECT_STREQ(result.c_str(), "");
}
TEST(isValidDbusString, testGoodIsValidDbusString)
{
// test 1 byte
EXPECT_TRUE(utils::isValidDbusString("\x41\x41\x41"));
// test 2 bytes
EXPECT_TRUE(utils::isValidDbusString("\xC3\xA9\xC3\xA9\xC3\xA9"));
// test 3 bytes
EXPECT_TRUE(
utils::isValidDbusString("\xE2\x82\xAC\xE2\x82\xAC\xE2\x82\xAC"));
// test 4 bytes
EXPECT_TRUE(utils::isValidDbusString(
"\xF0\x90\x8D\x88\xF0\x90\x8D\x88\xF0\x90\x8D\x88"));
}
TEST(isValidDbusString, testBadIsValidDbusString)
{
// test 1 byte, it must be <= 0x7f
EXPECT_FALSE(utils::isValidDbusString("\x80"));
// test 2 bytes, the first two bits of the leading byte
// should be 11b
EXPECT_FALSE(utils::isValidDbusString("\xE3\xA9"));
// test 2 bytes, the first two bits of the subsequent byte
// should be 10b
EXPECT_FALSE(utils::isValidDbusString("\xC3\xE9"));
// test 3 bytes, the first three bits of the leading byte
// should be 111b
EXPECT_FALSE(utils::isValidDbusString("\xF2\x82\xAC"));
// test 3 bytes, the first two bits of the subsequent byte
// should be 10b
EXPECT_FALSE(utils::isValidDbusString("\xE2\xF2\xAC"));
// test 4 bytes, the first four bits of the leading byte
// should be 1111b
EXPECT_FALSE(utils::isValidDbusString("\xC0\x90\x8D\x88"));
// test 4 bytes, the first two bits of the subsequent byte
// should be 10b
EXPECT_FALSE(utils::isValidDbusString("\xF0\x90\xFD\x88"));
}
TEST(makeDBusNameValid, Functional)
{
const std::vector<std::array<std::string, 2>> data{
{{"HGX_GPU_SXM 1 DRAM_0_Temp_0", "HGX_GPU_SXM_1_DRAM_0_Temp_0"}},
{{"HGX_GPU_SXM 1 &^* DRAM_0_Temp_0", "HGX_GPU_SXM_1_DRAM_0_Temp_0"}},
{{"/xyz/openbmc_project/inventory/system/processors/GPU_SXM_1",
"/xyz/openbmc_project/inventory/system/processors/GPU_SXM_1"}},
{{"/xyz/openbmc_project/inventory/system/processors/GPU_SXM 1 DRAM_0",
"/xyz/openbmc_project/inventory/system/processors/GPU_SXM_1_DRAM_0"}},
{{"xyz.openbmc_project.Configuration.NSM_Temp",
"xyz.openbmc_project.Configuration.NSM_Temp"}},
{{"xyz.openbmc_project.Sensor.HGX_GPU_SXM 1 DRAM_0_Temp_0",
"xyz.openbmc_project.Sensor.HGX_GPU_SXM_1_DRAM_0_Temp_0"}},
};
for (const auto& e : data)
{
EXPECT_STREQ(utils::makeDBusNameValid(e[0]).c_str(), e[1].c_str());
}
}
TEST(getDeviceNameFromDeviceType, ValidDeviceTypes)
{
EXPECT_EQ(utils::getDeviceNameFromDeviceType(0), "GPU");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(1), "SWITCH");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(2), "BRIDGE");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(3), "BASEBOARD");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(4), "EROT");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(5), "MCTPBRIDGE");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(6), "CPU");
}
TEST(getDeviceNameFromDeviceType, UnknownDeviceType)
{
EXPECT_EQ(utils::getDeviceNameFromDeviceType(7), "NSM_DEV_ID_UNKNOWN");
EXPECT_EQ(utils::getDeviceNameFromDeviceType(255), "NSM_DEV_ID_UNKNOWN");
}
TEST(getDeviceInstanceName, ValidInstances)
{
EXPECT_EQ(utils::getDeviceInstanceName(0, 0), "GPU_0");
EXPECT_EQ(utils::getDeviceInstanceName(1, 1), "SWITCH_1");
EXPECT_EQ(utils::getDeviceInstanceName(2, 2), "BRIDGE_2");
EXPECT_EQ(utils::getDeviceInstanceName(3, 3), "BASEBOARD_3");
EXPECT_EQ(utils::getDeviceInstanceName(4, 4), "EROT_4");
EXPECT_EQ(utils::getDeviceInstanceName(5, 5), "MCTPBRIDGE_5");
EXPECT_EQ(utils::getDeviceInstanceName(6, 6), "CPU_6");
}
TEST(getDeviceInstanceName, UnknownTypeWithValidInstance)
{
EXPECT_EQ(utils::getDeviceInstanceName(7, 0), "NSM_DEV_ID_UNKNOWN_0");
}
TEST(setBit, TestSettingBits)
{
utils::Bitfield256 bitMap{};
EXPECT_TRUE(bitMap.setBit(2));
EXPECT_EQ(bitMap.fields[0].byte, 0b00000000000000000000000000000100);
EXPECT_FALSE(bitMap.setBit(2));
EXPECT_TRUE(bitMap.setBit(33));
EXPECT_EQ(bitMap.fields[0].byte, 0b00000000000000000000000000000100);
EXPECT_EQ(bitMap.fields[1].byte, 0b00000000000000000000000000000010);
}
TEST(getSetBits, TestNoSetBits)
{
utils::Bitfield256 emptyBitField{};
EXPECT_EQ(emptyBitField.getSetBits(), "");
}
TEST(getSetBits, TestSetBits)
{
utils::Bitfield256 bitMap;
bitMap.fields[0].byte = 0b00000000000000000000000000000001;
EXPECT_EQ(bitMap.getSetBits(), "0");
bitMap.fields[0].byte = 0b00000000000000000000000000001101;
EXPECT_EQ(bitMap.getSetBits(), "0, 2, 3");
bitMap.fields[0].byte = 0b00000000000000000000000011110000;
bitMap.fields[2].byte = 0b00000000000000000000000000000001;
EXPECT_EQ(bitMap.getSetBits(), "4, 5, 6, 7, 64");
}
TEST(memFd, TestGoodWriteRead)
{
int fd = memfd_create("test", 0);
std::vector<uint8_t> data{0x01, 0x02, 0x03, 0x04, 0x05};
utils::writeBufferToFd(fd, data);
EXPECT_GT(fd, 0);
std::vector<uint8_t> readData;
utils::readFdToBuffer(fd, readData);
EXPECT_THAT(data, ElementsAre(0x01, 0x02, 0x03, 0x04, 0x05));
}
TEST(memFd, TestGoodWriteReadForEmptyBuffer)
{
int fd = memfd_create("test", 0);
std::vector<uint8_t> data;
utils::writeBufferToFd(fd, data);
EXPECT_GT(fd, 0);
std::vector<uint8_t> readData;
utils::readFdToBuffer(fd, readData);
EXPECT_THAT(data, ElementsAre());
}
TEST(convertMacAddressToString, TestGoodConversionMacAddressToString)
{
std::vector<uint8_t> macAddress{0x01, 0x01, 0x02, 0x03,
0x04, 0x05, 0x00, 0x00};
std::string macAddressString;
macAddressString.resize(sizeof("XX:XX:XX:XX:XX:XX"));
utils::convertMacAddressToString(macAddress.data(), macAddress.size(),
macAddressString);
macAddressString.resize(strlen(macAddressString.c_str()));
EXPECT_EQ(macAddressString, "01:01:02:03:04:05");
}
TEST(convertMacAddressToString, TestBadConversionMacAddressToString)
{
std::vector<uint8_t> macAddress{0x01, 0x01, 0x02, 0x03};
std::string macAddressString;
macAddressString.resize(sizeof("XX:XX:XX:XX:XX:XX"));
utils::convertMacAddressToString(macAddress.data(), macAddress.size(),
macAddressString);
macAddressString.resize(strlen(macAddressString.c_str()));
EXPECT_EQ(macAddressString, "");
}
TEST(convertGuid64ToString, TestGoodConversionGuid64ToString)
{
uint64_t guid = 0x0102030405060708;
std::string guidString;
utils::convertGuid64ToString(guid, guidString);
EXPECT_EQ(guidString, "0102-0304-0506-0708");
}
/*
* Additional tests for uncovered functions in common/utils.cpp
* Generated to improve functional coverage from 57.5% toward 90% target
* Focus: High-value utility functions (MCTP priority, string ops, conversions,
* bitmaps) Functions covered: ~15 of 27 uncovered (most impactful subset)
*/
// ============================================================================
// MCTP Priority Comparison Tests
// ============================================================================
TEST(MctpPriority, testIsPreferredSameMediumDifferentBinding)
{
MctpMedium pcieMedium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding pcieBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
MctpBinding smbusBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.SMBus";
auto current = std::make_tuple(pcieMedium, pcieBinding);
auto newInfo = std::make_tuple(pcieMedium, smbusBinding);
// Note: isPreferred() returns FALSE when current is better (lower priority
// number) PCIe binding (0) < SMBus binding (5), so current is better,
// function returns false
EXPECT_FALSE(utils::isPreferred(current, newInfo));
EXPECT_TRUE(utils::isPreferred(newInfo, current));
}
TEST(MctpPriority, testIsPreferredDifferentMedium)
{
MctpMedium pcieMedium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpMedium smbusMedium =
"xyz.openbmc_project.MCTP.Endpoint.MediaTypes.SMBus";
MctpBinding pcieBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
MctpBinding smbusBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.SMBus";
auto current = std::make_tuple(pcieMedium, pcieBinding);
auto newInfo = std::make_tuple(smbusMedium, smbusBinding);
// Note: isPreferred() returns FALSE when current is better (lower priority
// number) PCIe medium (0) < SMBus medium (6), so current is better,
// function returns false
EXPECT_FALSE(utils::isPreferred(current, newInfo));
EXPECT_TRUE(utils::isPreferred(newInfo, current));
}
TEST(MctpPriority, testIsPreferredSamePriority)
{
MctpMedium pcieMedium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding pcieBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
auto current = std::make_tuple(pcieMedium, pcieBinding);
auto same = std::make_tuple(pcieMedium, pcieBinding);
// Same priority - current is preferred (>=)
EXPECT_TRUE(utils::isPreferred(current, same));
}
// ============================================================================
// String Utility Tests
// ============================================================================
TEST(StringUtils, testConvertMsgToStringTx)
{
std::vector<uint8_t> buffer{0x01, 0x02, 0x03, 0x04};
uint8_t tag = 0xAB;
eid_t eid = 10;
std::string result = utils::convertMsgToString(utils::Tx, buffer, tag, eid);
// Should contain "Tx" and hex data
EXPECT_NE(result.find("Tx"), std::string::npos);
EXPECT_NE(result.find("01"), std::string::npos); // First byte
// EID format varies, just check result is non-empty
EXPECT_FALSE(result.empty());
}
TEST(StringUtils, testConvertMsgToStringRx)
{
std::vector<uint8_t> buffer{0xAA, 0xBB, 0xCC};
uint8_t tag = 0x12;
eid_t eid = 5;
std::string result = utils::convertMsgToString(utils::Rx, buffer, tag, eid);
// Should contain "Rx", EID, tag
EXPECT_NE(result.find("Rx"), std::string::npos);
EXPECT_NE(result.find("5"), std::string::npos); // EID
}
TEST(StringUtils, testSplitBasic)
{
std::string input = "one,two,three";
auto result = utils::split(input, ",");
ASSERT_EQ(result.size(), 3);
EXPECT_EQ(result[0], "one");
EXPECT_EQ(result[1], "two");
EXPECT_EQ(result[2], "three");
}
TEST(StringUtils, testSplitWithTrim)
{
std::string input = " one , two , three ";
auto result = utils::split(input, ",", " ");
ASSERT_EQ(result.size(), 3);
EXPECT_EQ(result[0], "one");
EXPECT_EQ(result[1], "two");
EXPECT_EQ(result[2], "three");
}
TEST(StringUtils, testSplitEmptyString)
{
std::string input = "";
auto result = utils::split(input, ",");
EXPECT_TRUE(result.empty());
}
TEST(StringUtils, testGetCurrentSystemTime)
{
std::string timeStr = utils::getCurrentSystemTime();
// Should return a non-empty string with timestamp format
EXPECT_FALSE(timeStr.empty());
// Basic sanity: should contain date/time separators
EXPECT_NE(timeStr.find("-"), std::string::npos); // Date separator
EXPECT_NE(timeStr.find(":"), std::string::npos); // Time separator
}
// ============================================================================
// UUID/EID Conversion Tests
// ============================================================================
TEST(UuidEidConversion, testGetUUIDFromEIDFound)
{
// Create a test EID table
std::multimap<std::string, std::tuple<eid_t, MctpMedium, MctpBinding>>
eidTable;
std::string uuid1 = "test-uuid-123";
std::string uuid2 = "test-uuid-456";
eid_t eid1 = 10;
eid_t eid2 = 20;
MctpMedium medium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding binding = "xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
eidTable.emplace(uuid1, std::make_tuple(eid1, medium, binding));
eidTable.emplace(uuid2, std::make_tuple(eid2, medium, binding));
auto result = utils::getUUIDFromEID(eidTable, eid1);
ASSERT_TRUE(result.has_value());
EXPECT_EQ(result.value(), uuid1);
}
TEST(UuidEidConversion, testGetUUIDFromEIDNotFound)
{
std::multimap<std::string, std::tuple<eid_t, MctpMedium, MctpBinding>>
eidTable;
std::string uuid1 = "test-uuid-123";
eid_t eid1 = 10;
eid_t eid_not_found = 99;
MctpMedium medium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding binding = "xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
eidTable.emplace(uuid1, std::make_tuple(eid1, medium, binding));
auto result = utils::getUUIDFromEID(eidTable, eid_not_found);
EXPECT_FALSE(result.has_value());
}
// ============================================================================
// Bitmap/Bitfield Conversion Tests
// ============================================================================
TEST(BitmapConversion, testBitfield256ToBitMap)
{
bitfield256_t bitfield;
memset(&bitfield, 0, sizeof(bitfield));
bitfield.fields[0].byte = 0b00000101; // Bits 0 and 2 set
auto result = utils::bitfield256_tToBitMap(bitfield);
// Function returns 32-byte array (256 bits / 8 bits per byte)
EXPECT_EQ(result.size(), 32);
// First byte should have bits 0 and 2 set (value 0b00000101 = 5)
EXPECT_EQ(result[0], 0b00000101);
}
TEST(BitmapConversion, testBitfield256ToBitArray)
{
bitfield256_t bitfield;
memset(&bitfield, 0, sizeof(bitfield));
bitfield.fields[0].byte = 0x0F0D0B0A; // Set bytes: 0x0A, 0x0B, 0x0D, 0x0F
auto result = utils::bitfield256_tToBitArray(bitfield);
// Function returns 32-byte array representation of 256-bit bitfield
ASSERT_EQ(result.size(), 32);
// First 32-bit field (fields[0]) is split into 4 bytes (big-endian)
EXPECT_EQ(result[0], 0x0F); // Most significant byte
EXPECT_EQ(result[1], 0x0D);
EXPECT_EQ(result[2], 0x0B);
EXPECT_EQ(result[3], 0x0A); // Least significant byte
}
TEST(BitmapConversion, testVectorTo256BitHexString)
{
std::vector<uint8_t> data(32, 0); // 32 bytes = 256 bits
data[0] = 0xAB;
data[1] = 0xCD;
data[31] = 0xEF;
std::string result = utils::vectorTo256BitHexString(data);
// Should be a hex string representation (lowercase)
EXPECT_FALSE(result.empty());
EXPECT_NE(result.find("ab"), std::string::npos); // First byte (lowercase)
EXPECT_NE(result.find("cd"), std::string::npos); // Second byte (lowercase)
}
// ============================================================================
// Type Conversion Tests (Safe Conversions)
// ============================================================================
// ============================================================================
// NSM Code/Reason String Conversion Tests
// ============================================================================
TEST(NsmStringConversion, testNsmCompletionCodeToStringSuccess)
{
std::string result = utils::nsmCompletionCodeToString(NSM_SUCCESS);
EXPECT_FALSE(result.empty());
EXPECT_NE(result.find("SUCCESS"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringError)
{
std::string result = utils::nsmCompletionCodeToString(NSM_ERROR);
EXPECT_FALSE(result.empty());
EXPECT_NE(result.find("ERROR"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringKnownCode)
{
// Test with a known reason code (exact values depend on implementation)
uint16_t reason_code = 0x0000; // Typically "No error" or similar
std::string result = utils::nsmReasonCodeToString(reason_code);
EXPECT_FALSE(result.empty());
}
TEST(NsmStringConversion, testNsmReasonCodeToStringUnknownCode)
{
uint16_t unknown_code = 0xFFFF;
std::string result = utils::nsmReasonCodeToString(unknown_code);
// Should return some representation even for unknown codes
EXPECT_FALSE(result.empty());
}
// ============================================================================
// Device Type/Role Combination Test
// ============================================================================
TEST(DeviceUtils, testCombineDeviceTypeAndRole)
{
uint8_t deviceType = 1; // e.g., SWITCH
uint8_t deviceRole = 2; // e.g., some role
uint16_t result = utils::combineDeviceTypeAndRole(deviceType, deviceRole);
// Function combines: (role << 8) | type (role in high byte, type in low
// byte)
EXPECT_EQ(result >> 8, deviceRole);
EXPECT_EQ(result & 0xFF, deviceType);
}
TEST(DeviceUtils, testGetDeviceInstanceName)
{
std::string result = utils::getDeviceInstanceName(NSM_DEV_ID_GPU, 5);
EXPECT_EQ(result, "GPU_5"); // Function adds underscore separator
result = utils::getDeviceInstanceName(NSM_DEV_ID_SWITCH, 0);
EXPECT_EQ(result, "SWITCH_0"); // Function adds underscore separator
}
// ============================================================================
// Utility Functions Tests (Batch 1 remaining)
// ============================================================================
TEST(UtilityFunctions, testRequestMsgToHexString)
{
// Test with sample message buffer
std::vector<uint8_t> msg = {0xAB, 0xCD, 0xEF, 0x12, 0x34};
std::string result = utils::requestMsgToHexString(msg);
// Should format as hex with spaces: "ab cd ef 12 34 "
EXPECT_EQ(result, "ab cd ef 12 34 ");
}
TEST(UtilityFunctions, testRequestMsgToHexStringEmpty)
{
std::vector<uint8_t> msg;
std::string result = utils::requestMsgToHexString(msg);
// Empty message should return empty string
EXPECT_EQ(result, "");
}
TEST(UtilityFunctions, testRequestMsgToHexStringSingleByte)
{
std::vector<uint8_t> msg = {0xFF};
std::string result = utils::requestMsgToHexString(msg);
EXPECT_EQ(result, "ff ");
}
TEST(UtilityFunctions, testGetCurrentSteadyClockTimestamp)
{
// Get timestamp twice with small delay
uint64_t t1 = utils::getCurrentSteadyClockTimestamp();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
uint64_t t2 = utils::getCurrentSteadyClockTimestamp();
// Second timestamp should be greater than first
EXPECT_GT(t2, t1);
// Difference should be at least 10ms (with some tolerance for timing)
EXPECT_GE(t2 - t1, 9);
// Should be reasonable (not zero, not absurdly large)
EXPECT_GT(t1, 0);
}
TEST(UtilityFunctions, testGetCurrentSteadyClockTimestampUs)
{
// Get timestamp twice with small delay
uint64_t t1 = utils::getCurrentSteadyClockTimestampUs();
std::this_thread::sleep_for(std::chrono::microseconds(500));
uint64_t t2 = utils::getCurrentSteadyClockTimestampUs();
// Second timestamp should be greater than first
EXPECT_GT(t2, t1);
// Difference should be at least 500us (with some tolerance)
EXPECT_GE(t2 - t1, 400);
// Should be reasonable (not zero, not absurdly large)
EXPECT_GT(t1, 0);
}
TEST(UtilityFunctions, testSteadyClockTimestampRelationship)
{
// Microsecond timestamp should be ~1000x millisecond timestamp
uint64_t tsMs = utils::getCurrentSteadyClockTimestamp();
uint64_t tsUs = utils::getCurrentSteadyClockTimestampUs();
// Convert ms to us and compare
// Allow 100ms (100000us) tolerance for Valgrind environments
// where clock calls can be significantly slower
uint64_t tsMsAsUs = tsMs * 1000;
uint64_t diff = (tsUs > tsMsAsUs) ? (tsUs - tsMsAsUs) : (tsMsAsUs - tsUs);
EXPECT_LT(diff, 100000);
}
// Total tests added: ~47
// Functions covered: ~18 of 27 uncovered utility functions
// Session additions (Batch 1 remaining):
// - Utility functions: 7 tests (3 functions)
// - requestMsgToHexString (3 tests)
// - getCurrentSteadyClockTimestamp (1 test)
// - getCurrentSteadyClockTimestampUs (1 test)
// - Timestamp relationship verification (1 test)
// - getDeviceInstanceName (1 test - was missing explicit test)
//
// Remaining uncovered (require mocks or are low-value logging):
// - printBuffer (2 overloads) - logging utility, low ROI
// - appendBufferToFd - requires file descriptor mocking (write syscall)
// - CustomFD operations - explicitly deleted (copy/move) or require fd mocking
// - Some internal helper functions
// These require infrastructure or have very low ROI for coverage target
// ============================================================================
// NSM SW Code String Conversion Tests (Complete Coverage)
// ============================================================================
TEST(NsmStringConversion, testNsmSwCodeToStringSuccess)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_SUCCESS);
EXPECT_NE(result.find("NSM_SW_SUCCESS"), std::string::npos);
EXPECT_NE(result.find("(0)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringError)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR);
EXPECT_NE(result.find("NSM_SW_ERROR"), std::string::npos);
EXPECT_NE(result.find("(1)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringErrorData)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR_DATA);
EXPECT_NE(result.find("NSM_SW_ERROR_DATA"), std::string::npos);
EXPECT_NE(result.find("(2)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringErrorLength)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR_LENGTH);
EXPECT_NE(result.find("NSM_SW_ERROR_LENGTH"), std::string::npos);
EXPECT_NE(result.find("(3)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringErrorNull)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR_NULL);
EXPECT_NE(result.find("NSM_SW_ERROR_NULL"), std::string::npos);
EXPECT_NE(result.find("(4)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringErrorCommandFail)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR_COMMAND_FAIL);
EXPECT_NE(result.find("NSM_SW_ERROR_COMMAND_FAIL"), std::string::npos);
EXPECT_NE(result.find("(5)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringErrorTimeout)
{
std::string result = utils::nsmSwCodeToString(NSM_SW_ERROR_TIMEOUT);
EXPECT_NE(result.find("NSM_SW_ERROR_TIMEOUT"), std::string::npos);
EXPECT_NE(result.find("(6)"), std::string::npos);
}
TEST(NsmStringConversion, testNsmSwCodeToStringUnknown)
{
std::string result = utils::nsmSwCodeToString(99);
EXPECT_NE(result.find("UNKNOWN"), std::string::npos);
EXPECT_NE(result.find("(99)"), std::string::npos);
}
// ============================================================================
// NSM Completion Code String Conversion Tests (Complete Coverage)
// ============================================================================
TEST(NsmStringConversion, testNsmCompletionCodeToStringInvalidData)
{
std::string result = utils::nsmCompletionCodeToString(NSM_ERR_INVALID_DATA);
EXPECT_NE(result.find("NSM_ERR_INVALID_DATA"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringInvalidDataLength)
{
std::string result =
utils::nsmCompletionCodeToString(NSM_ERR_INVALID_DATA_LENGTH);
EXPECT_NE(result.find("NSM_ERR_INVALID_DATA_LENGTH"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringNotReady)
{
std::string result = utils::nsmCompletionCodeToString(NSM_ERR_NOT_READY);
EXPECT_NE(result.find("NSM_ERR_NOT_READY"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringUnsupportedCommand)
{
std::string result =
utils::nsmCompletionCodeToString(NSM_ERR_UNSUPPORTED_COMMAND_CODE);
EXPECT_NE(result.find("NSM_ERR_UNSUPPORTED_COMMAND_CODE"),
std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringUnsupportedMsgType)
{
std::string result =
utils::nsmCompletionCodeToString(NSM_ERR_UNSUPPORTED_MSG_TYPE);
EXPECT_NE(result.find("NSM_ERR_UNSUPPORTED_MSG_TYPE"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringAccepted)
{
std::string result = utils::nsmCompletionCodeToString(NSM_ACCEPTED);
EXPECT_NE(result.find("NSM_ACCEPTED"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringBusy)
{
std::string result = utils::nsmCompletionCodeToString(NSM_BUSY);
EXPECT_NE(result.find("NSM_BUSY"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringBusAccess)
{
std::string result = utils::nsmCompletionCodeToString(NSM_ERR_BUS_ACCESS);
EXPECT_NE(result.find("NSM_ERR_BUS_ACCESS"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringInvalidState)
{
std::string result =
utils::nsmCompletionCodeToString(NSM_ERR_INVALID_STATE_FOR_COMMAND);
EXPECT_NE(result.find("NSM_ERR_INVALID_STATE_FOR_COMMAND"),
std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringInvalidRequestType)
{
std::string result =
utils::nsmCompletionCodeToString(NSM_ERR_INVALID_REQUEST_TYPE);
EXPECT_NE(result.find("NSM_ERR_INVALID_REQUEST_TYPE"), std::string::npos);
}
TEST(NsmStringConversion, testNsmCompletionCodeToStringUnknownCode)
{
std::string result = utils::nsmCompletionCodeToString(0xFF);
EXPECT_NE(result.find("UNKNOWN"), std::string::npos);
}
// ============================================================================
// NSM Reason Code String Conversion Tests (Complete Coverage)
// ============================================================================
TEST(NsmStringConversion, testNsmReasonCodeToStringInvalidPci)
{
std::string result = utils::nsmReasonCodeToString(ERR_INVALID_PCI);
EXPECT_NE(result.find("ERR_INVALID_PCI"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringInvalidRqd)
{
std::string result = utils::nsmReasonCodeToString(ERR_INVALID_RQD);
EXPECT_NE(result.find("ERR_INVALID_RQD"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringTimeout)
{
std::string result = utils::nsmReasonCodeToString(ERR_TIMEOUT);
EXPECT_NE(result.find("ERR_TIMEOUT"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringDownstreamTimeout)
{
std::string result = utils::nsmReasonCodeToString(ERR_DOWNSTREAM_TIMEOUT);
EXPECT_NE(result.find("ERR_DOWNSTREAM_TIMEOUT"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringI2cNackDevAddr)
{
std::string result =
utils::nsmReasonCodeToString(ERR_I2C_NACK_FROM_DEV_ADDR);
EXPECT_NE(result.find("ERR_I2C_NACK_FROM_DEV_ADDR"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringI2cNackDevCmdData)
{
std::string result =
utils::nsmReasonCodeToString(ERR_I2C_NACK_FROM_DEV_CMD_DATA);
EXPECT_NE(result.find("ERR_I2C_NACK_FROM_DEV_CMD_DATA"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringI2cNackDevAddrRs)
{
std::string result =
utils::nsmReasonCodeToString(ERR_I2C_NACK_FROM_DEV_ADDR_RS);
EXPECT_NE(result.find("ERR_I2C_NACK_FROM_DEV_ADDR_RS"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringNvlinkPortInvalid)
{
std::string result = utils::nsmReasonCodeToString(ERR_NVLINK_PORT_INVALID);
EXPECT_NE(result.find("ERR_NVLINK_PORT_INVALID"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringNvlinkPortDisabled)
{
std::string result = utils::nsmReasonCodeToString(ERR_NVLINK_PORT_DISABLED);
EXPECT_NE(result.find("ERR_NVLINK_PORT_DISABLED"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringNotSupported)
{
std::string result = utils::nsmReasonCodeToString(ERR_NOT_SUPPORTED);
EXPECT_NE(result.find("ERR_NOT_SUPPORTED"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringPropertyNotSupported)
{
std::string result =
utils::nsmReasonCodeToString(ERR_PROPERTY_NOT_SUPPORTED);
EXPECT_NE(result.find("ERR_PROPERTY_NOT_SUPPORTED"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringLifespanVolatileNotSupported)
{
std::string result =
utils::nsmReasonCodeToString(ERR_LIFESPAN_VOLATILE_NOT_SUPPORTED);
EXPECT_NE(result.find("ERR_LIFESPAN_VOLATILE_NOT_SUPPORTED"),
std::string::npos);
}
TEST(NsmStringConversion,
testNsmReasonCodeToStringLifespanPersistentNotSupported)
{
std::string result =
utils::nsmReasonCodeToString(ERR_LIFESPAN_PERSISTENT_NOT_SUPPORTED);
EXPECT_NE(result.find("ERR_LIFESPAN_PERSISTENT_NOT_SUPPORTED"),
std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringNoBootComplete)
{
std::string result = utils::nsmReasonCodeToString(ERR_NO_BOOT_COMPLETE);
EXPECT_NE(result.find("ERR_NO_BOOT_COMPLETE"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringUpdateInProgress)
{
std::string result = utils::nsmReasonCodeToString(ERR_UPDATE_IN_PROGRESS);
EXPECT_NE(result.find("ERR_UPDATE_IN_PROGRESS"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringImageCopyInProgress)
{
std::string result =
utils::nsmReasonCodeToString(ERR_IMAGE_COPY_IN_PROGRESS);
EXPECT_NE(result.find("ERR_IMAGE_COPY_IN_PROGRESS"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringImageCopyCompleted)
{
std::string result = utils::nsmReasonCodeToString(ERR_IMAGE_COPY_COMPLETED);
EXPECT_NE(result.find("ERR_IMAGE_COPY_COMPLETED"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringFlashWearMitigation)
{
std::string result =
utils::nsmReasonCodeToString(ERR_FLASH_WEAR_MITIGATION);
EXPECT_NE(result.find("ERR_FLASH_WEAR_MITIGATION"), std::string::npos);
}
TEST(NsmStringConversion, testNsmReasonCodeToStringIncompleteComponentSet)
{
std::string result =
utils::nsmReasonCodeToString(ERR_INCOMPLETE_COMPONENT_SET);
EXPECT_NE(result.find("ERR_INCOMPLETE_COMPONENT_SET"), std::string::npos);
}
// ============================================================================
// Device Type and Role Extraction Tests
// ============================================================================
TEST(DeviceUtils, testGetDeviceTypeAndRoleExtraction)
{
uint8_t deviceType = 0;
uint8_t deviceRole = 0;
uint16_t combined = utils::combineDeviceTypeAndRole(3, 5);
utils::getDeviceTypeAndRole(combined, &deviceType, &deviceRole);
EXPECT_EQ(deviceType, 3);
EXPECT_EQ(deviceRole, 5);
}
TEST(DeviceUtils, testGetDeviceTypeAndRoleZeroValues)
{
uint8_t deviceType = 0xFF;
uint8_t deviceRole = 0xFF;
uint16_t combined = utils::combineDeviceTypeAndRole(0, 0);
utils::getDeviceTypeAndRole(combined, &deviceType, &deviceRole);
EXPECT_EQ(deviceType, 0);
EXPECT_EQ(deviceRole, 0);
}
TEST(DeviceUtils, testGetDeviceTypeAndRoleMaxValues)
{
uint8_t deviceType = 0;
uint8_t deviceRole = 0;
uint16_t combined = utils::combineDeviceTypeAndRole(0xFF, 0xFF);
utils::getDeviceTypeAndRole(combined, &deviceType, &deviceRole);
EXPECT_EQ(deviceType, 0xFF);
EXPECT_EQ(deviceRole, 0xFF);
}
// ============================================================================
// Scaling and Conversion Tests with Invalid Value Handling
// ============================================================================
TEST(TypeConversion, testConvertAndScaleDownUint32ToDoubleNormalValue)
{
double result = utils::convertAndScaleDownUint32ToDouble(1000, 100.0);
EXPECT_DOUBLE_EQ(result, 10.0);
}
TEST(TypeConversion, testConvertAndScaleDownUint32ToDoubleInvalidValue)
{
double result = utils::convertAndScaleDownUint32ToDouble(0xFFFFFFFF, 100.0);
EXPECT_DOUBLE_EQ(result, static_cast<double>(0xFFFFFFFF));
}
TEST(TypeConversion, testConvertAndScaleDownUint32ToDoubleZero)
{
double result = utils::convertAndScaleDownUint32ToDouble(0, 100.0);
EXPECT_DOUBLE_EQ(result, 0.0);
}
TEST(TypeConversion, testConvertAndScaleDownUint8ToDoubleNormalValue)
{
double result = utils::convertAndScaleDownUint8ToDouble(100);
EXPECT_DOUBLE_EQ(result, 100.0);
}
TEST(TypeConversion, testConvertAndScaleDownUint8ToDoubleInvalidValue)
{
double result = utils::convertAndScaleDownUint8ToDouble(0xFF);
EXPECT_DOUBLE_EQ(result, static_cast<double>(0xFF));
}
TEST(TypeConversion, testConvertAndScaleDownUint8ToDoubleZero)
{
double result = utils::convertAndScaleDownUint8ToDouble(0);
EXPECT_DOUBLE_EQ(result, 0.0);
}
// ============================================================================
// Update Methods Bitfield to List Conversion Tests
// ============================================================================
TEST(BitmapConversion, testUpdateMethodsBitfieldToListEmpty)
{
bitfield32_t updateMethodBitfield = {0};
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_TRUE(result.empty());
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListAutomatic)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit0 = 1; // Automatic
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::Automatic);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListMediumSpecificReset)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit2 = 1; // MediumSpecificReset
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0],
sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::MediumSpecificReset);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListSystemReboot)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit3 = 1; // SystemReboot
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::SystemReboot);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListDCPowerCycle)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit4 = 1; // DCPowerCycle
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::DCPowerCycle);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListACPowerCycle)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit5 = 1; // ACPowerCycle
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::ACPowerCycle);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListWarmReset)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit16 = 1; // WarmReset
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::WarmReset);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListHotReset)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit17 = 1; // HotReset
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::HotReset);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListFLR)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit18 = 1; // FLR
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], sdbusplus::common::xyz::openbmc_project::software::
SecurityCommon::UpdateMethods::FLR);
}
TEST(BitmapConversion, testUpdateMethodsBitfieldToListMultipleBits)
{
bitfield32_t updateMethodBitfield = {0};
updateMethodBitfield.bits.bit0 = 1; // Automatic
updateMethodBitfield.bits.bit3 = 1; // SystemReboot
updateMethodBitfield.bits.bit17 = 1; // HotReset
auto result = utils::updateMethodsBitfieldToList(updateMethodBitfield);
EXPECT_EQ(result.size(), 3);
}
// ============================================================================
// Bitfield256 Additional Tests
// ============================================================================
TEST(Bitfield256, testIsAnyBitSetEmpty)
{
utils::Bitfield256 bf;
EXPECT_FALSE(bf.isAnyBitSet());
}
TEST(Bitfield256, testIsAnyBitSetAfterSet)
{
utils::Bitfield256 bf;
bf.setBit(5);
EXPECT_TRUE(bf.isAnyBitSet());
}
TEST(Bitfield256, testIsAnyBitSetMultipleBits)
{
utils::Bitfield256 bf;
bf.setBit(0);
bf.setBit(100);
bf.setBit(255);
EXPECT_TRUE(bf.isAnyBitSet());
}
TEST(Bitfield256, testClearAfterSet)
{
utils::Bitfield256 bf;
bf.setBit(10);
bf.setBit(50);
EXPECT_TRUE(bf.isAnyBitSet());
bf.clear();
EXPECT_FALSE(bf.isAnyBitSet());
}
TEST(Bitfield256, testClearEmptyBitfield)
{
utils::Bitfield256 bf;
bf.clear();
EXPECT_FALSE(bf.isAnyBitSet());
}
// ============================================================================
// Bitfield to Bool Vector Conversion Tests
// ============================================================================
TEST(BitmapConversion, testConvertBitfieldToVectorAllZeros)
{
std::vector<uint8_t> bitfield = {0x00, 0x00, 0x00};
std::vector<bool> supportedMetrics;
utils::convertBitfieldToVector(bitfield, supportedMetrics);
EXPECT_EQ(supportedMetrics.size(), 24); // 3 bytes * 8 bits
for (const auto& bit : supportedMetrics)
{
EXPECT_FALSE(bit);
}
}
TEST(BitmapConversion, testConvertBitfieldToVectorAllOnes)
{
std::vector<uint8_t> bitfield = {0xFF, 0xFF};
std::vector<bool> supportedMetrics;
utils::convertBitfieldToVector(bitfield, supportedMetrics);
EXPECT_EQ(supportedMetrics.size(), 16); // 2 bytes * 8 bits
for (const auto& bit : supportedMetrics)
{
EXPECT_TRUE(bit);
}
}
TEST(BitmapConversion, testConvertBitfieldToVectorMixedBits)
{
std::vector<uint8_t> bitfield = {0xAA}; // 10101010
std::vector<bool> supportedMetrics;
utils::convertBitfieldToVector(bitfield, supportedMetrics);
EXPECT_EQ(supportedMetrics.size(), 8);
EXPECT_FALSE(supportedMetrics[0]); // bit 0
EXPECT_TRUE(supportedMetrics[1]); // bit 1
EXPECT_FALSE(supportedMetrics[2]); // bit 2
EXPECT_TRUE(supportedMetrics[3]); // bit 3
EXPECT_FALSE(supportedMetrics[4]); // bit 4
EXPECT_TRUE(supportedMetrics[5]); // bit 5
EXPECT_FALSE(supportedMetrics[6]); // bit 6
EXPECT_TRUE(supportedMetrics[7]); // bit 7
}
TEST(BitmapConversion, testConvertBitfieldToVectorEmptyInput)
{
std::vector<uint8_t> bitfield;
std::vector<bool> supportedMetrics;
utils::convertBitfieldToVector(bitfield, supportedMetrics);
EXPECT_TRUE(supportedMetrics.empty());
}
// ============================================================================
// getEidFromUUID Tests
// ============================================================================
TEST(UuidEidConversion, getEidFromUUID_Found_ReturnsCorrectEid)
{
// Arrange
std::multimap<std::string, std::tuple<eid_t, MctpMedium, MctpBinding>>
eidTable;
std::string uuid = "00010203-0405-0607-0809-0a0b0c0d0e0f";
eid_t expectedEid = 42;
MctpMedium medium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding binding = "xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
eidTable.emplace(uuid, std::make_tuple(expectedEid, medium, binding));
// Act
eid_t result = utils::getEidFromUUID(eidTable, uuid);
// Assert
EXPECT_EQ(result, expectedEid);
}
TEST(UuidEidConversion, getEidFromUUID_NotFound_ReturnsMax)
{
// Arrange
std::multimap<std::string, std::tuple<eid_t, MctpMedium, MctpBinding>>
eidTable;
std::string uuid = "00010203-0405-0607-0809-0a0b0c0d0e0f";
eid_t someEid = 10;
MctpMedium medium = "xyz.openbmc_project.MCTP.Endpoint.MediaTypes.PCIe";
MctpBinding binding = "xyz.openbmc_project.MCTP.Binding.BindingTypes.PCIe";
eidTable.emplace(uuid, std::make_tuple(someEid, medium, binding));
std::string otherUuid = "11111111-2222-3333-4444-555555555555";
// Act
eid_t result = utils::getEidFromUUID(eidTable, otherUuid);
// Assert - should return max uint8_t when not found
EXPECT_EQ(result, std::numeric_limits<uint8_t>::max());
}
TEST(UuidEidConversion, getEidFromUUID_EmptyTable_ReturnsMax)
{
// Arrange
std::multimap<std::string, std::tuple<eid_t, MctpMedium, MctpBinding>>
eidTable;
std::string uuid = "00010203-0405-0607-0809-0a0b0c0d0e0f";
// Act
eid_t result = utils::getEidFromUUID(eidTable, uuid);
// Assert
EXPECT_EQ(result, std::numeric_limits<uint8_t>::max());
}
// ============================================================================
// parseStaticUuid Tests
// ============================================================================
TEST(ParseStaticUuid, ValidFormat_ReturnsZero)
{
// Arrange
uuid_t uuid = "STATIC:0:0:NSM_DEVICE_INSTANCE_NUMBER:0";
uint8_t deviceType = 0xFF;
uint8_t instanceNumber = 0xFF;
uint8_t deviceRole = 0xFF;
std::string remapPropName;
std::vector<std::string> remapPropValues;
// Act
int result = utils::parseStaticUuid(uuid, deviceType, instanceNumber,
deviceRole, remapPropName,
remapPropValues);
// Assert
EXPECT_EQ(result, 0);
EXPECT_EQ(deviceType, 0);
EXPECT_EQ(instanceNumber, 0);
EXPECT_EQ(remapPropName, "NSM_DEVICE_INSTANCE_NUMBER");
ASSERT_EQ(remapPropValues.size(), 1);
EXPECT_EQ(remapPropValues[0], "0");
}
TEST(ParseStaticUuid, ValidFormatWithDeviceRole_ReturnsZero)
{
// Arrange - deviceType 3 means BASEBOARD, combined with role=5 -> (5<<8)|3
// = 1283
uuid_t uuid = "STATIC:1283:2:MCTP_EID:10";
uint8_t deviceType = 0xFF;
uint8_t instanceNumber = 0xFF;
uint8_t deviceRole = 0xFF;
std::string remapPropName;
std::vector<std::string> remapPropValues;
// Act
int result = utils::parseStaticUuid(uuid, deviceType, instanceNumber,
deviceRole, remapPropName,
remapPropValues);
// Assert
EXPECT_EQ(result, 0);
EXPECT_EQ(deviceType, 3); // low byte of 1283
EXPECT_EQ(deviceRole, 5); // high byte of 1283
EXPECT_EQ(instanceNumber, 2);
EXPECT_EQ(remapPropName, "MCTP_EID");
ASSERT_EQ(remapPropValues.size(), 1);
EXPECT_EQ(remapPropValues[0], "10");
}
TEST(ParseStaticUuid, InvalidFormat_ReturnsNegative)
{
// Arrange - not starting with STATIC:
uuid_t uuid = "NOT_STATIC:0:0:PROP:VAL";
uint8_t deviceType, instanceNumber, deviceRole;
std::string remapPropName;
std::vector<std::string> remapPropValues;
// Act
int result = utils::parseStaticUuid(uuid, deviceType, instanceNumber,
deviceRole, remapPropName,
remapPropValues);
// Assert
EXPECT_LT(result, 0);
}
TEST(ParseStaticUuid, EmptyUuid_ReturnsNegative)
{
// Arrange
uuid_t uuid = "";
uint8_t deviceType, instanceNumber, deviceRole;
std::string remapPropName;
std::vector<std::string> remapPropValues;
// Act
int result = utils::parseStaticUuid(uuid, deviceType, instanceNumber,
deviceRole, remapPropName,
remapPropValues);
// Assert
EXPECT_LT(result, 0);
}
TEST(ParseStaticUuid, MultipleValues_ParsesCorrectly)
{
// Arrange - multiple colon-separated values
uuid_t uuid = "STATIC:0:0:MCTP_UUID:val1:val2";
uint8_t deviceType, instanceNumber, deviceRole;
std::string remapPropName;
std::vector<std::string> remapPropValues;
// Act
int result = utils::parseStaticUuid(uuid, deviceType, instanceNumber,
deviceRole, remapPropName,
remapPropValues);
// Assert
EXPECT_EQ(result, 0);
EXPECT_EQ(remapPropName, "MCTP_UUID");
ASSERT_GE(remapPropValues.size(), 2u);
EXPECT_EQ(remapPropValues[0], "val1");
EXPECT_EQ(remapPropValues[1], "val2");
}
// ============================================================================
// uint64ToDoubleSafeConvert Tests
// ============================================================================
TEST(TypeConversion, uint64ToDoubleSafeConvert_NormalValue_ReturnsExact)
{
// Arrange
uint64_t value = 1000;
// Act
double result = utils::uint64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, 1000.0);
}
TEST(TypeConversion, uint64ToDoubleSafeConvert_Zero_ReturnsZero)
{
// Arrange
uint64_t value = 0;
// Act
double result = utils::uint64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, 0.0);
}
TEST(TypeConversion, uint64ToDoubleSafeConvert_MaxSafeValue_ReturnsExact)
{
// Arrange - MAX_SAFE_INTEGER_IN_DOUBLE = (1ULL << 53) - 1
uint64_t value = (1ULL << 53) - 1;
// Act
double result = utils::uint64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, static_cast<double>(value));
}
TEST(TypeConversion, uint64ToDoubleSafeConvert_ExceedsSafe_ReturnsCapped)
{
// Arrange - value beyond safe range
uint64_t value = (1ULL << 53) + 100;
// Act
double result = utils::uint64ToDoubleSafeConvert(value);
// Assert - should be capped to MAX_SAFE_INTEGER_IN_DOUBLE
EXPECT_DOUBLE_EQ(result, static_cast<double>((1ULL << 53) - 1));
}
TEST(TypeConversion, uint64ToDoubleSafeConvert_MaxUint64_ReturnsCapped)
{
// Arrange
uint64_t value = std::numeric_limits<uint64_t>::max();
// Act
double result = utils::uint64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, static_cast<double>((1ULL << 53) - 1));
}
// ============================================================================
// int64ToDoubleSafeConvert Tests
// ============================================================================
TEST(TypeConversion, int64ToDoubleSafeConvert_PositiveNormal_ReturnsExact)
{
// Arrange
int64_t value = 12345;
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, 12345.0);
}
TEST(TypeConversion, int64ToDoubleSafeConvert_NegativeNormal_ReturnsExact)
{
// Arrange
int64_t value = -67890;
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, -67890.0);
}
TEST(TypeConversion, int64ToDoubleSafeConvert_Zero_ReturnsZero)
{
// Arrange
int64_t value = 0;
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, 0.0);
}
TEST(TypeConversion, int64ToDoubleSafeConvert_PositiveExceedsSafe_ReturnsCapped)
{
// Arrange - positive value beyond safe range
int64_t value = static_cast<int64_t>((1ULL << 53) + 100);
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert
EXPECT_DOUBLE_EQ(result, static_cast<double>((1ULL << 53) - 1));
}
TEST(TypeConversion, int64ToDoubleSafeConvert_NegativeExceedsSafe_ReturnsCapped)
{
// Arrange - negative value beyond safe range
int64_t value = -static_cast<int64_t>((1ULL << 53) + 100);
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert
// Use 1LL (signed) to get correct negative value; 1ULL would wrap around
EXPECT_DOUBLE_EQ(result, static_cast<double>(-((1LL << 53) - 1)));
}
TEST(TypeConversion, int64ToDoubleSafeConvert_MinInt64_ReturnsCapped)
{
// Arrange
int64_t value = std::numeric_limits<int64_t>::min();
// Act
double result = utils::int64ToDoubleSafeConvert(value);
// Assert - capped to negative MAX_SAFE_INTEGER_IN_DOUBLE
EXPECT_DOUBLE_EQ(result, static_cast<double>(-((1LL << 53) - 1)));
}
// ============================================================================
// convertBitMaskToVector Tests
// ============================================================================
TEST(BitmapConversion, convertBitMaskToVector_AllZeros_EmptyResult)
{
// Arrange
bitfield8_t value[2] = {};
value[0].byte = 0;
value[1].byte = 0;
std::vector<uint8_t> data;
// Act
utils::convertBitMaskToVector(data, value, 2);
// Assert
EXPECT_TRUE(data.empty());
}
TEST(BitmapConversion, convertBitMaskToVector_AllOnes_AllBitsPresent)
{
// Arrange
bitfield8_t value[1] = {};
value[0].byte = 0xFF;
std::vector<uint8_t> data;
// Act
utils::convertBitMaskToVector(data, value, 1);
// Assert - all 8 bits should be in the vector
ASSERT_EQ(data.size(), 8u);
EXPECT_EQ(data[0], 0); // bit 0
EXPECT_EQ(data[1], 1); // bit 1
EXPECT_EQ(data[2], 2); // bit 2
EXPECT_EQ(data[3], 3); // bit 3
EXPECT_EQ(data[4], 4); // bit 4
EXPECT_EQ(data[5], 5); // bit 5
EXPECT_EQ(data[6], 6); // bit 6
EXPECT_EQ(data[7], 7); // bit 7
}
TEST(BitmapConversion, convertBitMaskToVector_SomeBits_CorrectIndices)
{
// Arrange - 0b00000101 = bits 0 and 2 set
bitfield8_t value[1] = {};
value[0].byte = 0x05;
std::vector<uint8_t> data;
// Act
utils::convertBitMaskToVector(data, value, 1);
// Assert
ASSERT_EQ(data.size(), 2u);
EXPECT_EQ(data[0], 0); // bit 0
EXPECT_EQ(data[1], 2); // bit 2
}
TEST(BitmapConversion, convertBitMaskToVector_MultipleBytes_CorrectOffsets)
{
// Arrange - byte 0 has bit 0, byte 1 has bit 0 (which is bit 8 overall)
bitfield8_t value[2] = {};
value[0].byte = 0x01; // bit 0
value[1].byte = 0x01; // bit 8
std::vector<uint8_t> data;
// Act
utils::convertBitMaskToVector(data, value, 2);
// Assert
ASSERT_EQ(data.size(), 2u);
EXPECT_EQ(data[0], 0); // bit 0 in byte 0
EXPECT_EQ(data[1], 8); // bit 0 in byte 1 = index 8
}
// ============================================================================
// bitMapToBitfield256_t Tests
// ============================================================================
TEST(BitmapConversion, bitMapToBitfield256_t_ValidBitmap_ConvertsCorrectly)
{
// Arrange
std::vector<uint8_t> bitmap(32, 0);
bitmap[0] = 0xAB; // MSB of first field
bitmap[1] = 0xCD;
bitmap[2] = 0xEF;
bitmap[3] = 0x12; // LSB of first field
// Act
bitfield256_t result = utils::bitMapToBitfield256_t(bitmap);
// Assert - fields[0] should contain the big-endian representation
uint32_t expected = (0xAB << 24) | (0xCD << 16) | (0xEF << 8) | 0x12;
EXPECT_EQ(result.fields[0].byte, expected);
}
TEST(BitmapConversion, bitMapToBitfield256_t_WrongSize_ReturnsZero)
{
// Arrange - bitmap not 32 bytes
std::vector<uint8_t> bitmap(16, 0xFF);
// Act
bitfield256_t result = utils::bitMapToBitfield256_t(bitmap);
// Assert - all fields should be zero
for (int i = 0; i < 8; i++)
{
EXPECT_EQ(result.fields[i].byte, 0u);
}
}
TEST(BitmapConversion, bitMapToBitfield256_t_EmptyBitmap_ReturnsZero)
{
// Arrange
std::vector<uint8_t> bitmap;
// Act
bitfield256_t result = utils::bitMapToBitfield256_t(bitmap);
// Assert
for (int i = 0; i < 8; i++)
{
EXPECT_EQ(result.fields[i].byte, 0u);
}
}
TEST(BitmapConversion, bitMapToBitfield256_t_AllOnes_CorrectResult)
{
// Arrange
std::vector<uint8_t> bitmap(32, 0xFF);
// Act
bitfield256_t result = utils::bitMapToBitfield256_t(bitmap);
// Assert
for (int i = 0; i < 8; i++)
{
EXPECT_EQ(result.fields[i].byte, 0xFFFFFFFFu);
}
}
// ============================================================================
// indicesToBitmap Tests
// ============================================================================
TEST(BitmapConversion, indicesToBitmap_SingleIndex_CorrectBitSet)
{
// Arrange
std::vector<uint8_t> indices = {3};
// Act
auto result = utils::indicesToBitmap(indices, 1);
// Assert
ASSERT_EQ(result.size(), 1u);
EXPECT_EQ(result[0], 0x08); // bit 3 set
}
TEST(BitmapConversion, indicesToBitmap_MultipleIndices_CorrectBitsSet)
{
// Arrange
std::vector<uint8_t> indices = {0, 2, 7};
// Act
auto result = utils::indicesToBitmap(indices, 1);
// Assert
ASSERT_EQ(result.size(), 1u);
EXPECT_EQ(result[0], 0x85); // bits 0, 2, 7 set = 0b10000101
}
TEST(BitmapConversion, indicesToBitmap_EmptyIndices_ReturnsZeroBitmap)
{
// Arrange
std::vector<uint8_t> indices;
// Act
auto result = utils::indicesToBitmap(indices, 2);
// Assert
ASSERT_EQ(result.size(), 2u);
EXPECT_EQ(result[0], 0);
EXPECT_EQ(result[1], 0);
}
TEST(BitmapConversion, indicesToBitmap_ZeroSize_AutoSizes)
{
// Arrange
std::vector<uint8_t> indices = {9}; // requires at least 2 bytes
// Act
auto result = utils::indicesToBitmap(indices, 0);
// Assert
ASSERT_GE(result.size(), 2u);
EXPECT_EQ(result[1], 0x02); // bit 1 in byte 1 (overall bit 9)
}
TEST(BitmapConversion, indicesToBitmap_SizeTooLarge_Throws)
{
// Arrange
std::vector<uint8_t> indices = {0};
// Act & Assert
EXPECT_THROW(utils::indicesToBitmap(indices, 9), std::invalid_argument);
}
TEST(BitmapConversion, indicesToBitmap_IndexOutOfBounds_Throws)
{
// Arrange - index 16 requires at least 3 bytes, but we only allocate 1
std::vector<uint8_t> indices = {16};
// Act & Assert
EXPECT_THROW(utils::indicesToBitmap(indices, 1), std::invalid_argument);
}
// ============================================================================
// CustomFD Tests
// ============================================================================
TEST(CustomFD, Constructor_ValidFd_CreatesObject)
{
// Arrange
int fd = memfd_create("test_customfd", 0);
ASSERT_GE(fd, 0);
// Act
utils::CustomFD customFd(fd);
// Assert
EXPECT_EQ(static_cast<int>(customFd), fd);
EXPECT_EQ(customFd(), fd);
EXPECT_EQ(customFd.size(), 0u);
}
TEST(CustomFD, Constructor_InvalidFd_Throws)
{
// Act & Assert
EXPECT_THROW(utils::CustomFD(-1), std::runtime_error);
}
TEST(CustomFD, WriteAndRead_ValidData_Succeeds)
{
// Arrange
int fd = memfd_create("test_rw", 0);
ASSERT_GE(fd, 0);
// Pre-allocate space in the file
std::vector<uint8_t> initData(10, 0);
if (write(fd, initData.data(), initData.size()) < 0)
{}
lseek(fd, 0, SEEK_SET);
utils::CustomFD customFd(fd);
std::vector<uint8_t> writeData = {0xAA, 0xBB, 0xCC, 0xDD};
// Act - write at position 0
bool writeOk = customFd.write(0, writeData.data(), writeData.size());
// Assert
EXPECT_TRUE(writeOk);
// Act - read back
std::vector<uint8_t> readData(4, 0);
bool readOk = customFd.read(0, readData.data(), readData.size());
// Assert
EXPECT_TRUE(readOk);
EXPECT_EQ(readData, writeData);
}
TEST(CustomFD, Write_BeyondFileSize_ReturnsFalse)
{
// Arrange
int fd = memfd_create("test_write_beyond", 0);
ASSERT_GE(fd, 0);
utils::CustomFD customFd(fd);
std::vector<uint8_t> data = {0x01};
// Act - write beyond file size (file is empty, pos 100 > size 0)
bool result = customFd.write(100, data.data(), data.size());
// Assert
EXPECT_FALSE(result);
}
TEST(CustomFD, Read_BeyondFileSize_ReturnsFalse)
{
// Arrange
int fd = memfd_create("test_read_beyond", 0);
ASSERT_GE(fd, 0);
utils::CustomFD customFd(fd);
std::vector<uint8_t> data(4, 0);
// Act - read beyond file size (file is empty)
bool result = customFd.read(0, data.data(), data.size());
// Assert
EXPECT_FALSE(result);
}
TEST(CustomFD, Write_NullData_ReturnsFalse)
{
// Arrange
int fd = memfd_create("test_null_write", 0);
ASSERT_GE(fd, 0);
// Write some data first to have a non-zero file size
uint8_t dummy = 0;
if (write(fd, &dummy, 1) < 0)
{}
lseek(fd, 0, SEEK_SET);
utils::CustomFD customFd(fd);
// Act
bool result = customFd.write(0, nullptr, 4);
// Assert
EXPECT_FALSE(result);
}
TEST(CustomFD, Read_NullData_ReturnsFalse)
{
// Arrange
int fd = memfd_create("test_null_read", 0);
ASSERT_GE(fd, 0);
uint8_t dummy = 0;
if (write(fd, &dummy, 1) < 0)
{}
lseek(fd, 0, SEEK_SET);
utils::CustomFD customFd(fd);
// Act
bool result = customFd.read(0, nullptr, 1);
// Assert
EXPECT_FALSE(result);
}
TEST(CustomFD, Write_ZeroSize_ReturnsFalse)
{
// Arrange
int fd = memfd_create("test_zero_write", 0);
ASSERT_GE(fd, 0);
uint8_t dummy = 0;
if (write(fd, &dummy, 1) < 0)
{}
lseek(fd, 0, SEEK_SET);
utils::CustomFD customFd(fd);
uint8_t data = 0xAA;
// Act
bool result = customFd.write(0, &data, 0);
// Assert
EXPECT_FALSE(result);
}
TEST(CustomFD, Size_AfterWrite_UpdatesCorrectly)
{
// Arrange
int fd = memfd_create("test_size_update", 0);
ASSERT_GE(fd, 0);
// Pre-populate with 5 bytes
std::vector<uint8_t> initData(5, 0);
if (write(fd, initData.data(), initData.size()) < 0)
{}
lseek(fd, 0, SEEK_SET);
utils::CustomFD customFd(fd);
EXPECT_EQ(customFd.size(), 5u);
// Act - write 10 bytes starting at position 0 (extends file)
std::vector<uint8_t> largeData(10, 0xAA);
bool writeOk = customFd.write(0, largeData.data(), largeData.size());
// Assert
EXPECT_TRUE(writeOk);
EXPECT_GE(customFd.size(), 10u);
}
// ============================================================================
// appendBufferToFd Tests
// ============================================================================
TEST(FileDescriptorOps, appendBufferToFd_ValidData_Appends)
{
// Arrange
int fd = memfd_create("test_append", 0);
ASSERT_GE(fd, 0);
std::vector<uint8_t> firstData = {0x01, 0x02};
utils::writeBufferToFd(fd, firstData);
std::vector<uint8_t> appendData = {0x03, 0x04, 0x05};
// Act
utils::appendBufferToFd(fd, appendData);
// Assert - read back total data
std::vector<uint8_t> readBack;
utils::readFdToBuffer(fd, readBack);
ASSERT_EQ(readBack.size(), 5u);
EXPECT_EQ(readBack[0], 0x01);
EXPECT_EQ(readBack[1], 0x02);
EXPECT_EQ(readBack[2], 0x03);
EXPECT_EQ(readBack[3], 0x04);
EXPECT_EQ(readBack[4], 0x05);
close(fd);
}
TEST(FileDescriptorOps, appendBufferToFd_InvalidFd_Throws)
{
// Arrange
std::vector<uint8_t> data = {0x01};
// Act & Assert
EXPECT_THROW(utils::appendBufferToFd(-1, data), std::runtime_error);
}
TEST(FileDescriptorOps, readFdToBuffer_InvalidFd_Throws)
{
// Arrange
std::vector<uint8_t> buffer;
// Act & Assert
EXPECT_THROW(utils::readFdToBuffer(-1, buffer), std::runtime_error);
}
TEST(FileDescriptorOps, writeBufferToFd_InvalidFd_Throws)
{
// Arrange
std::vector<uint8_t> data = {0x01, 0x02};
// Act & Assert
EXPECT_THROW(utils::writeBufferToFd(-1, data), std::runtime_error);
}
// ============================================================================
// Associations helper function tests
// ============================================================================
TEST(Associations, getAssociationsTuple_EmptyVector_ReturnsEmpty)
{
// Arrange
std::vector<utils::Association> emptyAssociations;
// Act
auto result = utils::getAssociations(emptyAssociations);
// Assert
EXPECT_TRUE(result.empty());
}
TEST(Associations, getAssociationsTuple_ValidAssociations_ReturnsTuples)
{
// Arrange
std::vector<utils::Association> associations;
utils::Association assoc1;
assoc1.forward = "contains";
assoc1.backward = "contained_by";
assoc1.absolutePath = "/xyz/openbmc_project/inventory/test";
associations.push_back(assoc1);
utils::Association assoc2;
assoc2.forward = "parent";
assoc2.backward = "child";
assoc2.absolutePath = "/xyz/openbmc_project/inventory/test2";
associations.push_back(assoc2);
// Act
auto result = utils::getAssociations(associations);
// Assert
ASSERT_EQ(result.size(), 2u);
EXPECT_EQ(std::get<0>(result[0]), "contains");
EXPECT_EQ(std::get<1>(result[0]), "contained_by");
EXPECT_EQ(std::get<2>(result[0]), "/xyz/openbmc_project/inventory/test");
EXPECT_EQ(std::get<0>(result[1]), "parent");
EXPECT_EQ(std::get<1>(result[1]), "child");
EXPECT_EQ(std::get<2>(result[1]), "/xyz/openbmc_project/inventory/test2");
}
// ============================================================================
// vectorTo256BitHexString Edge Case Tests
// ============================================================================
TEST(BitmapConversion, vectorTo256BitHexString_WrongSize_ReturnsDefaultZero)
{
// Arrange - not 32 bytes
std::vector<uint8_t> data(16, 0xAB);
// Act
std::string result = utils::vectorTo256BitHexString(data);
// Assert - should return default 0x000...0
EXPECT_EQ(result.size(), 66u); // "0x" + 64 hex chars
EXPECT_EQ(result.substr(0, 2), "0x");
EXPECT_EQ(result, "0x" + std::string(64, '0'));
}
TEST(BitmapConversion, vectorTo256BitHexString_AllZeros_ReturnsZeroString)
{
// Arrange
std::vector<uint8_t> data(32, 0x00);
// Act
std::string result = utils::vectorTo256BitHexString(data);
// Assert
EXPECT_EQ(result, "0x" + std::string(64, '0'));
}
TEST(BitmapConversion, vectorTo256BitHexString_AllFF_ReturnsAllFF)
{
// Arrange
std::vector<uint8_t> data(32, 0xFF);
// Act
std::string result = utils::vectorTo256BitHexString(data);
// Assert
EXPECT_EQ(result, "0x" + std::string(64, 'f'));
}
// ============================================================================
// MCTP Priority Additional Tests
// ============================================================================
TEST(MctpPriority, isPreferred_UnknownMedium_HandlesGracefully)
{
// Arrange - Use unknown medium types
MctpMedium unknownMedium1 =
"xyz.openbmc_project.MCTP.Endpoint.MediaTypes.Unknown1";
MctpMedium unknownMedium2 =
"xyz.openbmc_project.MCTP.Endpoint.MediaTypes.Unknown2";
MctpBinding unknownBinding =
"xyz.openbmc_project.MCTP.Binding.BindingTypes.Unknown";
auto current = std::make_tuple(unknownMedium1, unknownBinding);
auto newInfo = std::make_tuple(unknownMedium2, unknownBinding);
// Act - should not crash even with unknown types
// Both get MAX_INT priority, so they're equal; isPreferred returns true
// for same priority
bool result = utils::isPreferred(current, newInfo);
// Assert - just ensure no crash; exact behavior depends on fallback
(void)result;
SUCCEED();
}
// ============================================================================
// printBuffer Tests (coverage for logging utility)
// ============================================================================
TEST(StringUtils, printBuffer_VectorOverload_NoCrash)
{
// Arrange
std::vector<uint8_t> buffer = {0x01, 0x02, 0x03};
uint8_t tag = 0x10;
eid_t eid = 5;
// Act - just ensure no crash (prints to lg2 logger)
utils::printBuffer(utils::Tx, buffer, tag, eid);
utils::printBuffer(utils::Rx, buffer, tag, eid);
// Assert
SUCCEED();
}
TEST(StringUtils, printBuffer_PtrOverload_NoCrash)
{
// Arrange
std::vector<uint8_t> buffer = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t tag = 0x20;
eid_t eid = 10;
// Act - just ensure no crash
utils::printBuffer(utils::Tx, buffer.data(), buffer.size(), tag, eid);
utils::printBuffer(utils::Rx, buffer.data(), buffer.size(), tag, eid);
// Assert
SUCCEED();
}
TEST(StringUtils, printBuffer_EmptyVector_NoCrash)
{
// Arrange
std::vector<uint8_t> buffer;
uint8_t tag = 0;
eid_t eid = 0;
// Act
utils::printBuffer(utils::Tx, buffer, tag, eid);
// Assert
SUCCEED();
}
// ============================================================================
// convertMsgToString Additional Tests
// ============================================================================
TEST(StringUtils, convertMsgToString_EmptyBuffer_ReturnsEmpty)
{
// Arrange
std::vector<uint8_t> buffer;
uint8_t tag = 0;
eid_t eid = 0;
// Act
std::string result = utils::convertMsgToString(utils::Tx, buffer, tag, eid);
// Assert - empty buffer returns "" (early return branch)
EXPECT_TRUE(result.empty());
}
TEST(StringUtils, convertMsgToString_LargeBuffer_Succeeds)
{
// Arrange
std::vector<uint8_t> buffer(256, 0xDE);
uint8_t tag = 0xFF;
eid_t eid = 255;
// Act
std::string result = utils::convertMsgToString(utils::Rx, buffer, tag, eid);
// Assert
EXPECT_FALSE(result.empty());
EXPECT_NE(result.find("Rx"), std::string::npos);
}
// ============================================================================
// Bitfield256 Additional Edge Cases
// ============================================================================
TEST(Bitfield256, setBit_Bit0_SetsCorrectly)
{
// Arrange
utils::Bitfield256 bf;
// Act
bool wasNew = bf.setBit(0);
// Assert
EXPECT_TRUE(wasNew);
EXPECT_EQ(bf.fields[0].byte, 1u);
}
TEST(Bitfield256, setBit_Bit255_SetsCorrectly)
{
// Arrange
utils::Bitfield256 bf;
// Act
bool wasNew = bf.setBit(255);
// Assert
EXPECT_TRUE(wasNew);
// Bit 255 = field 7 (255/32=7), bit 31 (255%32=31)
EXPECT_EQ(bf.fields[7].byte, (1u << 31));
}
TEST(Bitfield256, getSetBits_MultipleBitsAcrossFields_FormatsCorrectly)
{
// Arrange
utils::Bitfield256 bf;
bf.setBit(0);
bf.setBit(32); // First bit of field 1
bf.setBit(64); // First bit of field 2
bf.setBit(128); // First bit of field 4
// Act
std::string result = bf.getSetBits();
// Assert
EXPECT_NE(result.find("0"), std::string::npos);
EXPECT_NE(result.find("32"), std::string::npos);
EXPECT_NE(result.find("64"), std::string::npos);
EXPECT_NE(result.find("128"), std::string::npos);
}