Affix

 view release on metacpan or  search on metacpan

infix/src/common/double_tap.h  view on Meta::CPAN

/**
 * Copyright (c) 2025 Sanko Robinson
 *
 * This source code is dual-licensed under the Artistic License 2.0 or the MIT License.
 * You may choose to use this code under the terms of either license.
 *
 * SPDX-License-Identifier: (Artistic-2.0 OR MIT)
 *
 * The documentation blocks within this file are licensed under the
 * Creative Commons Attribution 4.0 International License (CC BY 4.0).
 *
 * SPDX-License-Identifier: CC-BY-4.0
 */
/**
 * @file double_tap.h
 * @brief A lightweight, single-header TAP (Test Anything Protocol) library.
 * @ingroup internal_test_harness
 *
 * @details This file provides a simple, self-contained testing harness that produces
 * TAP-compliant output, which is ideal for integration with CI/CD systems and other
 * testing tools. It is used for all unit and regression tests within the `infix` project.
 *
 * The library is designed to be trivial to use:
 * 1.  Define `DBLTAP_ENABLE` and `DBLTAP_IMPLEMENTATION` in a single test file.
 * 2.  Write all test logic within a function named `test_body(void)` using the `TEST` macro.
 * 3.  Use the provided macros (`plan`, `ok`, `subtest`, etc.) to structure tests.
 *
 * The library provides its own `main` function that initializes the harness, calls
 * the user-defined `test_body`, and reports the final results.
 *
 * @section thread_safety Thread Safety
 *
 * The design uses thread-local storage (`_Thread_local`, `__thread`) to manage the
 * test state (test counts, subtest nesting, etc.). This allows multiple threads to
 * run tests concurrently without interfering with each other's output or results,
 * making it suitable for testing thread-safe code. Global counters use atomic
 * operations where available to ensure correctness.
 *
 * @internal
 */
#pragma once
#ifdef DBLTAP_ENABLE
#define TAP_VERSION 13
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__unix__) || defined(__APPLE__) || defined(__OpenBSD__)
#include <unistd.h>
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h>
#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__OpenBSD__)
// Do not include pthread.h on OpenBSD to prevent linking/cleanup issues if -pthread is not used.
#include <pthread.h>
#endif

// C++ Headers must be included BEFORE extern "C"
#if defined(__cplusplus)
#include <atomic>
#endif

#ifdef __cplusplus
extern "C" {
#endif

// Portability Macros for Atomics and Thread-Local Storage
#if defined(__cplusplus)
#define TAP_ATOMIC_SIZE_T std::atomic<size_t>
#define TAP_ATOMIC_FETCH_ADD(ptr, val) std::atomic_fetch_add(ptr, (size_t)(val))
#define TAP_ATOMIC_INIT(val) (val)
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#define TAP_ATOMIC_SIZE_T _Atomic size_t
#define TAP_ATOMIC_FETCH_ADD(ptr, val) atomic_fetch_add(ptr, val)
#define TAP_ATOMIC_INIT(val) = val
#elif defined(__GNUC__) || defined(__clang__)
#define TAP_ATOMIC_SIZE_T size_t
#define TAP_ATOMIC_FETCH_ADD(ptr, val) __atomic_fetch_add(ptr, (size_t)(val), __ATOMIC_SEQ_CST)
#define TAP_ATOMIC_INIT(val) = val
#else
// Fallback for older compilers without atomics support. This is not thread-safe.
#define TAP_ATOMIC_SIZE_T size_t
#define TAP_ATOMIC_FETCH_ADD(ptr, val) ((*ptr) += (val))
#define TAP_ATOMIC_INIT(val) = val
#if !defined(_MSC_VER)
#warning "Compiler does not support C11 atomics or GCC builtins; global counters will not be thread-safe."
#endif
#endif



( run in 2.221 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )