Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ jobs:
./examples/system/dif_test/dif_test
./examples/system/dif_test/test_direct_access

- name: Test DMOD_LOG_STEP_* macros via log_step module
working-directory: build
run: |
./examples/system/dmod_loader/dmod_loader ./dmf/log_step.dmf
echo "log_step module loaded and executed successfully"

- name: Run manifest library tests
working-directory: build
run: ./tests/tests_dmod_manifest
Expand Down
3 changes: 2 additions & 1 deletion examples/module/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(library)
add_subdirectory(application)
add_subdirectory(application)
add_subdirectory(log_step)
3 changes: 2 additions & 1 deletion examples/module/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ DMOD_DIR=../..
# Subdirectories
# -----------------------------------------------------------------------------
SUBDIRS := library \
application
application \
log_step

# -----------------------------------------------------------------------------
# Initialization of paths
Expand Down
9 changes: 9 additions & 0 deletions examples/module/log_step/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
set(DMOD_MODULE_NAME log_step)
set(DMOD_MODULE_VERSION "0.1")
set(DMOD_AUTHOR_NAME "Patryk Kubiak")
set(DMOD_STACK_SIZE 1024)
set(DMOD_PRIORITY 0)

dmod_add_executable(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
main.c
)
28 changes: 28 additions & 0 deletions examples/module/log_step/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# #############################################################################
#
# Example application module that exercises DMOD_LOG_STEP_* macros.
#
# #############################################################################
DMOD_DIR=../../..

# -----------------------------------------------------------------------------
# Paths initialization
# -----------------------------------------------------------------------------
include $(DMOD_DIR)/paths.mk

# -----------------------------------------------------------------------------
# Module configuration
# -----------------------------------------------------------------------------
DMOD_MODULE_NAME=log_step
DMOD_MODULE_VERSION=0.1
DMOD_AUTHOR_NAME=Patryk Kubiak
DMOD_CSOURCES=main.c
DMOD_CXXSOURCES=
DMOD_INC_DIRS=
DMOD_LIBS=
DMOD_DEFINITIONS=

# -----------------------------------------------------------------------------
# Include the dmod app makefile
# -----------------------------------------------------------------------------
include $(DMOD_DMF_APP_FILE_PATH)
37 changes: 37 additions & 0 deletions examples/module/log_step/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#define DMOD_ENABLE_REGISTRATION ON
#include "dmod.h"

/**
* @brief Example module demonstrating DMOD_LOG_STEP_* macros.
*
* This module exercises:
* - DMOD_LOG_STEP_BEGIN : show an empty progress bar at the start of an operation
* - DMOD_LOG_STEP_PROGRESS : update the progress bar with a percentage
* - DMOD_LOG_STEP : conclude with [ OK ] or [ FAIL ] depending on result
*
* The DMOD_LOG_STEP_* macros concatenate their argument with a colour-escape
* prefix at compile time, so string literals must be used.
*/
int main(int argc, char** argv)
{
(void)argc;
(void)argv;

/* ---------------------------------------------------------------
* Simulate a successful multi-step operation
* --------------------------------------------------------------- */
DMOD_LOG_STEP_BEGIN("Initializing subsystem\n");
DMOD_LOG_STEP_PROGRESS(25, "Initializing subsystem\n");
DMOD_LOG_STEP_PROGRESS(50, "Initializing subsystem\n");
DMOD_LOG_STEP_PROGRESS(75, "Initializing subsystem\n");
DMOD_LOG_STEP(0, "Initializing subsystem\n");

/* ---------------------------------------------------------------
* Simulate a failing step (non-zero result → [ FAIL ])
* --------------------------------------------------------------- */
DMOD_LOG_STEP_BEGIN("Running diagnostics\n");
DMOD_LOG_STEP_PROGRESS(50, "Running diagnostics\n");
DMOD_LOG_STEP(1, "Running diagnostics\n");

return 0;
}
1 change: 1 addition & 0 deletions tests/system/if/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ set(TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_stack.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_uptime.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_module_log_level.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_log_step.cpp
PARENT_SCOPE
)
161 changes: 161 additions & 0 deletions tests/system/if/tests_dmod_log_step.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include <gtest/gtest.h>
#include "dmod.h"

// ===============================================================
// Tests for DMOD_LOG_STEP_* macros and Dmod_GetStepBar helper
// ===============================================================

class DmodLogStepTest : public ::testing::Test
{
};

/**
* @brief DMOD_LOG_STEP_BEGIN does not crash
*/
TEST_F(DmodLogStepTest, LogStepBegin_NoCrash)
{
DMOD_LOG_STEP_BEGIN("starting operation\n");
}

