| /* |
| * 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); |
| } |