blob: 8fe327f414eebfbd2af3cc6f41f3b7cc6dbfbb00 [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION &
* AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0
*/
/**
* Branch Coverage Enhancement Tests for libnsm/base.c
* Target: Increase branch coverage from 68.4% to 90%+
* Focus: Uncovered conditional branches, error paths, edge cases
*/
#include "base.h"
#include "common-tests.hpp"
#include "device-capability-discovery.h"
#include "diagnostics.h"
#include "platform-environmental.h"
#include <gtest/gtest.h>
/**
* Branch coverage tests for pack_nsm_header - NSM_EVENT message type
*/
TEST(PackNSMHeaderBranch, EventMessageType)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
hdr.nsm_msg_type = NSM_EVENT;
hdr.instance_id = 10;
hdr.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
auto rc = pack_nsm_header(&hdr, &msg);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(msg.datagram, 1); // EVENT sets datagram=1
EXPECT_EQ(msg.request, 1); // EVENT sets request=1
EXPECT_EQ(msg.instance_id, 10);
}
/**
* Branch coverage tests for pack_nsm_header - NSM_EVENT_ACKNOWLEDGMENT message
* type
*/
TEST(PackNSMHeaderBranch, EventAcknowledgmentMessageType)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
hdr.nsm_msg_type = NSM_EVENT_ACKNOWLEDGMENT;
hdr.instance_id = 15;
hdr.nvidia_msg_type = NSM_TYPE_PLATFORM_ENVIRONMENTAL;
auto rc = pack_nsm_header(&hdr, &msg);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(msg.datagram, 1); // EVENT_ACKNOWLEDGMENT sets datagram=1
EXPECT_EQ(msg.request, 0); // EVENT_ACKNOWLEDGMENT sets request=0
EXPECT_EQ(msg.instance_id, 15);
}
/**
* Branch coverage tests for pack_nsm_header - Invalid message type
*/
TEST(PackNSMHeaderBranch, InvalidMessageType)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
hdr.nsm_msg_type = 0x05; // Invalid message type (not REQUEST, RESPONSE,
// EVENT, or EVENT_ACKNOWLEDGMENT)
hdr.instance_id = 0;
hdr.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
auto rc = pack_nsm_header(&hdr, &msg);
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage tests for pack_nsm_header - Boundary instance ID
*/
TEST(PackNSMHeaderBranch, BoundaryInstanceId)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
// Test maximum valid instance ID
hdr.nsm_msg_type = NSM_REQUEST;
hdr.instance_id = NSM_INSTANCE_MAX; // 31 is max
hdr.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
auto rc = pack_nsm_header(&hdr, &msg);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(msg.instance_id, NSM_INSTANCE_MAX);
}
/**
* Branch coverage tests for unpack_nsm_header - Invalid PCI Vendor ID
*/
TEST(UnpackNSMHeaderBranch, InvalidPCIVendorId)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(0x8086); // Invalid: Intel, not NVIDIA
msg.ocp_type = OCP_TYPE;
msg.ocp_version = OCP_VERSION;
msg.request = 1;
msg.datagram = 0;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage tests for unpack_nsm_header - Invalid OCP Type
*/
TEST(UnpackNSMHeaderBranch, InvalidOCPType)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = 7; // Invalid: should be 8
msg.ocp_version = OCP_VERSION;
msg.request = 1;
msg.datagram = 0;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage tests for unpack_nsm_header - Invalid OCP Version
*/
TEST(UnpackNSMHeaderBranch, InvalidOCPVersion)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = OCP_TYPE;
msg.ocp_version = 0xF; // Invalid version (4-bit field max value)
msg.request = 1;
msg.datagram = 0;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage tests for unpack_nsm_header - Valid OCP Version V2
*/
TEST(UnpackNSMHeaderBranch, ValidOCPVersionV2)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = OCP_TYPE;
msg.ocp_version = OCP_VERSION_V2; // Version 10 is valid
msg.request = 1;
msg.datagram = 0;
msg.instance_id = 5;
msg.nvidia_msg_type = NSM_TYPE_NETWORK_PORT;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(hdr.nsm_msg_type, NSM_REQUEST);
EXPECT_EQ(hdr.instance_id, 5);
EXPECT_EQ(hdr.nvidia_msg_type, NSM_TYPE_NETWORK_PORT);
}
/**
* Branch coverage tests for unpack_nsm_header - Response message (request=0,
* datagram=0)
*/
TEST(UnpackNSMHeaderBranch, ResponseMessage)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = OCP_TYPE;
msg.ocp_version = OCP_VERSION;
msg.request = 0; // Response
msg.datagram = 0; // Not datagram
msg.instance_id = 12;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(hdr.nsm_msg_type, NSM_RESPONSE);
}
/**
* Branch coverage tests for unpack_nsm_header - Event Acknowledgment
* (request=0, datagram=1)
*/
TEST(UnpackNSMHeaderBranch, EventAcknowledgmentMessage)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = OCP_TYPE;
msg.ocp_version = OCP_VERSION;
msg.request = 0; // Not request
msg.datagram = 1; // Datagram
msg.instance_id = 8;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(hdr.nsm_msg_type, NSM_EVENT_ACKNOWLEDGMENT);
}
/**
* Branch coverage tests for unpack_nsm_header - Event message (request=1,
* datagram=1)
*/
TEST(UnpackNSMHeaderBranch, EventMessage)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
msg.pci_vendor_id = htobe16(PCI_VENDOR_ID);
msg.ocp_type = OCP_TYPE;
msg.ocp_version = OCP_VERSION;
msg.request = 1; // Request
msg.datagram = 1; // Datagram
msg.instance_id = 20;
auto rc = unpack_nsm_header(&msg, &hdr);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(hdr.nsm_msg_type, NSM_EVENT);
}
/**
* Branch coverage tests for pack_nsm_header_v2
*/
TEST(PackNSMHeaderV2Branch, ValidMessage)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
hdr.nsm_msg_type = NSM_REQUEST;
hdr.instance_id = 7;
hdr.nvidia_msg_type = NSM_TYPE_PCI_LINK;
auto rc = pack_nsm_header_v2(&hdr, &msg);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(msg.ocp_version, OCP_VERSION_V2); // V2 version
EXPECT_EQ(msg.instance_id, 7);
}
/**
* Branch coverage tests for pack_nsm_header_v2 - Error propagation
*/
TEST(PackNSMHeaderV2Branch, ErrorPropagation)
{
struct nsm_header_info hdr;
struct nsm_msg_hdr msg{};
hdr.nsm_msg_type = 0xAB; // Invalid type
hdr.instance_id = 0;
auto rc = pack_nsm_header_v2(&hdr, &msg);
EXPECT_EQ(rc,
NSM_SW_ERROR_DATA); // Error propagated from pack_nsm_header
}
/**
* Branch coverage for encode_ping_req - Null pointer
*/
TEST(EncodePingReqBranch, NullPointer)
{
auto rc = encode_ping_req(0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_ping_resp - Null pointer
*/
TEST(EncodePingRespBranch, NullPointer)
{
auto rc = encode_ping_resp(0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_ping_resp - Non-zero reason code
*/
TEST(EncodePingRespBranch, NonZeroReasonCode)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint16_t reason_code = 0x1234; // Non-zero reason code
auto rc = encode_ping_resp(5, reason_code, response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(response->hdr.instance_id, 5);
}
/**
* Branch coverage for decode_ping_resp - Null message pointer
* NOTE: Tests for null cc/reason_code removed - production code bug in
* libnsm/base.c:388 (decode_ping_resp dereferences *cc before checking return
* code from decode_reason_code_and_cc)
*/
TEST(DecodePingRespBranch, NullMessagePointer)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
uint8_t cc = 0;
uint16_t reason_code = 0;
// Null message - this is safe
auto rc =
decode_ping_resp(nullptr, responseMsg.size(), &cc, &reason_code);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_ping_resp - Invalid message length
*/
TEST(DecodePingRespBranch, InvalidMessageLength)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t reason_code = 0;
// Message too short
auto rc = decode_ping_resp(response, sizeof(nsm_msg_hdr) - 1, &cc,
&reason_code);
EXPECT_EQ(rc, NSM_SW_ERROR_LENGTH);
}
/**
* Branch coverage for decode_ping_resp - Non-zero data_size
* Tests line 397 in base.c (resp->data_size != 0 error path)
*/
TEST(DecodePingRespBranch, NonZeroDataSize)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
// Set up a valid ping response but with non-zero data_size
auto resp_payload =
reinterpret_cast<nsm_common_resp *>(response->payload);
resp_payload->command = NSM_PING;
resp_payload->completion_code = NSM_SUCCESS;
resp_payload->data_size = 1; // Non-zero triggers error
uint8_t cc = 0;
uint16_t reason_code = 0;
auto rc =
decode_ping_resp(response, responseMsg.size(), &cc, &reason_code);
// Should return error because data_size should be 0 for ping response
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage for decode_long_running_event - Extract instance_id
* Tests lines 1070-1071 in base.c (instance_id != NULL path)
*/
TEST(DecodeLongRunningEventBranch, ExtractInstanceId)
{
// Construct a minimal long-running event message
// Message layout: nsm_msg_hdr + nsm_event + nsm_long_running_resp
size_t msg_len = sizeof(nsm_msg_hdr) + NSM_EVENT_MIN_LEN +
sizeof(nsm_long_running_resp);
std::vector<uint8_t> msgData(msg_len, 0);
auto msg = reinterpret_cast<nsm_msg *>(msgData.data());
// Set up event payload (minimal fields - function doesn't validate
// them)
auto event = reinterpret_cast<nsm_event *>(msg->payload);
event->event_class = 0; // Don't care - not validated by function
event->event_id = 1;
event->event_state = 0; // Don't care - just needs to exist
event->data_size = sizeof(nsm_long_running_resp);
// Set up long_running_resp in event data
auto resp = reinterpret_cast<nsm_long_running_resp *>(event->data);
resp->instance_id = 0x15; // Test instance ID value
resp->completion_code = NSM_SUCCESS;
uint8_t instance_id = 0;
uint8_t cc = 0;
uint16_t reason_code = 0;
// Call with non-NULL instance_id to cover lines 1070-1071
auto rc = decode_long_running_event(msg, msg_len, &instance_id, &cc,
&reason_code);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
EXPECT_EQ(instance_id, 0x15); // Verify instance_id was extracted
EXPECT_EQ(cc, NSM_SUCCESS);
}
/**
* Branch coverage for encode_raw_cmd_req_v2 - Non-zero data size
* Tests line 1197 in base.c (dataSize > 0 path with memcpy)
*/
TEST(EncodeRawCmdReqV2Branch, NonZeroDataSize)
{
// Test encode_raw_cmd_req_v2 with non-zero dataSize
// This covers line 1197 (memcpy when dataSize > 0)
std::vector<uint8_t> msgData(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req_v2) + 10);
auto msg = reinterpret_cast<nsm_msg *>(msgData.data());
uint8_t instanceId = 5;
uint8_t messageType = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY;
uint8_t commandCode = 0x42; // Arbitrary command code
uint8_t payload[] = {0x01, 0x02, 0x03, 0x04, 0x05};
size_t dataSize = sizeof(payload);
auto rc = encode_raw_cmd_req_v2(instanceId, messageType, commandCode,
payload, dataSize, msg);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
// Verify the payload was copied
auto request = reinterpret_cast<nsm_common_req_v2 *>(msg->payload);
EXPECT_EQ(request->command, commandCode);
EXPECT_EQ(request->data_size, dataSize);
// Verify data was copied after the common request header
uint8_t *copiedData = msg->payload + sizeof(nsm_common_req_v2);
EXPECT_EQ(memcmp(copiedData, payload, dataSize), 0);
}
/**
* Branch coverage for encode_get_histogram_format_resp - Error completion code
* Tests line 1281 in base.c (cc != NSM_SUCCESS path)
*/
TEST(EncodeGetHistogramFormatRespBranch, ErrorCompletionCode)
{
// Test encode_get_histogram_format_resp with non-success completion
// code This covers line 1281 (encode_reason_code path when cc !=
// NSM_SUCCESS)
std::vector<uint8_t> responseMsg(256, 0);
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t instance_id = 7;
uint8_t cc = NSM_ERR_INVALID_DATA; // Non-success completion code
uint16_t reason_code = 0x5678;
// These parameters are not used when cc != NSM_SUCCESS, but must be
// valid
nsm_histogram_format_metadata meta_data = {};
meta_data.num_of_buckets = 0;
meta_data.min_sampling_time = 0;
meta_data.accumulation_cycle = 0;
meta_data.reserved0 = 0;
meta_data.increment_duration = 0;
meta_data.bucket_unit_of_measure = 0;
meta_data.reserved1 = 0;
meta_data.bucket_data_type = 0;
meta_data.reserved2 = 0;
uint8_t bucket_offsets[4] = {0};
uint32_t bucket_offsets_size = sizeof(bucket_offsets);
auto rc = encode_get_histogram_format_resp(
instance_id, cc, reason_code, &meta_data, bucket_offsets,
bucket_offsets_size, response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
// Verify response structure for error case
auto resp_payload =
reinterpret_cast<nsm_common_non_success_resp *>(response->payload);
EXPECT_EQ(resp_payload->command, NSM_GET_HISTOGRAM_FORMAT);
EXPECT_EQ(resp_payload->completion_code, cc);
EXPECT_EQ(le16toh(resp_payload->reason_code), reason_code);
}
/**
* Branch coverage for encode_get_supported_nvidia_message_types_req - Null
* pointer
*/
TEST(EncodeSupportedNvidiaMessageTypesReqBranch, NullPointer)
{
auto rc = encode_get_supported_nvidia_message_types_req(0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_get_supported_nvidia_message_types_resp - Error
* completion code
*/
TEST(EncodeSupportedNvidiaMessageTypesRespBranch, ErrorCompletionCode)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) +
sizeof(nsm_get_supported_nvidia_message_types_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
std::vector<uint8_t> types(SUPPORTED_MSG_TYPE_DATA_SIZE, 0);
uint16_t reason_code = 0x5678;
auto rc = encode_get_supported_nvidia_message_types_resp(
3, NSM_ERROR, reason_code, (bitfield8_t *)types.data(), response);
EXPECT_EQ(rc, NSM_SUCCESS); // Note: encode returns NSM_SUCCESS, not
// NSM_SW_SUCCESS
auto resp =
reinterpret_cast<nsm_common_non_success_resp *>(response->payload);
EXPECT_EQ(resp->completion_code, NSM_ERROR);
}
/**
* Branch coverage for encode_get_supported_command_codes_req - Null pointer
*/
TEST(EncodeSupportedCommandCodesReqBranch, NullPointer)
{
auto rc = encode_get_supported_command_codes_req(0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_get_supported_command_codes_req - Different
* message types
*/
TEST(EncodeSupportedCommandCodesReqBranch, DifferentMessageTypes)
{
std::vector<uint8_t> requestMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_supported_command_codes_req));
auto request = reinterpret_cast<nsm_msg *>(requestMsg.data());
// Test with NSM_TYPE_NETWORK_PORT
auto rc = encode_get_supported_command_codes_req(
10, NSM_TYPE_NETWORK_PORT, request);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
auto req = reinterpret_cast<nsm_get_supported_command_codes_req *>(
request->payload);
EXPECT_EQ(req->nvidia_message_type, NSM_TYPE_NETWORK_PORT);
}
/**
* Branch coverage for encode_get_supported_command_codes_resp - Null pointers
*/
TEST(EncodeSupportedCommandCodesRespBranch, NullPointers)
{
std::vector<uint8_t> codes(SUPPORTED_COMMAND_CODE_DATA_SIZE, 0);
// Null message pointer
auto rc = encode_get_supported_command_codes_resp(
0, NSM_SUCCESS, 0, (bitfield8_t *)codes.data(), nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_supported_command_codes_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
// Null codes pointer
rc = encode_get_supported_command_codes_resp(0, NSM_SUCCESS, 0, nullptr,
response);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_get_supported_command_codes_resp - Null pointers
* NOTE: Tests for null cc/reason_code removed - production code bug in
* libnsm/base.c:574 (decode_get_supported_command_codes_resp dereferences *cc
* without checking for null first)
*/
TEST(DecodeSupportedCommandCodesRespBranch, NullOutputPointers)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_supported_command_codes_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t reason_code = 0;
uint8_t codes[SUPPORTED_COMMAND_CODE_DATA_SIZE];
// Null message pointer
auto rc = decode_get_supported_command_codes_resp(
nullptr, responseMsg.size(), &cc, &reason_code,
(bitfield8_t *)codes);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
// Null codes pointer
rc = decode_get_supported_command_codes_resp(
response, responseMsg.size(), &cc, &reason_code, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_get_supported_command_codes_resp - Invalid length
*/
TEST(DecodeSupportedCommandCodesRespBranch, InvalidLength)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_get_supported_command_codes_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t reason_code = 0;
uint8_t codes[SUPPORTED_COMMAND_CODE_DATA_SIZE];
// Message too short
auto rc = decode_get_supported_command_codes_resp(
response, responseMsg.size() - 5, &cc, &reason_code,
(bitfield8_t *)codes);
EXPECT_EQ(rc, NSM_SW_ERROR_LENGTH);
}
/**
* Branch coverage for encode_query_device_identification_resp - Different
* device types
*/
TEST(EncodeQueryDeviceIdentificationRespBranch, DifferentDeviceTypes)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_query_device_identification_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
// Test with NSM_DEV_ID_SWITCH
auto rc = encode_query_device_identification_resp(
15, NSM_SUCCESS, ERR_NULL, NSM_DEV_ID_SWITCH, 3, response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
auto resp = reinterpret_cast<nsm_query_device_identification_resp *>(
response->payload);
EXPECT_EQ(resp->device_identification, NSM_DEV_ID_SWITCH);
EXPECT_EQ(resp->instance_id, 3);
}
/**
* Branch coverage for encode_query_device_identification_resp - Null pointer
*/
TEST(EncodeQueryDeviceIdentificationRespBranch, NullPointer)
{
auto rc = encode_query_device_identification_resp(0, NSM_SUCCESS, 0, 0,
0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_query_device_identification_resp - Error
* completion code Tests line 637 in base.c (cc != NSM_SUCCESS path)
*/
TEST(EncodeQueryDeviceIdentificationRespBranch, ErrorCompletionCode)
{
// Test with non-success completion code to trigger error path
std::vector<uint8_t> responseMsg(256, 0);
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t instance = 10;
uint8_t cc = NSM_ERR_INVALID_DATA; // Non-success completion code
uint16_t reason_code = 0xABCD;
uint8_t device_identification = NSM_DEV_ID_SWITCH;
uint8_t device_instance = 5;
auto rc = encode_query_device_identification_resp(
instance, cc, reason_code, device_identification, device_instance,
response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
// Verify error response structure
auto resp_payload =
reinterpret_cast<nsm_common_non_success_resp *>(response->payload);
EXPECT_EQ(resp_payload->command, NSM_QUERY_DEVICE_IDENTIFICATION);
EXPECT_EQ(resp_payload->completion_code, cc);
EXPECT_EQ(le16toh(resp_payload->reason_code), reason_code);
}
/**
* Branch coverage for decode_query_device_identification_resp - Null pointers
*/
TEST(DecodeQueryDeviceIdentificationRespBranch, NullPointers)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_query_device_identification_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t reason_code = 0;
uint8_t device_id = 0;
uint8_t instance_id = 0;
// Null message
auto rc = decode_query_device_identification_resp(
nullptr, responseMsg.size(), &cc, &reason_code, &device_id,
&instance_id);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
// Null device_id pointer
rc = decode_query_device_identification_resp(
response, responseMsg.size(), &cc, &reason_code, nullptr,
&instance_id);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
// Null instance_id pointer
rc = decode_query_device_identification_resp(
response, responseMsg.size(), &cc, &reason_code, &device_id,
nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_query_device_identification_resp - Invalid length
*/
TEST(DecodeQueryDeviceIdentificationRespBranch, InvalidLength)
{
std::vector<uint8_t> responseMsg(
sizeof(nsm_msg_hdr) + sizeof(nsm_query_device_identification_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t reason_code = 0;
uint8_t device_id = 0;
uint8_t instance_id = 0;
// Message too short
auto rc = decode_query_device_identification_resp(
response, sizeof(nsm_msg_hdr), &cc, &reason_code, &device_id,
&instance_id);
EXPECT_EQ(rc, NSM_SW_ERROR_LENGTH);
}
/**
* Branch coverage for encode_common_req - Null pointer
*/
TEST(EncodeCommonReqBranch, NullPointer)
{
auto rc = encode_common_req(0, NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_PING, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_common_req - Basic decode
*/
TEST(DecodeCommonReqBranch, BasicDecode)
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req));
auto request = reinterpret_cast<nsm_msg *>(requestMsg.data());
// Set up header
request->hdr.pci_vendor_id = htobe16(PCI_VENDOR_ID);
request->hdr.ocp_type = OCP_TYPE;
request->hdr.ocp_version = OCP_VERSION;
request->hdr.request = 1;
request->hdr.datagram = 0;
auto req = reinterpret_cast<nsm_common_req *>(request->payload);
req->command = NSM_PING;
req->data_size = 0;
// Valid decode - only takes 2 parameters
auto rc = decode_common_req(request, requestMsg.size());
EXPECT_EQ(rc, NSM_SW_SUCCESS);
}
/**
* Branch coverage for encode_common_resp - Null pointer
*/
TEST(EncodeCommonRespBranch, NullPointer)
{
auto rc = encode_common_resp(0, NSM_SUCCESS, 0,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_PING, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_common_resp - Error with reason code
*/
TEST(EncodeCommonRespBranch, ErrorWithReasonCode)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint16_t reason_code = 0xABCD;
auto rc = encode_common_resp(8, NSM_ERROR, reason_code,
NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_PING, response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
auto resp = reinterpret_cast<nsm_common_resp *>(response->payload);
EXPECT_EQ(resp->completion_code, NSM_ERROR);
EXPECT_EQ(resp->command, NSM_PING);
}
/**
* Branch coverage for decode_common_resp - Null message pointer
* NOTE: Tests for null cc/data_size/reason_code removed - production code bug
* in libnsm/base.c:971 (decode_common_resp calls decode_reason_code_and_cc with
* unchecked reason_code, then dereferences *cc)
*/
TEST(DecodeCommonRespBranch, NullMessagePointer)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
uint8_t cc = 0;
uint16_t data_size = 0;
uint16_t reason_code = 0;
// Null message pointer - this is safe
auto rc = decode_common_resp(nullptr, responseMsg.size(), &cc,
&data_size, &reason_code);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_common_resp - Invalid length
*/
TEST(DecodeCommonRespBranch, InvalidLength)
{
std::vector<uint8_t> responseMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_resp));
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t cc = 0;
uint16_t data_size = 0;
uint16_t reason_code = 0;
// Message too short
auto rc = decode_common_resp(response, sizeof(nsm_msg_hdr) - 1, &cc,
&data_size, &reason_code);
EXPECT_EQ(rc, NSM_SW_ERROR_LENGTH);
}
/**
* Branch coverage for encode_raw_cmd_req - With payload data
*/
TEST(EncodeRawCmdReqBranch, WithPayloadData)
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req) + 16);
auto request = reinterpret_cast<nsm_msg *>(requestMsg.data());
uint8_t payload_data[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10};
auto rc =
encode_raw_cmd_req(5, NSM_TYPE_DIAGNOSTIC, NSM_ENABLE_DISABLE_WP,
payload_data, 16, request);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
auto req = reinterpret_cast<nsm_common_req *>(request->payload);
EXPECT_EQ(req->command, NSM_ENABLE_DISABLE_WP);
EXPECT_EQ(req->data_size, 16);
EXPECT_EQ(request->payload[2], 0x01); // First byte of payload data
}
/**
* Branch coverage for encode_raw_cmd_req - Null message pointer
*/
TEST(EncodeRawCmdReqBranch, NullMessagePointer)
{
uint8_t payload[4] = {0};
auto rc = encode_raw_cmd_req(0, NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_PING, payload, 4, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for encode_raw_cmd_req - Data size mismatch
*/
TEST(EncodeRawCmdReqBranch, DataSizeMismatch)
{
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req));
auto request = reinterpret_cast<nsm_msg *>(requestMsg.data());
// Null data but non-zero size - error
auto rc = encode_raw_cmd_req(0, NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY,
NSM_PING, nullptr, 1, request);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
/**
* Branch coverage for decode_common_req_v2 - Invalid PCI vendor ID
* Tests line 924 in base.c (unpack_nsm_header error path)
*/
TEST(DecodeCommonReqV2Branch, InvalidPciVendorId)
{
// Create a message with invalid PCI vendor ID to trigger unpack error
std::vector<uint8_t> requestMsg(sizeof(nsm_msg_hdr) +
sizeof(nsm_common_req_v2));
auto request = reinterpret_cast<nsm_msg *>(requestMsg.data());
// Set up header with invalid PCI vendor ID (not 0x10de)
request->hdr.pci_vendor_id = htobe16(0xFFFF); // Invalid vendor ID
request->hdr.ocp_type = OCP_TYPE;
request->hdr.ocp_version = OCP_VERSION_V2;
request->hdr.instance_id = 5;
// decode_common_req_v2 should fail when unpack_nsm_header detects
// invalid vendor ID
auto rc = decode_common_req_v2(request, requestMsg.size());
EXPECT_EQ(rc, NSM_SW_ERROR_DATA);
}
/**
* Branch coverage for encode_set_gpio_state_resp - Error completion code
* Tests line 1737 in base.c (cc != NSM_SUCCESS path)
*/
TEST(EncodeSetGpioStateRespBranch, ErrorCompletionCode)
{
// Test with non-success completion code to trigger error path
std::vector<uint8_t> responseMsg(256, 0);
auto response = reinterpret_cast<nsm_msg *>(responseMsg.data());
uint8_t instance_id = 7;
uint8_t cc = NSM_ERR_INVALID_DATA; // Non-success completion code
uint16_t reason_code = 0x5678;
uint16_t offset = 0;
uint16_t length = 0;
uint8_t gpio_values[8] = {0};
uint32_t gpio_values_size = 0;
auto rc = encode_set_gpio_state_resp(instance_id, cc, reason_code,
offset, length, gpio_values,
gpio_values_size, response);
EXPECT_EQ(rc, NSM_SW_SUCCESS);
// Verify error response structure
auto resp_payload =
reinterpret_cast<nsm_common_non_success_resp *>(response->payload);
EXPECT_EQ(resp_payload->command, NSM_SET_GPIO_STATE);
EXPECT_EQ(resp_payload->completion_code, cc);
EXPECT_EQ(le16toh(resp_payload->reason_code), reason_code);
}
// Branch coverage for encode_get_supported_nvidia_message_types_resp
// Tests the "if (msg == NULL)" TRUE branch (line 435 in base.c)
TEST(EncodeGetSupportedNvidiaMsgTypesRespBranch, NullMsg)
{
auto rc = encode_get_supported_nvidia_message_types_resp(
0, NSM_SUCCESS, 0, nullptr, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_nsm_query_device_identification_req
// Tests the "if (msg == NULL)" TRUE branch (line 593 in base.c)
TEST(EncodeNsmQueryDeviceIdentificationReqBranch, NullMsg)
{
auto rc = encode_nsm_query_device_identification_req(0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_nsm_event_acknowledgement — L730
TEST(EncodeNsmEventAcknowledgementBranch, NullMsg)
{
auto rc = encode_nsm_event_acknowledgement(0, 0, 0, nullptr);
EXPECT_EQ(rc, NSM_ERR_INVALID_DATA);
}
// Branch coverage for decode_nsm_event_acknowledgement — L755
// (event_id == NULL part — short-circuits after msg/instance_id/nsm_type)
TEST(DecodeNsmEventAcknowledgementBranch, NullEventId)
{
std::vector<uint8_t> buf(
sizeof(nsm_msg_hdr) + sizeof(nsm_event_ack) + 1, 0);
auto *msg = reinterpret_cast<const nsm_msg *>(buf.data());
uint8_t instance_id = 0, nsm_type = 0;
auto rc = decode_nsm_event_acknowledgement(
msg, buf.size(), &instance_id, &nsm_type, nullptr);
EXPECT_EQ(rc, NSM_ERR_INVALID_DATA);
}
// Branch coverage for encode_common_req_v2 — L897
TEST(EncodeCommonReqV2Branch, NullMsg)
{
auto rc = encode_common_req_v2(0, 0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_histogram_format_req — L1210
TEST(EncodeGetHistogramFormatReqBranch, NullMsg)
{
auto rc = encode_get_histogram_format_req(0, 0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_histogram_format_resp — L1266
TEST(EncodeGetHistogramFormatRespBranch, NullMsg)
{
auto rc = encode_get_histogram_format_resp(0, NSM_SUCCESS, 0, nullptr,
nullptr, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_histogram_data_req — L1371
TEST(EncodeGetHistogramDataReqBranch, NullMsg)
{
auto rc = encode_get_histogram_data_req(0, 0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_histogram_data_resp — L1427
TEST(EncodeGetHistogramDataRespBranch, NullMsg)
{
auto rc = encode_get_histogram_data_resp(0, NSM_SUCCESS, 0, 0, 0,
nullptr, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_gpio_state_req — L1510
TEST(EncodeGetGpioStateReqBranch, NullMsg)
{
auto rc = encode_get_gpio_state_req(0, 0, 0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_get_gpio_state_resp — L1568
TEST(EncodeGetGpioStateRespBranch, NullMsg)
{
auto rc = encode_get_gpio_state_resp(0, NSM_SUCCESS, 0, 0, 0, nullptr,
0, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// Branch coverage for encode_set_gpio_state_req — L1644 (msg == NULL)
TEST(EncodeSetGpioStateReqBranch, NullMsg)
{
uint8_t gpio_vals[1] = {0};
auto rc = encode_set_gpio_state_req(0, 0, 0, gpio_vals, 1, nullptr);
EXPECT_EQ(rc, NSM_SW_ERROR_NULL);
}
// ---------------------------------------------------------------------------
// Pack-fail branches (instance_id > NSM_INSTANCE_MAX = 31)
// ---------------------------------------------------------------------------
// Branch coverage for encode_ping_req — L362 (rc != NSM_SW_SUCCESS)
TEST(EncodePingReqBranch, PackFail)
{
std::vector<uint8_t> buf(256, 0);
auto *msg = reinterpret_cast<nsm_msg *>(buf.data());
auto rc = encode_ping_req(32, msg); // instance_id 32 > NSM_INSTANCE_MAX
EXPECT_NE(rc, NSM_SW_SUCCESS);
}
// Branch coverage for encode_common_req_v2 — L904 (rc != NSM_SW_SUCCESS)
TEST(EncodeCommonReqV2Branch, PackFail)
{
std::vector<uint8_t> buf(256, 0);
auto *msg = reinterpret_cast<nsm_msg *>(buf.data());
auto rc = encode_common_req_v2(32, 0, 0, msg);
EXPECT_NE(rc, NSM_SW_SUCCESS);
}
// Branch coverage for encode_set_gpio_state_req — L1659 (rc != NSM_SW_SUCCESS)
TEST(EncodeSetGpioStateReqBranch, PackFail)
{
std::vector<uint8_t> buf(256, 0);
auto *msg = reinterpret_cast<nsm_msg *>(buf.data());
uint8_t gpio_vals[1] = {0};
auto rc = encode_set_gpio_state_req(32, 0, 0, gpio_vals, 1, msg);
EXPECT_NE(rc, NSM_SW_SUCCESS);
}