/**
* @brief DMOD_LOG_STEP_PROGRESS does not crash at 0%
*/
TEST_F(DmodLogStepTest, LogStepProgress_Zero_NoCrash)
{
DMOD_LOG_STEP_PROGRESS(0, "operation in progress\n");
}

/**
* @brief DMOD_LOG_STEP_PROGRESS does not crash at 50%
*/
TEST_F(DmodLogStepTest, LogStepProgress_Mid_NoCrash)
{
DMOD_LOG_STEP_PROGRESS(50, "operation in progress\n");
}

/**
* @brief DMOD_LOG_STEP_PROGRESS does not crash at 100%
*/
TEST_F(DmodLogStepTest, LogStepProgress_Full_NoCrash)
{
DMOD_LOG_STEP_PROGRESS(100, "operation in progress\n");
}

/**
* @brief DMOD_LOG_STEP with result 0 (success) does not crash
*/
TEST_F(DmodLogStepTest, LogStep_Success_NoCrash)
{
DMOD_LOG_STEP(0, "operation result\n");
}

/**
* @brief DMOD_LOG_STEP with non-zero result (failure) does not crash
*/
TEST_F(DmodLogStepTest, LogStep_Failure_NoCrash)
{
DMOD_LOG_STEP(1, "operation result\n");
}

/**
* @brief Full sequence (begin, progress, step) does not crash
*/
TEST_F(DmodLogStepTest, FullSequence_NoCrash)
{
DMOD_LOG_STEP_BEGIN("loading module\n");
DMOD_LOG_STEP_PROGRESS(25, "loading module\n");
DMOD_LOG_STEP_PROGRESS(75, "loading module\n");
DMOD_LOG_STEP(0, "loading module\n");
}

/**
* @brief Dmod_GetStepBar returns non-NULL for 0%
*/
TEST_F(DmodLogStepTest, GetStepBar_Zero_NotNull)
{
EXPECT_NE(Dmod_GetStepBar(0), nullptr);
}

/**
* @brief Dmod_GetStepBar returns non-NULL for 50%
*/
TEST_F(DmodLogStepTest, GetStepBar_Mid_NotNull)
{
EXPECT_NE(Dmod_GetStepBar(50), nullptr);
}

/**
* @brief Dmod_GetStepBar returns non-NULL for 100%
*/
TEST_F(DmodLogStepTest, GetStepBar_Full_NotNull)
{
EXPECT_NE(Dmod_GetStepBar(100), nullptr);
}

/**
* @brief Dmod_GetStepBar clamps negative percentages without crashing
*/
TEST_F(DmodLogStepTest, GetStepBar_Negative_NoCrash)
{
const char* bar = Dmod_GetStepBar(-10);
EXPECT_NE(bar, nullptr);
/* negative should clamp to the same bar as 0% */
EXPECT_STREQ(bar, Dmod_GetStepBar(0));
}

/**
* @brief Dmod_GetStepBar clamps percentages above 100 without crashing
*/
TEST_F(DmodLogStepTest, GetStepBar_Over100_NoCrash)
{
const char* bar = Dmod_GetStepBar(110);
EXPECT_NE(bar, nullptr);
/* values > 100 should clamp to the same bar as 100% */
EXPECT_STREQ(bar, Dmod_GetStepBar(100));
}

/* Count the number of filled-block UTF-8 sequences (U+2588, encoded as
* \xe2\x96\x88) in a bar string. Each filled segment adds one such sequence.
*/
static int CountFilledBlocks(const char* bar)
{
int count = 0;
while (bar && *bar)
{
if ((unsigned char)bar[0] == 0xe2 &&
(unsigned char)bar[1] == 0x96 &&
(unsigned char)bar[2] == 0x88)
{
count++;
bar += 3;
}
else
{
bar++;
}
}
return count;
}

/**
* @brief Dmod_GetStepBar returns bars with non-decreasing fill as percentage rises
*
* The seven discrete states (index 0..6, one per ~17%) should never regress:
* each representative percentage must have at least as many filled blocks as
* the previous one.
*/
TEST_F(DmodLogStepTest, GetStepBar_Monotone)
{
int prevFill = CountFilledBlocks(Dmod_GetStepBar(0));

/* Walk through representative percentages and ensure fill never decreases */
int percentages[] = { 17, 34, 50, 67, 84, 100 };
for (int i = 0; i < (int)(sizeof(percentages) / sizeof(percentages[0])); i++)
{
const char* cur = Dmod_GetStepBar(percentages[i]);
ASSERT_NE(cur, nullptr);
int curFill = CountFilledBlocks(cur);
EXPECT_GE(curFill, prevFill);
prevFill = curFill;
}
}
Loading