{"id":24503962,"url":"https://github.com/fcf-framework/fcftest","last_synced_at":"2026-06-13T01:02:57.519Z","repository":{"id":273465296,"uuid":"919802462","full_name":"fcf-framework/fcfTest","owner":"fcf-framework","description":"Provides the FCF_TEST macro to perform the check in unit tests","archived":false,"fork":false,"pushed_at":"2025-01-21T03:56:16.000Z","size":6,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-15T08:25:39.471Z","etag":null,"topics":["cpp","unittest"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fcf-framework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-21T03:28:01.000Z","updated_at":"2025-01-21T04:13:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"a471d912-fbca-46c1-aebf-3f243467dc5c","html_url":"https://github.com/fcf-framework/fcfTest","commit_stats":null,"previous_names":["fcf-framework/fcftest"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fcf-framework/fcfTest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fcf-framework%2FfcfTest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fcf-framework%2FfcfTest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fcf-framework%2FfcfTest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fcf-framework%2FfcfTest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fcf-framework","download_url":"https://codeload.github.com/fcf-framework/fcfTest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fcf-framework%2FfcfTest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270702562,"owners_count":24630877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","unittest"],"created_at":"2025-01-21T23:19:16.109Z","updated_at":"2026-06-13T01:02:57.509Z","avatar_url":"https://github.com/fcf-framework.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fcfTest\n\n**fcfTest** is a lightweight, header-only unit testing framework for C++. It provides a simple macro, FCF_TEST, which implements all possible checks and displays the current values ​​of variables. The framework also includes test registration, command-line execution, a built-in simple logger, and tools for measuring execution time.\n\nThe library is distributed as a single header file: `fcfTest/test.hpp`.\n\nTo use the library, you must define the `FCF_TEST_IMPLEMENTATION` macro before including the header file in your application's main cpp file to avoid errors due to multiple definitions.\n\n### Liniks:\n(New section of the site dedicated to the description of this library.)\n\nOfficial page with documentation: https://fcf-framework.is-a-fullstack.dev/cpp-libraries/fcfTest \n\nUsage article on dev.to: https://dev.to/vladimirm/fcftest-unit-test-library-3cgg\n\n### Friendly:\nIf something doesn't work for you, please report it quickly in Issues and we'll fix it!\n\n## Quick Start Example\n\n```c++\n#define FCF_TEST_IMPLEMENTATION\n#include \u003cfcfTest/test.hpp\u003e\n#include \u003cvector\u003e\n\n// Declare a test case\nFCF_TEST_DECLARE(\"MyLibraryPartName\", \"ExamplesGroupName\", \"VectorSizeTestName\"){\n  std::vector\u003cstd::string\u003e vec;\n  vec.push_back(\"test\");\n\n  // Perform an assertion. If false, throws std::runtime_error with details.\n  FCF_TEST(vec.size() == 2, vec.size());\n}\n\nint main(int a_argc, char* a_argv[]){\n  // Run the test suite via command line interface\n  bool error;\n  fcf::NTest::cmdRun(a_argc, a_argv, fcf::NTest::CRM_RUN, \u0026error);\n  return error ? 1 : 0;\n}\n```\n\n**Output:**\nThe program will execute the registered tests. If an assertion fails, it prints a descriptive error including file, line number and variable values. If successful, it prints a summary count of completed tests.\n\n ```stdout\nPerforming the test: \"MyLibraryPartName\" -\u003e \"ExamplesGroupName\" -\u003e \"VectorSizeTestName\" ...\nTest error: vec.size() == 2  [FILE: DIR_PATH/main.cpp:9]\n  Values:\n    vec.size(): 1\n```\n\n## Core Macros\n\n### `FCF_TEST_IMPLEMENTATION`\n\nThis macro is used to enable the implementation section within the header file `fcfTest/test.hpp`.\n- **Usage**: Must be defined (`#define FCF_TEST_IMPLEMENTATION`) before including the header if you want to use the library's functionality (e.g., running tests, using the logger).\n- **Purpose**: Prevents multiple definition errors by ensuring that global variables and function definitions are only generated once per compilation unit. When omitted, the header provides only declarations.\n\n### `FCF_TEST_EXPORT`\n\nThis macro is used to export symbols from the test library when building it as a DLL or shared library.\n- **Usage**: Defined by the main FCF library macros (`FCF_EXPORT`) if applicable, otherwise empty.\n- **Purpose**: Ensures consistent symbol visibility for functions and variables defined in `fcfTest` when compiled as a DLL.\n\n### `FCF_TEST_IMPORT`\n\nThis macro is used to import symbols from the test library when using it as a client application linking against a shared library.\n- **Usage**: Defined by the main FCF library macros (`FCF_IMPORT`) if applicable, otherwise empty.\n- **Purpose**: Ensures consistent symbol visibility for functions and variables defined in external shared libraries when they are imported into the client process without multiple definition errors.\n\n### `FCF_TEST`\n\nThe primary macro for performing checks in unit tests.\n- **Behavior**: Evaluates `(a_expression)`. If the result is false (non-zero), it throws a `std::runtime_error`.\n- **Error Message**: The exception message includes:\n  - The failing expression (`#exp`).\n  - The file name and line number where the macro was called.\n  - Values of all additional arguments provided in `a_observedVariables`.\n\n**Example:**\n```c++\nint x = 5;\nFCF_TEST(x == 4, x);\n// Throws error: Test error: x == 4 [FILE: main.cpp:10]\n// Values:\n//    x: 5\n```\n\n## Testing Organization Macros\n\nTests are organized hierarchically into Parts, Groups, and Tests. This allows for filtering execution based on these levels.\n\n### `FCF_TEST_DECLARE(am_part, am_group, am_test)`\n\nDeclares a new test case.\n- **Parameters**:\n  - `am_part`: The name of the part (logical grouping level).\n  - `am_group`: The name of the group (sub-grouping level).\n  - `am_test`: The unique identifier of the test function.\n- **Usage**: This macro generates a static anonymous class that registers the test with the global storage upon instantiation.\n\n**Example:**\n```c++\nFCF_TEST_DECLARE(\"Network\", \"HTTP\", \"GetRequestTest\") {\n    // Test implementation\n}\nFCF_TEST_DECLARE(\"Network\", \"HTTP\", \"PostRequestTest\") {\n    // Test implementation\n}\n```\n\n### `FCF_TEST_PART_ORDER(am_part, am_order)`\n\nRegisters the execution order for a specific part.\n- **Parameters**:\n  - `am_part`: Name of the part.\n  - `am_order`: Integer priority (lower values run first).\n\n**Example:**\n```c++\nFCF_TEST_PART_ORDER(\"CriticalTests\", 1); // Run critical tests first\nFCF_TEST_PART_ORDER(\"GeneralTests\", 2);\n```\n\n### `FCF_TEST_GROUP_ORDER(am_group, am_order)`\n\nRegisters the execution order for a specific group within a part.\n- **Parameters**:\n  - `am_group`: Name of the group.\n  - `am_order`: Integer priority.\n\n**Example:**\n```c++\nFCF_TEST_GROUP_ORDER(\"Integration\", 1);\nFCF_TEST_GROUP_ORDER(\"Unit\", 2);\n```\n\n### `FCF_TEST_TEST_ORDER(am_test, am_order)`\n\nRegisters the execution order for a specific test within a group.\n- **Parameters**:\n  - `am_test`: Name of the test.\n  - `am_order`: Integer priority.\n\n**Example:**\n```c++\nFCF_TEST_TEST_ORDER(\"SmokeTest\", 1);\nFCF_TEST_TEST_ORDER(\"LoadTest\", 2);\n```\n\n## Global Logging Functions\n\nThe library provides global shortcuts to access streams based on log levels. These are defined in the `fcf::NTest` namespace and also available globally if included directly or via specific exports.\n\n### `ftl()`, `err()`, `wrn()`, `att()`, `log()`, `inf()`, `dbg()`, `trc()`\n\nThese functions return references to output streams (`std::ostream\u0026`) corresponding to specific log levels:\n- `ftl()`: Fatal level.\n- `err()`: Error level.\n- `wrn()`: Warning level.\n- `att()`: Attention level.\n- `log()`: Log level (default).\n- `inf()`: Information level.\n- `dbg()`: Debug level.\n- `trc()`: Trace level.\n\nIf the global logger's level is set lower than the requested level, these return a reference to an empty stream buffer (no output).\n\n**Example:**\n```c++\nfcf::NTest::ftl() \u003c\u003c \"This will only appear if log level is FTL or higher\" \u003c\u003c std::endl;\nfcf::NTest::dbg() \u003c\u003c \"This appears only in debug mode\" \u003c\u003c std::endl;\n```\n\n## Benchmarking: `Duration` Class\n\nThe `fcf::NTest::Duration` class provides a simple interface for measuring the execution time of code blocks. It uses `std::chrono::high_resolution_clock`.\n\n### Members and Methods\n- **Constructor**: `Duration(unsigned long long a_iterations)`\n  - **Parameters**:\n    - `a_iterations`: The number of times the enclosed functor will be executed.\n- **Default Constructor**: `Duration()`\n  - Sets the number of iterations to 1.\n- **Methods**:\n  - `unsigned long long iterationCount()`: Returns the number of iterations set for this duration.\n  - `void begin()`: Records the start time for timing.\n  - `void end()`: Records the end time for timing.\n  - `std::chrono::nanoseconds totalDuration()`: Returns the total duration of all iterations in nanoseconds.\n  - `std::chrono::nanoseconds duration()`: Returns the average duration of a single iteration in nanoseconds.\n  - `void operator()(TFunctor\u0026\u0026 a_functor)`: Executes a functor multiple times and measures the total duration.\n    - **Parameters**:\n      - `a_functor`: The callable object to execute.\n\n**Example:**\n```c++\n// Measure sorting 1000 times\nfcf::NTest::Duration bench(1000);\nbench([](){\n    std::vector\u003cint\u003e v = {5, 2, 9};\n    std::sort(v.begin(), v.end());\n});\n\nstd::cout \u003c\u003c \"Total: \" \u003c\u003c bench.totalDuration().count() \u003c\u003c \" ns\\n\";\nstd::cout \u003c\u003c \"Avg: \" \u003c\u003c bench.duration().count() \u003c\u003c \" ns\\n\";\n```\n\n## Command Line Interface\n\nThe test runner supports filtering tests by Part, Group, or specific Test name, and setting the global log level. It uses a command-line argument parser implemented in `cmdRun`.\n\n### The `Options` Structure\n\nThis structure holds the configuration for running tests. It is populated automatically by the command line parser but can be used manually.\n\n```c++\nstruct Options {\n  std::vector\u003cstd::string\u003e parts;         ///\u003c List of part names to run (empty means all).\n  std::vector\u003cstd::string\u003e groups;        ///\u003c List of group names to run (empty means all).\n  std::vector\u003cstd::string\u003e tests;         ///\u003c List of specific test names to run (empty means all).\n  std::vector\u003cstd::string\u003e ignoreParts;   ///\u003c List of ignore part names.\n  std::vector\u003cstd::string\u003e ignoreGroups;  ///\u003c List of ignore group names to run.\n  std::vector\u003cstd::string\u003e ignoreTests;   ///\u003c List of ignore specific test names to run.\n  ELogLevel                logLevel;      ///\u003c Desired logging level.\n};\n```\n\n### The `cmdRun` Function\n\nThe central function for executing the test suite. It parses command-line arguments and determines the action.\n\n**`ECmdMode cmdRun(Options\u0026 a_dstOptions, int a_argc, const char* const* a_argv, ECmdRunMode a_runMode, bool* a_errorPtr = 0)`**\n\nParses command line arguments and executes the appropriate action.\n\n- **Parameters**:\n  - `a_dstOptions`: Reference to the `Options` structure to populate with parsed arguments.\n  - `a_argc`: Number of command line arguments.\n  - `a_argv`: Array of argument strings.\n  - `a_runMode`: Current mode of execution (`CRM_PARSE`, `CRM_EXECUTE`, or `CRM_RUN`).\n  - `a_errorPtr`: A pointer to a variable that receives information about a test error. If an error occurs, the value is set to true. If a null pointer is passed, the function throws an exception.\n- **Returns**: `ECmdMode` returns the selected mode based on the parameters of the command line a_argv.\n\n#### `ECmdMode` Enum\n\nDefines the mode of operation for the command line parser:\n- **`CM_NONE`**: No specific mode was set.\n- **`CM_RUN`**: The `--test-run` flag was detected.\n- **`CM_LIST`**: The `--test-list` flag was detected.\n- **`CM_HELP`**: The `--test-help` flag was detected.\n\n\n#### `ECmdRunMode` Enum\n\nThis enum dictates how `cmdRun` behaves during parsing:\n\n- **`CRM_PARSE`**: Parses arguments but **does not** execute tests or show help/list. Returns the determined mode (e.g., `CM_HELP`, `CM_LIST`) so the caller can decide what to do next.\n- **`CRM_EXECUTE`**: Parses arguments. If the flag `--test-run` was provided, it executes tests. If `--test-help` or `--test-list` were provided, it displays that information immediately and returns.\n- **`CRM_RUN`**: Parses arguments and **automatically executes** tests unless `--test-help` or `--test-list` was explicitly requested.\n\n#### Usage Examples\n\n```c++\nint main(int a_argc, char* a_argv[]) {\n    // Standard execution: Parse and run.\n    bool error = false;\n    fcf::NTest::cmdRun(a_argc, a_argv, fcf::NTest::CRM_RUN, \u0026error);\n    return error ? 1 : 0;\n}\n```\n\n```c++\nint main(int a_argc, char* a_argv[]) {\n    // Standard execution: Parse and run by request.\n    bool error = false;\n    int mode = fcf::NTest::cmdRun(a_argc, a_argv, fcf::NTest::CRM_EXECUTE, \u0026error);\n    if (error) {\n        // An error occurred while running a test.\n        return 1;\n    }\n    if (mode != fcf::NTest::CM_NONE){\n        // The --test-run | --test-help | ---test-list flags were passed at startup.\n        // And the function performed all the actions\n        return 0;\n    }\n\n    .... your application code ...\n\n    return 0;\n}\n```\n\n```c++\nint main(int a_argc, char* a_argv[]) {\n    // Or custom menu mode: Just parse to see what was asked\n    fcf::NTest::Options options;\n    int mode = fcf::NTest::cmdRun(options, a_argc, a_argv, fcf::NTest::CRM_PARSE);\n    if (mode == fcf::NTest::CM_HELP) {\n        fcf::NTest::cmdHelp();\n        return 0;\n    } else if (mode == fcf::NTest::CM_LIST) {\n        fcf::NTest::cmdList();\n        return 0;\n    } else if (mode == fcf::NTest::CM_RUN) {\n        bool error = false;\n        fcf::NTest::run(options, \u0026error);\n        return error ? 1 : 0;\n    }\n    // ... default execution\n}\n```\n\n### Command Line Flags\n\n- `--test-run`: Forces execution of selected tests.\n- `--test-list`: Prints a list of all available tests in the hierarchy (Part -\u003e Group -\u003e Test).\n- `--test-help`: Displays usage information and available flags.\n- `--test-log-level LEVEL`: Sets the global logging verbosity (e.g., `dbg`, `log`, `err`).\n- `--test-part PART_NAME`: Filters execution to only tests belonging to the specified part. Can be used multiple times.\n- `--test-group GROUP_NAME`: Filters execution to only tests belonging to the specified group. Can be used multiple times.\n- `--test-test TEST_NAME`: Filters execution to run only the specific test named. Can be used multiple times.\n- `--test-ignore-part PART_NAME`: Exclude tests in the specified part(s). Can be used multiple times.\n- `--test-ignore-group GROUP_NAME`: Exclude tests in the specified group(s). Can be used multiple times.\n- `--test-ignore-test TEST_NAME`: Exclude the specified test(s). Can be used multiple times.\n\n\n**Example Command:**\n```bash\n./my_tests --test-run --test-part Network --test-group HTTP --test-log-level dbg\n```\n\n### Helper Functions\n\n- **`cmdHelp()`**: Displays help information and available command-line flags.\n- **`cmdList()`**: Displays a list of all registered tests with their hierarchy structure.\n- **`run(const Options\u0026 a_options, bool* a_errorPtr = 0)`**: Executes the selected tests based on an `Options` object.\n  - **Parameters**:\n    - `a_options`: Configuration options specifying which tests to run and logging level.\n    - `a_errorPtr`: A pointer to a variable receiving error information. If an error occurs, the value is set to true. If a null pointer is passed, the function throws an exception.\n  - **Returns**: void.\n\n## Full Usage Example\n\n```c++\n#define FCF_TEST_IMPLEMENTATION\n#include \u003cfcfTest/test.hpp\u003e\n#include \u003cvector\u003e\n#include \u003ccmath\u003e\n\n// --- Test Declarations ---\n\nFCF_TEST_DECLARE(\"Math\", \"BasicArithmetic\", \"Addition\") {\n    int a = 2;\n    int b = 3;\n    FCF_TEST(a + b == 5, a, b);\n}\n\nFCF_TEST_DECLARE(\"Math\", \"BasicArithmetic\", \"Subtraction\") {\n    int a = 10;\n    int b = 4;\n    FCF_TEST(a - b == 6, a, b);\n}\n\nFCF_TEST_DECLARE(\"Vector\", \"SizeCheck\", \"EmptyVector\") {\n    std::vector\u003cint\u003e v;\n    FCF_TEST(v.size() == 0, v.size());\n}\n\n// --- Order Registration ---\n// Run Math tests before Vector tests\nFCF_TEST_PART_ORDER(\"Math\", 1);\nFCF_TEST_PART_ORDER(\"Vector\", 2);\n\n// Run \"BasicArithmetic\" group first within Math part\nFCF_TEST_GROUP_ORDER(\"BasicArithmetic\", 1);\n\n// Run Addition test first\nFCF_TEST_TEST_ORDER(\"Addition\", 1);\n\nint main(int a_argc, char* a_argv[]) {\n    // Use CRM_RUN for standard execution\n    bool error;\n    fcf::NTest::cmdRun(a_argc, a_argv, fcf::NTest::CRM_RUN, \u0026error);\n    return error ? 1 : 0;\n}\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffcf-framework%2Ffcftest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffcf-framework%2Ffcftest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffcf-framework%2Ffcftest/lists"}