Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/Types/StringUtils.hpp>
#include <Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp>
#include <cassert>
#include <cstdio>
Expand Down Expand Up @@ -89,15 +90,30 @@ void AssertFatalAdapterComponentImpl::reportAssert(FILE_NAME_ARG file,
FwAssertArgType arg4,
FwAssertArgType arg5,
FwAssertArgType arg6) {

constexpr FwSizeType outputSize = FW_MIN(static_cast<FwSizeType>(AssertFatalAdapterEventFileSize),
static_cast<FwSizeType>(FW_LOG_STRING_MAX_SIZE));
char output[outputSize];
FwSizeType len = Fw::StringUtils::string_length(file, FileNameStringSize);

// Calculate start index. If string is shorter than N, keep whole string.
FW_ASSERT(file != nullptr);
const char* start = (len > outputSize) ? file + (len - outputSize) : file;

// Copy safely into output buffer (also ensures null-termination)
Fw::StringUtils::string_copy(output, start, outputSize + 1);

// Get file arg for events
#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT
Fw::LogStringArg fileArg;
fileArg.format("0x%08" PRIX32, file);
#else
Fw::LogStringArg fileArg(file);

Fw::LogStringArg fileArg(start);
#endif

CHAR msg[Fw::StringBase::BUFFER_SIZE(FW_ASSERT_TEXT_SIZE)] = {0};
Fw::defaultReportAssert(file, static_cast<U32>(lineNo), numArgs, arg1, arg2, arg3, arg4, arg5, arg6, msg,
Fw::defaultReportAssert(output, static_cast<U32>(lineNo), numArgs, arg1, arg2, arg3, arg4, arg5, arg6, msg,
sizeof(msg));
Fw::Logger::log("%s\n", msg);

Expand Down
22 changes: 11 additions & 11 deletions Svc/AssertFatalAdapter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
#
# Note: using PROJECT_NAME as EXECUTABLE_NAME
####

set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapter.fpp"
"${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapterComponentImpl.cpp"

register_fprime_module(
AUTOCODER_INPUTS
"${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapter.fpp"
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapterComponentImpl.cpp"
)

register_fprime_module()
# UTs ###
set(UT_SOURCE_FILES
"${FPRIME_FRAMEWORK_PATH}/Svc/AssertFatalAdapter/AssertFatalAdapter.fpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/AssertFatalAdapterTester.cpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp"
register_fprime_ut(
AUTOCODER_INPUTS
"${FPRIME_FRAMEWORK_PATH}/Svc/AssertFatalAdapter/AssertFatalAdapter.fpp"
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/test/ut/AssertFatalAdapterTester.cpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp"
)
register_fprime_ut()
set (UT_TARGET_NAME "${FPRIME_CURRENT_MODULE}_ut_exe")
if (TARGET "${UT_TARGET_NAME}")
target_compile_options("${UT_TARGET_NAME}" PRIVATE -Wno-conversion)
Expand Down
146 changes: 139 additions & 7 deletions Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

namespace Svc {

// Apply all truncations to file buffer size
const FwSizeType FILE_ARG_MAX_LEN =
FW_MIN(static_cast<FwSizeType>(AssertFatalAdapterEventFileSize),
FW_MIN(static_cast<FwSizeType>(FW_LOG_STRING_MAX_SIZE), static_cast<FwSizeType>(FW_ASSERT_TEXT_SIZE)));

// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
Expand All @@ -36,16 +41,20 @@ AssertFatalAdapterTester::~AssertFatalAdapterTester() {}
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
void doLeadingTruncation(char* dst, const char* src, FwSizeType truncatedSize) {
FW_ASSERT(src != nullptr);
FW_ASSERT(dst != nullptr);
FwSizeType len = Fw::StringUtils::string_length(src, FileNameStringSize);
// Calculate start index. If string is shorter than N, keep whole string.
const char* start = (len > truncatedSize) ? src + (len - truncatedSize) : src;
// Copy safely into output buffer (also ensures null-termination)
(void)Fw::StringUtils::string_copy(dst, start, truncatedSize + 1);
}

void AssertFatalAdapterTester::testAsserts() {
U32 lineNo;

// apply all truncations to file buffer size
const FwSizeType fileMaxSize =
std::min({static_cast<FwSizeType>(AssertFatalAdapterEventFileSize),
static_cast<FwSizeType>(FW_LOG_STRING_MAX_SIZE), static_cast<FwSizeType>(FW_ASSERT_TEXT_SIZE)});

char file[Fw::StringBase::BUFFER_SIZE(fileMaxSize)];
char file[Fw::StringBase::BUFFER_SIZE(FILE_ARG_MAX_LEN)];
Fw::String fileString;

// Asserts may be turned off resulting in this component doing a no-op
Expand All @@ -57,10 +66,11 @@ void AssertFatalAdapterTester::testAsserts() {

#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT
fileString.format("0x%08" PRIX32, ASSERT_FILE_ID);
(void)Fw::StringUtils::string_copy(file, fileString.toChar(), static_cast<FwSizeType>(sizeof(file)));
#else
fileString = __FILE__;
doLeadingTruncation(file, fileString.toChar(), AssertFatalAdapterEventFileSize);
#endif
(void)Fw::StringUtils::string_copy(file, fileString.toChar(), static_cast<FwSizeType>(sizeof(file)));

// FW_ASSERT_0

Expand Down Expand Up @@ -138,6 +148,94 @@ void AssertFatalAdapterTester::testAsserts() {
ASSERT_EVENTS_AF_UNEXPECTED_ASSERT(0, unexpectedFileArg, 1000, 10);
}

void AssertFatalAdapterTester::testTruncation() {
#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT
// File ID mode doesn't use string paths, skip truncation test
return;
#else
constexpr FwSizeType maxSize = FILE_ARG_MAX_LEN;
ASSERT_LE(maxSize, static_cast<FwSizeType>(FW_ASSERT_TEXT_SIZE));
// Test 1: Short path should remain unchanged
const char* shortPath = "test/short.cpp";
this->clearTextLogs();
this->component.reportAssert(shortPath, 100, 0, 0, 0, 0, 0, 0, 0);
ASSERT_EVENTS_AF_ASSERT_0_SIZE(1);
ASSERT_EVENTS_AF_ASSERT_0(0, shortPath, 100);
// Verify text log contains the short path
const std::string& textLog1 = this->getLastTextLog();
ASSERT_NE(textLog1.find(shortPath), std::string::npos) << "Text log should contain full short path";
this->clearHistory();

// Test 2: Path exactly at limit should remain unchanged
char exactPath[Fw::StringBase::BUFFER_SIZE(maxSize)];
fillWithBytePattern(exactPath, sizeof(exactPath), true);
this->clearTextLogs();
this->component.reportAssert(exactPath, 200, 0, 0, 0, 0, 0, 0, 0);
ASSERT_EVENTS_AF_ASSERT_0_SIZE(1);
ASSERT_EVENTS_AF_ASSERT_0(0, exactPath, 200);
// Verify text log contains the exact path
const std::string& textLog2 = this->getLastTextLog();
ASSERT_NE(textLog2.find(exactPath), std::string::npos) << "Text log should contain exact-length path";
this->clearHistory();

// Test 3: Long path should be truncated (keeps trailing portion)
// Create a path longer than maxSize
constexpr FwSizeType longPathSize = maxSize + 2;
char longPath[longPathSize + 1];
fillWithBytePattern(longPath, longPathSize, true);

// Fill with pattern: "prefix..." + "suffix/truncation_test.cpp"
const char* suffix = "/suffix/truncation_test.cpp";
FwSizeType suffixLen = Fw::StringUtils::string_length(suffix, FileNameStringSize);
FwSizeType prefixLen = longPathSize - maxSize;
// Fill prefix with repeating digits
for (FwSizeType i = 0; i < prefixLen; i++) {
longPath[i] = (i % 10) + 'a';
}
Fw::StringUtils::string_copy(longPath + prefixLen + (maxSize-suffixLen), suffix, suffixLen+1);

// Expected truncated result: keeps last (maxSize) characters
char expectedTruncated[Fw::StringBase::BUFFER_SIZE(maxSize)];
doLeadingTruncation(expectedTruncated, longPath, maxSize);
printf("longPath %s\n", longPath);
printf("expectedTruncated %s\n", expectedTruncated);

this->clearTextLogs();
this->component.reportAssert(longPath, 300, 1, 42, 0, 0, 0, 0, 0);
ASSERT_EVENTS_AF_ASSERT_1_SIZE(1);
ASSERT_EVENTS_AF_ASSERT_1(0, expectedTruncated, 300, 42);
// Verify text log contains truncated path, not full path
const std::string& textLog3 = this->getLastTextLog();
ASSERT_NE(textLog3.find(expectedTruncated), std::string::npos) << "Text log should contain truncated path";
// Verify the prefix (which should be truncated away) is NOT in the text log
char prefixOnly[11] = {0};
Fw::StringUtils::string_copy(prefixOnly, longPath, 11);
ASSERT_EQ(textLog3.find(prefixOnly), std::string::npos) << "Text log should NOT contain truncated prefix portion";
this->clearHistory();

// Test 4: Verify truncation with all assert variants (test AF_ASSERT_3 as example)
char veryLongPath[longPathSize + 1];
fillWithBytePattern(veryLongPath, sizeof(veryLongPath), true);

char expectedTruncated2[Fw::StringBase::BUFFER_SIZE(maxSize)];
doLeadingTruncation(expectedTruncated2, veryLongPath, maxSize);

this->clearTextLogs();
this->component.reportAssert(veryLongPath, 400, 3, 1, 2, 3, 0, 0, 0);
ASSERT_EVENTS_AF_ASSERT_3_SIZE(1);
ASSERT_EVENTS_AF_ASSERT_3(0, expectedTruncated2, 400, 1, 2, 3);
// Verify text log contains truncated path
const std::string& textLog4 = this->getLastTextLog();
ASSERT_NE(textLog4.find(expectedTruncated2), std::string::npos)
<< "Text log should contain truncated path for ASSERT_3";
// Verify the beginning (which should be truncated away) is NOT in the text log
char beginOnly[11] = {0};
Fw::StringUtils::string_copy(beginOnly, veryLongPath, 11);
ASSERT_EQ(textLog4.find(beginOnly), std::string::npos)
<< "Text log should NOT contain truncated beginning for ASSERT_3";
#endif
}

// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
Expand Down Expand Up @@ -165,7 +263,41 @@ void AssertFatalAdapterTester::textLogIn(const FwEventIdType id, //!< T
) {
TextLogEntry e = {id, timeTag, severity, text};

// Store the text log message for verification
this->textLogMessages.push_back(text.toChar());

printTextLogHistoryEntry(e, stdout);
}

void AssertFatalAdapterTester::clearTextLogs() {
this->textLogMessages.clear();
}

const std::string& AssertFatalAdapterTester::getLastTextLog() const {
FW_ASSERT(!this->textLogMessages.empty(), static_cast<FwAssertArgType>(this->textLogMessages.size()));
return this->textLogMessages.back();
}

void AssertFatalAdapterTester::fillWithBytePattern(char* buffer, FwSizeType size, bool nullTerminate) {
FW_ASSERT(buffer != nullptr);
FW_ASSERT(size > 0);

const FwSizeType fillSize = nullTerminate ? (size - 1) : size;

// Fill with repeating two-digit pattern: "00112233445566778899001122..."
// Each position shows (index % 100) in decimal, making byte positions identifiable
for (FwSizeType i = 0; i < fillSize; i++) {
const FwSizeType digitValue = (i / 2) % 100;
if (i % 2 == 0) {
buffer[i] = '0' + (digitValue / 10); // Tens digit
} else {
buffer[i] = '0' + (digitValue % 10); // Ones digit
}
}

if (nullTerminate) {
buffer[fillSize] = '\0';
}
}

} // end namespace Svc
26 changes: 26 additions & 0 deletions Svc/AssertFatalAdapter/test/ut/AssertFatalAdapterTester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef TESTER_HPP
#define TESTER_HPP

#include <string>
#include <vector>
#include "AssertFatalAdapterGTestBase.hpp"
#include "Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp"

Expand Down Expand Up @@ -41,6 +43,10 @@ class AssertFatalAdapterTester : public AssertFatalAdapterGTestBase {
//!
void testAsserts();

//! Test file path truncation
//!
void testTruncation();

private:
// ----------------------------------------------------------------------
// Helper methods
Expand All @@ -63,11 +69,31 @@ class AssertFatalAdapterTester : public AssertFatalAdapterGTestBase {
//!
AssertFatalAdapterComponentImpl component;

//! Storage for text log messages
//!
std::vector<std::string> textLogMessages;

void textLogIn(const FwEventIdType id, //!< The event ID
const Fw::Time& timeTag, //!< The time
const Fw::LogSeverity severity, //!< The severity
const Fw::TextLogString& text //!< The event string
) override;

//! Clear text log history
//!
void clearTextLogs();

//! Get the last text log message
//!
const std::string& getLastTextLog() const;

//! Fill buffer with identifiable byte pattern for debugging
//! Writes repeating pattern: "00112233...99" to make byte positions visible
//! \param buffer: Character buffer to fill
//! \param size: Total size of buffer (includes null terminator)
//! \param nullTerminate: If true, writes null terminator at end
//!
static void fillWithBytePattern(char* buffer, FwSizeType size, bool nullTerminate = true);
};

} // end namespace Svc
Expand Down
5 changes: 4 additions & 1 deletion Svc/AssertFatalAdapter/test/ut/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ TEST(Nominal, NominalInit) {
Svc::AssertFatalAdapterTester tester;
tester.testAsserts();
}

TEST(Nominal, FilePathTruncation) {
Svc::AssertFatalAdapterTester tester;
tester.testTruncation();
}
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
Expand Down
10 changes: 6 additions & 4 deletions default/config/AcConstants.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@ constant FileNameStringSize = 240
@ The size of an assert text string
constant FwAssertTextSize = 256

@ The size of a file name in an AssertFatalAdapter event
@ The size of a file name in an AssertFatalAdapter event (leading-truncation)
@ Note: File names in assertion failures are also truncated by
@ the constants FW_ASSERT_TEXT_SIZE and FW_LOG_STRING_MAX_SIZE, set
@ in FpConfig.h.
constant AssertFatalAdapterEventFileSize = FileNameStringSize
@ the constants FwAssertTextSize (in this file) and FW_LOG_STRING_MAX_SIZE (set
@ in FW_LOG_STRING_MAX_SIZE)
@ Set much smaller than FwAssertTextSize so there's space for time stamp/assert
@ arguments in log message
constant AssertFatalAdapterEventFileSize = 150

@ The maximum size in bytes for passing sequence arguments through CmdSeqIn ports
@ Note: This must fit within FW_CMD_ARG_BUFFER_MAX_SIZE along with cmd arguments using Svc::SeqArgs
Expand Down
Loading