diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df60bd..76fccda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,23 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v7.0.0-beta.2] - October 15, 2025 - -### Added - -- ULOG_BUILD_DISABLED option to completely disable the library at compile time. -- Disabled feature test to ensure no code is included when disabled. - -### Changed - -- `ulog_lock_set_fn` now returns `ulog_status` for error handling when locking fails. - -## [v7.0.0-beta.1] - October 9, 2025 +## [v7.0.0] - October 23, 2025 > 🚨 **BREAKING CHANGES**: Complete API redesign from v6.5.0. This is a major architectural overhaul with new type system, function names, and build configuration. -The changelog below consolidates all changes from alpha versions leading up to this release. - ### Added #### Core Features @@ -51,6 +38,12 @@ The changelog below consolidates all changes from alpha versions leading up to t - Enable with `ULOG_BUILD_CONFIG_HEADER_ENABLED=1` - Use `ulog_config.h` by default or customize with `ULOG_BUILD_CONFIG_HEADER_NAME` +#### Optional Features + +- `ULOG_BUILD_DISABLED` option to completely disable the library at compile time. +- `ULOG_BUILD_WARN_NOT_ENABLED` option to emit warnings when used a feature that is disabled. +- `ULOG_BUILD_CONFIG_HEADER_ENABLED`, `ULOG_BUILD_CONFIG_HEADER_NAME` - options to enable a static configuration header to submit build-time options in a single file. + #### Extensions - **Syslog Levels Extension** (`extensions/ulog_syslog.c/.h`) @@ -62,10 +55,9 @@ The changelog below consolidates all changes from alpha versions leading up to t - **Generic Logger Interface Extension** - Easier migration from/to other logging libraries -- **Comprehensive Documentation** +- **Microlog 6 compatibility layer** - - Extensions included in releases - - Documentation moved to `extensions/README.md` for better visibility + - Eases transition from Microlog 6 to ulog v7.0 #### Resource Management @@ -130,7 +122,6 @@ All build configuration now uses unified `ULOG_BUILD_*` pattern: #### Topics Overhaul - **Level-Based Control**: Topics now use log levels instead of simple enable/disable - - `ulog_topic_add()` now takes a level parameter - Replaces previous binary enabled/disabled state - **Registration Required**: All topics (static and dynamic) must use `ulog_topic_add()` @@ -144,12 +135,6 @@ All build configuration now uses unified `ULOG_BUILD_*` pattern: - **Visual Improvements**: FATAL level color changed from magenta to "red on white" - **Feature Names**: Simplified naming (Custom Prefix → Prefix, Extra Outputs → Outputs, File String → Source Location, Runtime Mode → Dynamic Config) -#### Documentation & Examples - -- Example application completely rewritten for v7.0 API -- Better inline documentation and demonstrations -- Syslog levels and dynamic level switching examples - ### Removed - **Emoji Levels**: `ULOG_FEATURE_EMOJI_LEVELS` / `ULOG_USE_EMOJI` completely removed @@ -170,189 +155,3 @@ All build configuration now uses unified `ULOG_BUILD_*` pattern: - Buffer handling in print system - Various bugs in `test_time.cpp` - Consistency and formatting in feature documentation - -## [v7.0.0-alpha.4] - October 9, 2025 - -### Added - -- Add extensions to the release -- Add Static Configuration Header `ulog_config.h` feature to simplify configuration. Use `ULOG_BUILD_CONFIG_HEADER_ENABLED=1` to enable it. -- Add `ULOG_BUILD_CONFIG_HEADER_NAME` to use a static configuration header instead of default `ulog_config.h`. - -### Changed - -- Move extensions documentation from `doc/extensions.md` to `extensions/README.md` for better visibility -- Revamp topics handling from enable/disable to level-based - - `ulog_topic_add()` now takes a level parameter instead of enabled/disabled state -- `ULOG_BUILD_TOPICS_NUM` is replaced with `ULOG_BUILD_TOPICS_MODE` and `ULOG_BUILD_TOPICS_STATIC_NUM` - -### Removed - -- Revamp topics handling from enable/disable to level-based - - `ulog_topic_enable()` and `ulog_topic_enable_all()` - - `ulog_topic_disable()` and `ulog_topic_disable_all()` - -## [v7.0.0-alpha.3] - September 17, 2025 - -### Added - -- Custom log levels via `ulog_level_set_new_levels(ulog_level_descriptor)` / `ulog_level_reset_levels()` -- Replace default levels with generic `ULOG_LEVEL_0...7` - for custom level schemes. -- New macros `ulog_t(level, topic, ...)` and `ulog(level, ...)` for dynamic level logging. -- `ULOG_STATUS_DISABLED` status code for disabled features. -- Extensions: - - Syslog levels extension (`extensions/ulog_syslog.c/.h`) providing RFC 5424 style severities (DEBUG, INFO, NOTICE, WARN, ERR, CRIT, ALERT, EMERG) - - Thread-safe lock extensions for CMSIS-RTOS2, FreeRTOS, POSIX, ThreadX, and Windows. - - Generic logger interface extension for easier migration from/to other logging libraries. - - New documentation page `doc/extensions.md` and README Extensions section. -- Unit tests. UT coverage: >85% lines, >90% functions - -### Changed - -- `ulog_prefix_set_fn` now returns `ulog_status` for error handling. -- Default levels are now aliases for generic `ULOG_LEVEL_0...7`. TRACE = 0, DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4, FATAL = 5. Upper levels (6,7) are unused by default. -- Color of `FATAL` level from "magenta" to "red on white" for better visibility. -- Example application updated to demonstrate syslog levels and dynamic level switching. -- `ULOG_BUILD_LEVEL_STYLE` replaced with `ULOG_BUILD_LEVEL_SHORT` (bool, 0/1) for static configuration of level style. - -### Fixed - -- Minor consistency and formatting adjustments in feature documentation prior to extension introduction. -- Memory (de)allocation for dynamic topics, adding (de)allocation of name string. -- Potential problems with va_list in `ulog_event_get_message()` and `ulog_event_to_cstr()` - -## [v7.0.0-alpha.2] - September 8, 2025 - -### Added - -- Binding topic to a specific output via `ulog_topic_add(TOPIC, OUTPUT, ENABLED)` -- New status codes: - - `ULOG_STATUS_NOT_FOUND` returned when a topic or output is not present (previously returned `ULOG_STATUS_ERROR`) - - `ULOG_STATUS_BUSY` for lock timeouts / failed lock attempts -- `ulog_topic_remove(TOPIC)` -- `ulog_cleanup()` to free all dynamic resources and reset added entities (topics, outputs, etc.) - -### Changed - -- Topics are now require `ulog_topic_add()` to be used. For both static and dynamic topics. -- Standardized macro alias naming conventions for consistency - - Renamed topic aliases: `logt_*` → `ulog_t_*` (e.g., `logt_info` → `ulog_t_info`) - - Removed basic aliases: `log_*` → use `ulog_*` directly (e.g., `log_info` → `ulog_info`) -- Dynamic Config functions now return `ulog_status` for error handling - as they can fail on failed locks -- `ulog_lock_fn` now returns `ulog_status` - error handling for failed locks. -- Replace term "callback" with "handler" for clarity and consistency. - -### Fixed - -- Fix potential buffer overflows on printing -- Fix early exits on outputs and topics iteration after removal - -## [v7.0.0-alpha.1] - September 4, 2025 - -> 🚨 BREAKING CHANGES: Complete API redesign from v6.5.0. This is a major architectural overhaul with new type system, function names, and build configuration. - -### Added - -- Output Management System: Outputs replace callbacks for logging destinations - - `ulog_output_add()` - Add custom callback outputs (replaces `ulog_add_callback()`) - - `ulog_output_add_file()` - Add file outputs (replaces `ulog_add_fp()`) - - `ulog_output_remove()` - Remove outputs dynamically (NEW) - - `ulog_output_level_set()` / `ulog_output_level_set_all()` - Per-output level control (replaces `ulog_set_quiet()`) - - `ULOG_OUTPUT_STDOUT` - Predefined output for stdout (NEW) -- Enhanced Type System: Modern C enum types for better type safety - - `ulog_level` enum: `ULOG_LEVEL_TRACE`, `ULOG_LEVEL_DEBUG`, `ULOG_LEVEL_INFO`, `ULOG_LEVEL_WARN`, `ULOG_LEVEL_ERROR`, `ULOG_LEVEL_FATAL` - - `ulog_status` enum: `ULOG_STATUS_OK`, `ULOG_STATUS_ERROR`, `ULOG_STATUS_INVALID_ARGUMENT` - - `ulog_topic_id` type for topic identification - - `ulog_output` type for output handles - -### Changed - -- Renamed Features: - - Custom Prefix → Prefix: Simplified naming (`ULOG_BUILD_PREFIX_SIZE`) - - Extra Outputs → Outputs: Unified output system (`ULOG_BUILD_EXTRA_OUTPUTS`) - - File String → Source Location: More descriptive (`ULOG_BUILD_SOURCE_LOCATION`) - - Runtime Mode → Dynamic Config: More accurate (`ULOG_BUILD_DYNAMIC_CONFIG`) -- Enhanced Macro System: Dual macro system with backward compatibility - - Primary: `ulog_trace()`, `ulog_debug()`, `ulog_info()`, `ulog_warn()`, `ulog_error()`, `ulog_fatal()` - - Aliases: `log_trace()`, `log_debug()`, etc. (unchanged for compatibility) - - Topic macros: `ulog_topic_*(topic, ...)` with `logt_*()` aliases -- Build Configuration Revolution - - Old System: Feature flags (`ULOG_FEATURE_*`, `ULOG_NO_COLOR`, `ULOG_HAVE_TIME`, `ULOG_CUSTOM_PREFIX_SIZE`, etc.) - - New System: Unified `ULOG_BUILD_*` pattern with consistent semantics: - - `ULOG_BUILD_COLOR=1` (replaces `!ULOG_NO_COLOR`) - - `ULOG_BUILD_TIME=1` (replaces `ULOG_HAVE_TIME`) - - `ULOG_BUILD_PREFIX_SIZE=N` (replaces `ULOG_CUSTOM_PREFIX_SIZE`) - - `ULOG_BUILD_EXTRA_OUTPUTS=N` (replaces `ULOG_EXTRA_OUTPUTS`) - - `ULOG_BUILD_SOURCE_LOCATION=1` (replaces `!ULOG_HIDE_FILE_STRING`) - - `ULOG_BUILD_LEVEL_STYLE` (replaces `ULOG_SHORT_LEVEL_STRINGS`) - - `ULOG_BUILD_TOPICS_NUM=N` (replaces `ULOG_TOPICS_NUM`) - - `ULOG_BUILD_DYNAMIC_CONFIG=1` (replaces `ULOG_RUNTIME_MODE`) -- Level Constants Migration - - Old: `LOG_TRACE`, `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR`, `LOG_FATAL` - - New: `ULOG_LEVEL_TRACE`, `ULOG_LEVEL_DEBUG`, `ULOG_LEVEL_INFO`, `ULOG_LEVEL_WARN`, `ULOG_LEVEL_ERROR`, `ULOG_LEVEL_FATAL` -- Function Renaming for Consistency - - Core Functions: - - `ulog_get_level_string()` → `ulog_level_to_string()` - - `ulog_set_level()` → `ulog_output_level_set_all()` - - `ulog_set_quiet()` → `ulog_output_level_set(ULOG_OUTPUT_STDOUT, level)` - - Output Management: - - `ulog_add_callback()` → `ulog_output_add()` - - `ulog_add_fp()` → `ulog_output_add_file()` - - Configuration Functions: - - `ulog_configure_levels()` → `ulog_level_config()` - - `ulog_configure_prefix()` → `ulog_prefix_config()` - - `ulog_configure_color()` → `ulog_color_config()` - - `ulog_configure_time()` → `ulog_time_config()` - - `ulog_configure_topics()` → `ulog_topic_config()` - - `ulog_configure_file_string()` → `ulog_source_location_config()` - - Topic Functions (complete renaming): - - `ulog_add_topic()` → `ulog_topic_add()` - - `ulog_set_topic_level()` → `ulog_topic_level_set()` - - `ulog_get_topic_id()` → `ulog_topic_get_id()` - - `ulog_enable_topic()` → `ulog_topic_enable()` - - `ulog_disable_topic()` → `ulog_topic_disable()` - - `ulog_enable_all_topics()` → `ulog_topic_enable_all()` - - `ulog_disable_all_topics()` → `ulog_topic_disable_all()` - - Other Functions: - - `ulog_set_lock()` → `ulog_lock_set_fn()` - - `ulog_set_prefix_fn()` → `ulog_prefix_set_fn()` -- Type Naming Standardization - - Old: Mixed case (`ulog_Event`, `ulog_LogFn`, `ulog_LockFn`, `ulog_PrefixFn`) - - New: Consistent lowercase with underscores (`ulog_event`, `ulog_log_fn`, `ulog_lock_fn`, `ulog_prefix_fn`) -- Topic Display Format - - Old: `[Topic] LEVEL` format - - New: `LEVEL [Topic]` format for better readability -- Testing: - - Updated all test cases to use new API functions - - `test_runtime_config.cpp` → `test_dynamic_config.cpp` - - `test_custom_prefix.cpp` → `test_prefix.cpp` -- Example Application: - - Complete rewrite using new v7.0 API - - Demonstrates new output management system - - Better inline documentation - -### Removed - -- Emoji Levels: `ULOG_FEATURE_EMOJI_LEVELS` / `ULOG_USE_EMOJI` removed entirely -- Remove event from public API: Access to private data through standardized getters - - `ulog_event_get_message()` - Extract formatted message to buffer - - `ulog_event_get_topic()` - Get topic ID from event - - `ulog_event_get_time()` - Get timestamp from event - - `ulog_event_get_file()` / `ulog_event_get_line()` - Get source location - - `ulog_event_get_level()` - Get log level from event - -### Fixed - -- Prefix Execution: Fixed multiple prefix callback execution per single log call -- Topic Processing: Enhanced topic string processing and validation -- Memory Management: Improved buffer handling in print system -- Fix bugs in the `test_time.cpp` - -### Critical Migration Notes - -1. All function names changed - Use find/replace with mapping above -2. All log level constants changed - `LOG_*` → `ULOG_LEVEL_*` -3. All build defines changed - `ULOG_FEATURE_*` → `ULOG_BUILD_*` -4. Event access changed - Direct field access → getter functions -5. Output system changed - Handler registration → output management -6. Type names changed - CamelCase → snake_case diff --git a/extensions/README.md b/extensions/README.md index 4824d3a..4582fcb 100644 --- a/extensions/README.md +++ b/extensions/README.md @@ -43,6 +43,7 @@ This set of extensions provides additional logging features and integrations. | Extension | Description | Main Header | | ------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | Generic Logger Interface | Provides a generic logging interface that can simplify migration from/to other logging libraries. | [`ulog_generic_interface.h`](../extensions/ulog_generic_interface.h) | +| microlog6 Compatibility | Backward compatibility layer for code written against microlog v6.x API. | [`ulog_microlog6.h`](../extensions/ulog_microlog6.h) | ## Adding Your Own Extension diff --git a/extensions/ulog_microlog6.h b/extensions/ulog_microlog6.h new file mode 100644 index 0000000..6fc7387 --- /dev/null +++ b/extensions/ulog_microlog6.h @@ -0,0 +1,367 @@ +/* ============================================================================ + microlog extension: microlog6 Compatibility Layer + + This extension provides backward compatibility for code written against + microlog v6.x API. It maps the old API to the new v7.x API. + + Usage: + #include "ulog_microlog6.h" + + Note: Build-time configuration macros need manual mapping: + - ULOG_NO_COLOR → ULOG_BUILD_COLOR=0 + - ULOG_CUSTOM_PREFIX_SIZE → ULOG_BUILD_PREFIX_SIZE + - ULOG_HAVE_TIME → ULOG_BUILD_TIME=1 + - ULOG_USE_EMOJI → (not supported in v7.x) + - ULOG_EXTRA_OUTPUTS → ULOG_BUILD_EXTRA_OUTPUTS + - ULOG_HIDE_FILE_STRING → ULOG_BUILD_SOURCE_LOCATION=0 + - ULOG_SHORT_LEVEL_STRINGS → ULOG_BUILD_LEVEL_SHORT=1 + - ULOG_TOPICS_NUM (static) → ULOG_BUILD_TOPICS_MODE=1 + ULOG_BUILD_TOPICS_STATIC_NUM + - ULOG_TOPICS_NUM=-1 → ULOG_BUILD_TOPICS_MODE=2 + - ULOG_RUNTIME_MODE → ULOG_BUILD_DYNAMIC_CONFIG=1 +============================================================================ */ + +#pragma once + +#include "ulog.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ============================================================================ + Core: Log Level Enum Compatibility +============================================================================ */ + +// Map old log level enum to new ones (keep macro form to avoid enum mismatches) +#define LOG_TRACE ULOG_LEVEL_TRACE +#define LOG_DEBUG ULOG_LEVEL_DEBUG +#define LOG_INFO ULOG_LEVEL_INFO +#define LOG_WARN ULOG_LEVEL_WARN +#define LOG_ERROR ULOG_LEVEL_ERROR +#define LOG_FATAL ULOG_LEVEL_FATAL + +/* ============================================================================ + Core: Basic Logging Macros +============================================================================ */ + +#define log_trace(...) ulog_trace(__VA_ARGS__) +#define log_debug(...) ulog_debug(__VA_ARGS__) +#define log_info(...) ulog_info(__VA_ARGS__) +#define log_warn(...) ulog_warn(__VA_ARGS__) +#define log_error(...) ulog_error(__VA_ARGS__) +#define log_fatal(...) ulog_fatal(__VA_ARGS__) + +/* ============================================================================ + Core: Event Type Compatibility +============================================================================ */ + +// Type aliases for backward compatibility +typedef ulog_event ulog_Event; // Note: capital E in old version +typedef ulog_output_handler_fn ulog_LogFn; + +/* ============================================================================ + Core: Functions with Compatible Signatures +============================================================================ */ + +/// @brief Returns the string representation of the level (compatible) +static inline const char *ulog_get_level_string(int level) { + const char *name = ulog_level_to_string((ulog_level)level); + if (name == NULL) { + name = "?"; + } + + // If short style is active (single character), fall back to default long names + if (name[0] != '\0' && name[1] == '\0') { + switch (level) { + case LOG_TRACE: return "TRACE"; + case LOG_DEBUG: return "DEBUG"; + case LOG_INFO: return "INFO"; + case LOG_WARN: return "WARN"; + case LOG_ERROR: return "ERROR"; + case LOG_FATAL: return "FATAL"; + default: break; + } + } + return name; +} + +/// @brief Sets the debug level for all outputs +static inline void ulog_set_level(int level) { + (void)ulog_output_level_set_all((ulog_level)level); +} + +/// @brief Disables/enables logging to stdout +/// @param enable true = quiet mode (disable stdout), false = enable stdout +static inline void ulog_set_quiet(bool enable) { + if (enable) { + // Raise stdout threshold so regular logs are filtered out + (void)ulog_output_level_set(ULOG_OUTPUT_STDOUT, ULOG_LEVEL_FATAL); + } else { + // Re-enable stdout at TRACE level + (void)ulog_output_level_set(ULOG_OUTPUT_STDOUT, ULOG_LEVEL_TRACE); + } +} + +/* ============================================================================ + Feature: Lock Compatibility +============================================================================ */ + +typedef void (*ulog_LockFn)(bool lock, void *lock_arg); + +// Internal static storage for lock wrapper +static ulog_LockFn _ulog_compat_stored_lock_fn = NULL; +static void *_ulog_compat_stored_lock_arg = NULL; + +// Internal wrapper function to adapt old void return to new ulog_status return +static inline ulog_status _ulog_compat_lock_wrapper(bool lock, void *arg) { + (void)arg; // Use stored args instead + if (_ulog_compat_stored_lock_fn != NULL) { + _ulog_compat_stored_lock_fn(lock, _ulog_compat_stored_lock_arg); + } + return ULOG_STATUS_OK; +} + +/// @brief Sets the lock function (compatible wrapper) +/// Note: This uses static storage and may not work with multiple different locks +/// For production use with multiple locks, consider a more sophisticated approach +static inline void ulog_set_lock(ulog_LockFn function, void *lock_arg) { + if (function == NULL) { + _ulog_compat_stored_lock_fn = NULL; + _ulog_compat_stored_lock_arg = NULL; + ulog_lock_set_fn(NULL, NULL); + return; + } + + _ulog_compat_stored_lock_fn = function; + _ulog_compat_stored_lock_arg = lock_arg; + ulog_lock_set_fn(_ulog_compat_lock_wrapper, NULL); +} + +/* ============================================================================ + Feature: Runtime Config Compatibility +============================================================================ */ + +#if defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1 + +static inline void ulog_configure_color(bool enabled) { + (void)ulog_color_config(enabled); +} + +static inline void ulog_configure_prefix(bool enabled) { + (void)ulog_prefix_config(enabled); +} + +static inline void ulog_configure_file_string(bool enabled) { + (void)ulog_source_location_config(enabled); +} + +static inline void ulog_configure_time(bool enabled) { + (void)ulog_time_config(enabled); +} + +static inline void ulog_configure_levels(bool use_short_levels) { + if (use_short_levels) { + (void)ulog_level_config(ULOG_LEVEL_CONFIG_STYLE_SHORT); + } else { + (void)ulog_level_config(ULOG_LEVEL_CONFIG_STYLE_DEFAULT); + } +} + +static inline void ulog_configure_topics(bool enabled) { + (void)ulog_topic_config(enabled); +} + +#endif // ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Feature: Custom Prefix Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_PREFIX_SIZE) && ULOG_BUILD_PREFIX_SIZE > 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +typedef void (*ulog_PrefixFn)(ulog_Event *ev, char *prefix, size_t prefix_size); + +/// @brief Sets the prefix function (compatible wrapper) +static inline void ulog_set_prefix_fn(ulog_PrefixFn function) { + // The signatures are compatible, just cast + (void)ulog_prefix_set_fn((ulog_prefix_fn)function); +#if defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1 + (void)ulog_prefix_config(function != NULL); +#endif +} + +#endif // ULOG_BUILD_PREFIX_SIZE || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Feature: Extra Outputs Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_EXTRA_OUTPUTS) && ULOG_BUILD_EXTRA_OUTPUTS > 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +/// @brief Adds a callback (returns int for compatibility) +/// @return 0 if success, -1 if failed +static inline int ulog_add_callback(ulog_LogFn function, void *arg, int level) { + ulog_output_id id = ulog_output_add(function, arg, (ulog_level)level); + return (id == ULOG_OUTPUT_INVALID) ? -1 : 0; +} + +/// @brief Add file callback (returns int for compatibility) +/// @return 0 if success, -1 if failed +static inline int ulog_add_fp(FILE *fp, int level) { + ulog_output_id id = ulog_output_add_file(fp, (ulog_level)level); + return (id == ULOG_OUTPUT_INVALID) ? -1 : 0; +} + +#endif // ULOG_BUILD_EXTRA_OUTPUTS || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Feature: Topics Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_TOPICS_MODE) && ULOG_BUILD_TOPICS_MODE != 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +// Topic macros using old naming convention +#define TOPIC_NOT_FOUND ULOG_TOPIC_ID_INVALID + +#define logt_trace(TOPIC_NAME, ...) ulog_topic_trace(TOPIC_NAME, __VA_ARGS__) +#define logt_debug(TOPIC_NAME, ...) ulog_topic_debug(TOPIC_NAME, __VA_ARGS__) +#define logt_info(TOPIC_NAME, ...) ulog_topic_info(TOPIC_NAME, __VA_ARGS__) +#define logt_warn(TOPIC_NAME, ...) ulog_topic_warn(TOPIC_NAME, __VA_ARGS__) +#define logt_error(TOPIC_NAME, ...) ulog_topic_error(TOPIC_NAME, __VA_ARGS__) +#define logt_fatal(TOPIC_NAME, ...) ulog_topic_fatal(TOPIC_NAME, __VA_ARGS__) + +/// @brief Adds a topic (compatible with old API) +/// @param topic_name Topic name +/// @param enable true to enable topic, false to disable +/// @return Topic ID if success, -1 if failed +static inline int ulog_add_topic(const char *topic_name, bool enable) { + if (topic_name == NULL || topic_name[0] == '\0') { + return -1; + } + + ulog_topic_id id = ulog_topic_add(topic_name, ULOG_OUTPUT_ALL, ULOG_LEVEL_TRACE); + if (id == ULOG_TOPIC_ID_INVALID) { + return -1; + } + + if (!enable) { + ulog_status status = ulog_topic_level_set(topic_name, ULOG_LEVEL_FATAL); + if (status != ULOG_STATUS_OK) { + return -1; + } + } + return (int)id; +} + +/// @brief Sets the debug level of a given topic (returns int for compatibility) +/// @return 0 if success, -1 if failed +static inline int ulog_set_topic_level(const char *topic_name, int level) { + ulog_status status = ulog_topic_level_set(topic_name, (ulog_level)level); + return (status == ULOG_STATUS_OK) ? 0 : -1; +} + +/// @brief Gets the topic ID (compatible) +/// @return Topic ID if success, -1 if failed, TOPIC_NOT_FOUND if not found +static inline int ulog_get_topic_id(const char *topic_name) { + return (int)ulog_topic_get_id(topic_name); +} + +/// @brief Enables the topic (sets level to TRACE) +/// @return 0 if success, -1 if failed +static inline int ulog_enable_topic(const char *topic_name) { + ulog_status status = ulog_topic_level_set(topic_name, ULOG_LEVEL_TRACE); + return (status == ULOG_STATUS_OK) ? 0 : -1; +} + +/// @brief Disables the topic (sets level to highest severity) +/// @return 0 if success, -1 if failed +static inline int ulog_disable_topic(const char *topic_name) { + ulog_status status = ulog_topic_level_set(topic_name, ULOG_LEVEL_FATAL); + return (status == ULOG_STATUS_OK) ? 0 : -1; +} + +/// @brief Enables all topics +/// Note: In v7.x, there's no direct API for this. This is a simplified version +/// that only works if you track your topics externally +/// @return 0 (always succeeds in this simple implementation) +static inline int ulog_enable_all_topics(void) { + // v7.x doesn't provide an iterate-all-topics API + // Users must track topics if they need this functionality + // This is a limitation of the compatibility layer + return 0; // Return success but note this is incomplete +} + +/// @brief Disables all topics +/// Note: Same limitation as ulog_enable_all_topics +/// @return 0 (always succeeds in this simple implementation) +static inline int ulog_disable_all_topics(void) { + // Same limitation as enable_all_topics + return 0; // Return success but note this is incomplete +} + +#endif // ULOG_BUILD_TOPICS_MODE || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Feature Flags Compatibility (read-only) +============================================================================ */ + +// Map old feature flags to new build configuration checks +#if defined(ULOG_BUILD_COLOR) && ULOG_BUILD_COLOR == 1 + #define ULOG_FEATURE_COLOR true +#else + #define ULOG_FEATURE_COLOR false +#endif + +#if defined(ULOG_BUILD_PREFIX_SIZE) && ULOG_BUILD_PREFIX_SIZE > 0 + #define ULOG_FEATURE_CUSTOM_PREFIX true +#else + #define ULOG_FEATURE_CUSTOM_PREFIX false +#endif + +#if defined(ULOG_BUILD_TIME) && ULOG_BUILD_TIME == 1 + #define ULOG_FEATURE_TIME true +#else + #define ULOG_FEATURE_TIME false +#endif + +#if defined(ULOG_BUILD_EXTRA_OUTPUTS) && ULOG_BUILD_EXTRA_OUTPUTS > 0 + #define ULOG_FEATURE_EXTRA_OUTPUTS true +#else + #define ULOG_FEATURE_EXTRA_OUTPUTS false +#endif + +#if defined(ULOG_BUILD_SOURCE_LOCATION) && ULOG_BUILD_SOURCE_LOCATION == 1 + #define ULOG_FEATURE_FILE_STRING true +#elif defined(ULOG_BUILD_SOURCE_LOCATION) && ULOG_BUILD_SOURCE_LOCATION == 0 + #define ULOG_FEATURE_FILE_STRING false +#else + #define ULOG_FEATURE_FILE_STRING true // Default is enabled in v7.x +#endif + +#if defined(ULOG_BUILD_LEVEL_SHORT) && ULOG_BUILD_LEVEL_SHORT == 1 + #define ULOG_FEATURE_SHORT_LEVELS true +#else + #define ULOG_FEATURE_SHORT_LEVELS false +#endif + +#if defined(ULOG_BUILD_TOPICS_MODE) && ULOG_BUILD_TOPICS_MODE != 0 + #define ULOG_FEATURE_TOPICS true +#else + #define ULOG_FEATURE_TOPICS false +#endif + +#if defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1 + #define ULOG_FEATURE_RUNTIME_MODE true +#else + #define ULOG_FEATURE_RUNTIME_MODE false +#endif + +// Note: ULOG_FEATURE_EMOJI_LEVELS is not supported in v7.x +#define ULOG_FEATURE_EMOJI_LEVELS false + +#ifdef __cplusplus +} +#endif diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 291298b..9b5750b 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -181,3 +181,12 @@ target_sources(test_disabled PRIVATE test_disabled.cpp) # No ulog.c source when target_include_directories(test_disabled PRIVATE ${ULOG_INCLUDE_DIR}) target_compile_definitions(test_disabled PRIVATE "-DULOG_BUILD_DISABLED=1") add_test(NAME DisabledFeatureTest COMMAND test_disabled) + +# --- microlog6 Compatibility Test --- +add_executable(test_microlog6_compat) +target_sources(test_microlog6_compat PRIVATE ${ULOG_SRC} + ut_callback.c + test_microlog6_compat.cpp) +target_include_directories(test_microlog6_compat PRIVATE ${ULOG_INCLUDE_DIR}) +target_compile_definitions(test_microlog6_compat PRIVATE ${ULOG_CONFIG_TEST_DYNAMIC_CONFIG}) +add_test(NAME Microlog6CompatTest COMMAND test_microlog6_compat) diff --git a/tests/unit/test_event_getters.cpp b/tests/unit/test_event_getters.cpp index 92814bf..acb62b2 100644 --- a/tests/unit/test_event_getters.cpp +++ b/tests/unit/test_event_getters.cpp @@ -255,8 +255,13 @@ TEST_CASE_FIXTURE(EventGettersTestFixture, "Event Getters with Complex Log") { REQUIRE(topic_id != ULOG_TOPIC_ID_INVALID); #endif + #if ULOG_HAS_TIME time_t before_log = time(nullptr); + #endif + + #if ULOG_HAS_SOURCE_LOCATION int test_line = __LINE__ + 4; + #endif reset_event_capture(); #if ULOG_HAS_TOPICS @@ -264,7 +269,9 @@ TEST_CASE_FIXTURE(EventGettersTestFixture, "Event Getters with Complex Log") { #else ulog_warn("Complex message with number %d and string %s", 123, "abc"); #endif + #if ULOG_HAS_TIME time_t after_log = time(nullptr); + #endif REQUIRE(event_captured); diff --git a/tests/unit/test_microlog6_compat.cpp b/tests/unit/test_microlog6_compat.cpp new file mode 100644 index 0000000..a65275d --- /dev/null +++ b/tests/unit/test_microlog6_compat.cpp @@ -0,0 +1,512 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest/doctest.h" + +#include +#include "ulog.h" +#include "../../extensions/ulog_microlog6.h" +#include "ut_callback.h" + +struct TestFixture { + public: + TestFixture() { + // Per-test setup + // Note: We add the callback every time since ulog_cleanup() removes it + ulog_output_add(ut_callback, nullptr, ULOG_LEVEL_TRACE); + ulog_output_level_set_all(ULOG_LEVEL_TRACE); + ut_callback_reset(); + } + + ~TestFixture() { + // Cleanup after each test + ulog_cleanup(); + } +}; + +/* ============================================================================ + Test: Log Level Enum Compatibility +============================================================================ */ + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Log level enum values") { + CHECK(LOG_TRACE == ULOG_LEVEL_TRACE); + CHECK(LOG_DEBUG == ULOG_LEVEL_DEBUG); + CHECK(LOG_INFO == ULOG_LEVEL_INFO); + CHECK(LOG_WARN == ULOG_LEVEL_WARN); + CHECK(LOG_ERROR == ULOG_LEVEL_ERROR); + CHECK(LOG_FATAL == ULOG_LEVEL_FATAL); +} + +/* ============================================================================ + Test: Basic Logging Macros +============================================================================ */ + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Basic logging macros") { + log_trace("trace message"); + CHECK(ut_callback_get_message_count() == 1); + CHECK(strstr(ut_callback_get_last_message(), "trace message") != nullptr); + + log_debug("debug message"); + CHECK(ut_callback_get_message_count() == 2); + CHECK(strstr(ut_callback_get_last_message(), "debug message") != nullptr); + + log_info("info message"); + CHECK(ut_callback_get_message_count() == 3); + CHECK(strstr(ut_callback_get_last_message(), "info message") != nullptr); + + log_warn("warn message"); + CHECK(ut_callback_get_message_count() == 4); + CHECK(strstr(ut_callback_get_last_message(), "warn message") != nullptr); + + log_error("error message"); + CHECK(ut_callback_get_message_count() == 5); + CHECK(strstr(ut_callback_get_last_message(), "error message") != nullptr); + + log_fatal("fatal message"); + CHECK(ut_callback_get_message_count() == 6); + CHECK(strstr(ut_callback_get_last_message(), "fatal message") != nullptr); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Logging with format strings") { + log_info("Hello %s", "world"); + CHECK(ut_callback_get_message_count() == 1); + CHECK(strstr(ut_callback_get_last_message(), "Hello world") != nullptr); + + log_debug("Number: %d", 42); + CHECK(ut_callback_get_message_count() == 2); + CHECK(strstr(ut_callback_get_last_message(), "Number: 42") != nullptr); + + log_error("Float: %.2f", 3.14); + CHECK(ut_callback_get_message_count() == 3); + CHECK(strstr(ut_callback_get_last_message(), "Float: 3.14") != nullptr); +} + +/* ============================================================================ + Test: Type Aliases +============================================================================ */ + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Type aliases") { + // Test that ulog_Event is an alias for ulog_event + // This is a compile-time check - if it compiles, the alias works + ulog_Event *ev_ptr = nullptr; + (void)ev_ptr; // Suppress unused variable warning + + // Test that ulog_LogFn is an alias for ulog_output_handler_fn + ulog_LogFn fn_ptr = nullptr; + (void)fn_ptr; +} + +/* ============================================================================ + Test: Core Functions +============================================================================ */ + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_get_level_string") { + CHECK(strcmp(ulog_get_level_string(LOG_TRACE), "TRACE") == 0); + CHECK(strcmp(ulog_get_level_string(LOG_DEBUG), "DEBUG") == 0); + CHECK(strcmp(ulog_get_level_string(LOG_INFO), "INFO ") == 0); + CHECK(strcmp(ulog_get_level_string(LOG_WARN), "WARN ") == 0); + CHECK(strcmp(ulog_get_level_string(LOG_ERROR), "ERROR") == 0); + CHECK(strcmp(ulog_get_level_string(LOG_FATAL), "FATAL") == 0); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_set_level") { + ulog_set_level(LOG_INFO); + + log_trace("Should not appear"); + CHECK(ut_callback_get_message_count() == 0); + + log_debug("Should not appear"); + CHECK(ut_callback_get_message_count() == 0); + + log_info("Should appear"); + CHECK(ut_callback_get_message_count() == 1); + + log_warn("Should appear"); + CHECK(ut_callback_get_message_count() == 2); + + log_error("Should appear"); + CHECK(ut_callback_get_message_count() == 3); + + log_fatal("Should appear"); + CHECK(ut_callback_get_message_count() == 4); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_set_quiet") { + // Note: This test assumes ULOG_OUTPUT_STDOUT is used + // We're testing the wrapper logic, not actual stdout suppression + + ulog_set_quiet(true); + // After setting quiet mode, stdout should be at a very high level + // We can't directly test stdout, but we can verify the callback still works + log_info("This goes to callback"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_set_quiet(false); + // After disabling quiet mode, stdout should be re-enabled + log_info("This also goes to callback"); + CHECK(ut_callback_get_message_count() == 2); +} + +/* ============================================================================ + Test: Lock Compatibility +============================================================================ */ + +static bool lock_called = false; +static bool lock_acquired = false; + +static void test_lock_fn(bool lock, void *arg) { + lock_called = true; + lock_acquired = lock; + (void)arg; +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_set_lock") { + lock_called = false; + lock_acquired = false; + + ulog_set_lock(test_lock_fn, nullptr); + + // Trigger a log to invoke the lock + log_info("Test message"); + + // The lock should have been called + CHECK(lock_called == true); +} + +/* ============================================================================ + Test: Extra Outputs Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_EXTRA_OUTPUTS) && ULOG_BUILD_EXTRA_OUTPUTS > 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +static int custom_callback_count = 0; +static void custom_callback(ulog_Event *ev, void *arg) { + custom_callback_count++; + (void)ev; + (void)arg; +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_add_callback") { + custom_callback_count = 0; + + int result = ulog_add_callback(custom_callback, nullptr, LOG_INFO); + CHECK(result == 0); // Should return 0 on success + + log_info("Test message"); + CHECK(custom_callback_count == 1); + + log_warn("Another message"); + CHECK(custom_callback_count == 2); + + // Test that it respects the level + log_debug("Should not appear"); + CHECK(custom_callback_count == 2); // Count should not increase +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_add_fp") { + const char *filename = "test_microlog6_compat.log"; + FILE *fp = fopen(filename, "w"); + REQUIRE(fp != nullptr); + + int result = ulog_add_fp(fp, LOG_INFO); + CHECK(result == 0); // Should return 0 on success + + log_info("Test file message"); + fclose(fp); + + // Verify the file contains the message + fp = fopen(filename, "r"); + REQUIRE(fp != nullptr); + + char buffer[256]; + fgets(buffer, sizeof(buffer), fp); + fclose(fp); + + CHECK(strstr(buffer, "Test file message") != nullptr); +} + +#endif // ULOG_BUILD_EXTRA_OUTPUTS || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Test: Topics Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_TOPICS_MODE) && ULOG_BUILD_TOPICS_MODE != 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: TOPIC_NOT_FOUND constant") { + CHECK(TOPIC_NOT_FOUND == ULOG_TOPIC_ID_INVALID); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Topic logging macros") { + ulog_add_topic("test_topic", true); // Enable the topic + + logt_trace("test_topic", "trace topic message"); + CHECK(ut_callback_get_message_count() == 1); + CHECK(strstr(ut_callback_get_last_message(), "trace topic message") != nullptr); + + logt_debug("test_topic", "debug topic message"); + CHECK(ut_callback_get_message_count() == 2); + + logt_info("test_topic", "info topic message"); + CHECK(ut_callback_get_message_count() == 3); + + logt_warn("test_topic", "warn topic message"); + CHECK(ut_callback_get_message_count() == 4); + + logt_error("test_topic", "error topic message"); + CHECK(ut_callback_get_message_count() == 5); + + logt_fatal("test_topic", "fatal topic message"); + CHECK(ut_callback_get_message_count() == 6); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_add_topic") { + // Test adding enabled topic + int id1 = ulog_add_topic("enabled_topic", true); + CHECK(id1 >= 0); // Should return valid ID + + logt_info("enabled_topic", "Should appear"); + CHECK(ut_callback_get_message_count() == 1); + + // Test adding disabled topic + int id2 = ulog_add_topic("disabled_topic", false); + CHECK(id2 >= 0); // Should return valid ID + + logt_info("disabled_topic", "Should not appear"); + CHECK(ut_callback_get_message_count() == 1); // Count unchanged + + // Test adding topic with NULL name + int id_invalid = ulog_add_topic(nullptr, true); + CHECK(id_invalid == -1); // Should fail +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_set_topic_level") { + ulog_add_topic("level_topic", true); + + // Set topic to INFO level + int result = ulog_set_topic_level("level_topic", LOG_INFO); + CHECK(result == 0); + + logt_debug("level_topic", "Should not appear"); + CHECK(ut_callback_get_message_count() == 0); + + logt_info("level_topic", "Should appear"); + CHECK(ut_callback_get_message_count() == 1); + + logt_error("level_topic", "Should appear"); + CHECK(ut_callback_get_message_count() == 2); + + // Test with non-existent topic + result = ulog_set_topic_level("nonexistent", LOG_INFO); + CHECK(result == -1); // Should fail +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_get_topic_id") { + int id = ulog_add_topic("id_test_topic", true); + CHECK(id >= 0); + + int retrieved_id = ulog_get_topic_id("id_test_topic"); + CHECK(retrieved_id == id); + + // Test with non-existent topic + int invalid_id = ulog_get_topic_id("nonexistent_topic"); + CHECK(invalid_id == TOPIC_NOT_FOUND); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_enable_topic") { + ulog_add_topic("enable_test", false); // Start disabled + + logt_info("enable_test", "Should not appear"); + CHECK(ut_callback_get_message_count() == 0); + + int result = ulog_enable_topic("enable_test"); + CHECK(result == 0); + + logt_info("enable_test", "Should appear"); + CHECK(ut_callback_get_message_count() == 1); + + // Test with non-existent topic + result = ulog_enable_topic("nonexistent"); + CHECK(result == -1); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_disable_topic") { + ulog_add_topic("disable_test", true); // Start enabled + + logt_info("disable_test", "Should appear"); + CHECK(ut_callback_get_message_count() == 1); + + int result = ulog_disable_topic("disable_test"); + CHECK(result == 0); + + logt_info("disable_test", "Should not appear"); + CHECK(ut_callback_get_message_count() == 1); // Count unchanged + + // Test with non-existent topic + result = ulog_disable_topic("nonexistent"); + CHECK(result == -1); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_enable_all_topics") { + // Note: This is a simplified implementation that always returns 0 + int result = ulog_enable_all_topics(); + CHECK(result == 0); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_disable_all_topics") { + // Note: This is a simplified implementation that always returns 0 + int result = ulog_disable_all_topics(); + CHECK(result == 0); +} + +#endif // ULOG_BUILD_TOPICS_MODE || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Test: Runtime Config Compatibility +============================================================================ */ + +#if defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1 + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_color") { + // Just test that the function can be called without error + ulog_configure_color(true); + log_info("Color enabled"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_color(false); + log_info("Color disabled"); + CHECK(ut_callback_get_message_count() == 2); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_prefix") { + ulog_configure_prefix(true); + log_info("Prefix enabled"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_prefix(false); + log_info("Prefix disabled"); + CHECK(ut_callback_get_message_count() == 2); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_file_string") { + ulog_configure_file_string(true); + log_info("File string enabled"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_file_string(false); + log_info("File string disabled"); + CHECK(ut_callback_get_message_count() == 2); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_time") { + ulog_configure_time(true); + log_info("Time enabled"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_time(false); + log_info("Time disabled"); + CHECK(ut_callback_get_message_count() == 2); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_levels") { + ulog_configure_levels(true); // Short levels + log_info("Short levels"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_levels(false); // Long levels + log_info("Long levels"); + CHECK(ut_callback_get_message_count() == 2); +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_configure_topics") { + ulog_configure_topics(true); + log_info("Topics enabled"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_configure_topics(false); + log_info("Topics disabled"); + CHECK(ut_callback_get_message_count() == 2); +} + +#endif // ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Test: Custom Prefix Compatibility +============================================================================ */ + +#if (defined(ULOG_BUILD_PREFIX_SIZE) && ULOG_BUILD_PREFIX_SIZE > 0) || \ + (defined(ULOG_BUILD_DYNAMIC_CONFIG) && ULOG_BUILD_DYNAMIC_CONFIG == 1) + +static void test_prefix_fn(ulog_Event *ev, char *prefix, size_t prefix_size) { + snprintf(prefix, prefix_size, "[PREFIX] "); + (void)ev; +} + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: ulog_set_prefix_fn") { + ulog_set_prefix_fn(test_prefix_fn); + + log_info("Test with prefix"); + CHECK(ut_callback_get_message_count() == 1); + CHECK(strstr(ut_callback_get_last_message(), "[PREFIX]") != nullptr); +} + +#endif // ULOG_BUILD_PREFIX_SIZE || ULOG_BUILD_DYNAMIC_CONFIG + +/* ============================================================================ + Test: Feature Flags +============================================================================ */ + +TEST_CASE("microlog6_compat: Feature flags are defined") { + // Just verify that the feature flags are defined + // Their values depend on build configuration + bool color = ULOG_FEATURE_COLOR; + bool prefix = ULOG_FEATURE_CUSTOM_PREFIX; + bool time = ULOG_FEATURE_TIME; + bool extra = ULOG_FEATURE_EXTRA_OUTPUTS; + bool file = ULOG_FEATURE_FILE_STRING; + bool short_levels = ULOG_FEATURE_SHORT_LEVELS; + bool topics = ULOG_FEATURE_TOPICS; + bool runtime = ULOG_FEATURE_RUNTIME_MODE; + bool emoji = ULOG_FEATURE_EMOJI_LEVELS; + + (void)color; + (void)prefix; + (void)time; + (void)extra; + (void)file; + (void)short_levels; + (void)topics; + (void)runtime; + (void)emoji; + + // Emoji should always be false in v7.x + CHECK(ULOG_FEATURE_EMOJI_LEVELS == false); +} + +/* ============================================================================ + Test: Integration - Mixed old and new API +============================================================================ */ + +TEST_CASE_FIXTURE(TestFixture, "microlog6_compat: Mix old and new API") { + // Test that old and new API can be used together + log_info("Old API message"); + CHECK(ut_callback_get_message_count() == 1); + + ulog_info("New API message"); + CHECK(ut_callback_get_message_count() == 2); + + // Set level using old API + ulog_set_level(LOG_WARN); + + log_debug("Should not appear (old API)"); + CHECK(ut_callback_get_message_count() == 2); + + ulog_debug("Should not appear (new API)"); + CHECK(ut_callback_get_message_count() == 2); + + log_error("Should appear (old API)"); + CHECK(ut_callback_get_message_count() == 3); + + ulog_error("Should appear (new API)"); + CHECK(ut_callback_get_message_count() == 4); +} diff --git a/tests/unit/test_output.cpp b/tests/unit/test_output.cpp index 6f68a81..44d4997 100644 --- a/tests/unit/test_output.cpp +++ b/tests/unit/test_output.cpp @@ -419,7 +419,12 @@ TEST_CASE_FIXTURE(OutputTestFixture, "Output Integration") { // Should have added at least one output CHECK(successful_additions > 0); - + + // Cleanup explicitly remove outputs we added + for (int i = 0; i < successful_additions; i++) { + ulog_output_remove(outputs[i]); + } + // Cleanup ulog_cleanup(); } diff --git a/version b/version index 53f71e5..66ce77b 100644 --- a/version +++ b/version @@ -1 +1 @@ -7.0.0-beta.2 +7.0.0