function(quill_add_test TEST_NAME SOURCES)
    set(HEADER_FILES
            ../bundled/doctest/doctest.h
            ../misc/TestUtilities.h
    )

    # Create a test executable
    add_executable(${TEST_NAME} "")

    set_common_compile_options(${TEST_NAME})

    # Add sources
    target_sources(${TEST_NAME} PRIVATE ${SOURCES} ${HEADER_FILES})

    # include dirs
    target_include_directories(${TEST_NAME}
            PUBLIC
            $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test/misc>
            $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test/bundled>
            $<INSTALL_INTERFACE:include>
            PRIVATE
            ..)

    # Link dependencies
    check_cxx_atomics_available(HAVE_CXX_ATOMIC)
    if (HAVE_CXX_ATOMIC)
        target_link_libraries(${TEST_NAME} quill quill_test_common)
    else ()
        target_link_libraries(${TEST_NAME} quill quill_test_common atomic)
    endif ()

    if (QUILL_ENABLE_EXTENSIVE_TESTS)
        target_compile_definitions(${TEST_NAME} PRIVATE QUILL_ENABLE_EXTENSIVE_TESTS)
    endif ()

    if (QUILL_NO_EXCEPTIONS)
        target_compile_definitions(${TEST_NAME} PRIVATE DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS)
    endif ()

    # Do not decay cxx standard if not specified
    set_property(TARGET ${TEST_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)

    # Set output test directory
    set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/test)

    # Add this target to the post build unit tests
    # Set sanitizer environment variables for test execution if sanitizers are enabled
    if (QUILL_SANITIZE_ADDRESS)
        doctest_discover_tests(${TEST_NAME} PROPERTIES
                ENVIRONMENT "ASAN_OPTIONS=detect_leaks=1:check_initialization_order=1:halt_on_error=1;UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1")
    else ()
        doctest_discover_tests(${TEST_NAME})
    endif ()
endfunction()

include(Doctest)

quill_add_test(TEST_ArithmeticTypesLogging ArithmeticTypesLoggingTest.cpp)
quill_add_test(TEST_BackendExceptionNotifier BackendExceptionNotifierTest.cpp)
quill_add_test(TEST_BackendImmediateFlushFromBackendThread BackendImmediateFlushFromBackendThreadTest.cpp)
quill_add_test(TEST_ErrorNotifierThrows ErrorNotifierThrowsTest.cpp)
quill_add_test(TEST_BackendLongSleepAndNotify BackendLongSleepAndNotifyTest.cpp)
quill_add_test(TEST_BackendStartInvalidTransitLimits BackendStartInvalidTransitLimitsTest.cpp)
quill_add_test(TEST_BackendStartSignalRollback BackendStartSignalRollbackTest.cpp)
quill_add_test(TEST_BackendTransitBufferHardLimit BackendTransitBufferHardLimitTest.cpp)
quill_add_test(TEST_BackendTransitBufferSoftLimit BackendTransitBufferSoftLimitTest.cpp)
quill_add_test(TEST_BackendTscClock BackendTscClockTest.cpp)
quill_add_test(TEST_BackendTscClockInvalidConfig BackendTscClockInvalidConfigTest.cpp)
quill_add_test(TEST_BackendFormatterNonStdExceptionDoesNotBlockQueue BackendFormatterNonStdExceptionDoesNotBlockQueueTest.cpp)
quill_add_test(TEST_ManualBackendWorker ManualBackendWorkerTest.cpp)
quill_add_test(TEST_ManualBackendWorkerErrorNotifier ManualBackendWorkerErrorNotifierTest.cpp)
quill_add_test(TEST_ManualBackendWorkerTimeoutPoll ManualBackendWorkerTimeoutPollTest.cpp)
quill_add_test(TEST_MetricSink MetricSinkTest.cpp)
quill_add_test(TEST_BacktraceDynamicLogLevel BacktraceDynamicLogLevelTest.cpp)
quill_add_test(TEST_BacktraceFlushOnError BacktraceFlushOnErrorTest.cpp)
quill_add_test(TEST_BacktraceSinkErrorNoDuplicateFlush BacktraceSinkErrorNoDuplicateFlushTest.cpp)
quill_add_test(TEST_BacktraceMultithreadedStressTest BacktraceMultithreadedStressTest.cpp)
quill_add_test(TEST_BacktraceManualFlush BacktraceManualFlushTest.cpp)
quill_add_test(TEST_BacktraceNoFlush BacktraceNoFlushTest.cpp)
quill_add_test(TEST_BacktraceTerminatedThreadFlush BacktraceTerminatedThreadFlushTest.cpp)
quill_add_test(TEST_BinaryDataLoggingTest BinaryDataLoggingTest.cpp)
quill_add_test(TEST_BinaryDataDeferredFormatCodec BinaryDataDeferredFormatCodecTest.cpp)
quill_add_test(TEST_BinaryDataNullPointerNormalization BinaryDataNullPointerNormalizationTest.cpp)
quill_add_test(TEST_BinaryFileWriter BinaryFileWriterTest.cpp)
quill_add_test(TEST_BoundedBlockingQueue BoundedBlockingQueueTest.cpp)
quill_add_test(TEST_BoundedBlockingOversizedMessage BoundedBlockingOversizedMessageTest.cpp)
quill_add_test(TEST_BoundedDroppingQueue BoundedDroppingQueueTest.cpp)
quill_add_test(TEST_CArrayTypesLogging CArrayTypesLoggingTest.cpp)
quill_add_test(TEST_BoundedDroppingQueueDropMessages BoundedDroppingQueueDropMessagesTest.cpp)
quill_add_test(TEST_ConsoleSinkStderrMultipleFormats ConsoleSinkStderrMultipleFormatsTest.cpp)
quill_add_test(TEST_ConsoleSinkStdoutMultipleFormats ConsoleSinkStdoutMultipleFormatsTest.cpp)
quill_add_test(TEST_ConsoleSinkInvalidStream ConsoleSinkInvalidStreamTest.cpp)
quill_add_test(TEST_CsvWriting CsvWritingTest.cpp)
quill_add_test(TEST_CsvWriterAppendHeader CsvWriterAppendHeaderTest.cpp)
quill_add_test(TEST_CsvWriterFailedRotationHeader CsvWriterFailedRotationHeaderTest.cpp)
quill_add_test(TEST_CsvWriterRotatingAppendHeader CsvWriterRotatingAppendHeaderTest.cpp)
quill_add_test(TEST_CsvWriterRotationOnCreateHeader CsvWriterRotationOnCreateHeaderTest.cpp)
quill_add_test(TEST_CsvWriterRotationOnCreateAppendHeader CsvWriterRotationOnCreateAppendHeaderTest.cpp)
quill_add_test(TEST_CsvWriterAfterClose CsvWriterAfterCloseTest.cpp)
quill_add_test(TEST_CsvWritingCustomFrontend CsvWritingCustomFrontendTest.cpp)
quill_add_test(TEST_EnumLogging EnumLoggingTest.cpp)
quill_add_test(TEST_ErrorNotifierDisabled ErrorNotifierDisabledTest.cpp)
quill_add_test(TEST_EnvironmentLogLevelInitialization EnvironmentLogLevelInitializationTest.cpp)
quill_add_test(TEST_FlushMultipleLoggers FlushMultipleLoggers.cpp)
quill_add_test(TEST_FlushWithoutAnyLog FlushWithoutAnyLog.cpp)
quill_add_test(TEST_JsonConsoleLogging JsonConsoleLoggingTest.cpp)
quill_add_test(TEST_JsonCustomSinkNamedArgsNull JsonCustomSinkNamedArgsNullTest.cpp)
quill_add_test(TEST_JsonFileLogging JsonFileLoggingTest.cpp)
quill_add_test(TEST_JsonLineSeparatorEscape JsonLineSeparatorEscapeTest.cpp)
quill_add_test(TEST_JsonMultilineMetadata JsonMultilineMetadataTest.cpp)
quill_add_test(TEST_JsonVariedParamsLogging JsonVariedParamsLoggingTest.cpp)
quill_add_test(TEST_NamedArgsEdgeCases NamedArgsEdgeCasesTest.cpp)
quill_add_test(TEST_LogArgumentsEvaluation LogArgumentsEvaluationTest.cpp)
quill_add_test(TEST_LogFlushWithSoftLimit LogFlushWithSoftLimitTest.cpp)
quill_add_test(TEST_LoggerAddRemoveGet LoggerAddRemoveGetTest.cpp)
quill_add_test(TEST_CreateOrGetLoggerRequiresSourceLogger CreateOrGetLoggerRequiresSourceLoggerTest.cpp)
quill_add_test(TEST_MacroFreeBacktraceFlushTest MacroFreeBacktraceFlushTest.cpp)
quill_add_test(TEST_MacroFreeJsonLoggingTest MacroFreeJsonLoggingTest.cpp)
quill_add_test(TEST_MacroFreeMultiFrontendThreadsTest MacroFreeMultiFrontendThreadsTest.cpp)
quill_add_test(TEST_MacrosAndFunctionsLoggingTest MacrosAndFunctionsLoggingTest.cpp)
quill_add_test(TEST_MacrosDisableFileFunctionTest MacrosDisableFileFunctionTest.cpp)
quill_add_test(TEST_Macros MacrosTest.cpp)
quill_add_test(TEST_MdcFormatErrorDoesNotBlockBackendQueue MdcFormatErrorDoesNotBlockBackendQueueTest.cpp)
quill_add_test(TEST_MdcLogging MdcLoggingTest.cpp)
quill_add_test(TEST_MonotonicOutputTimestamps MonotonicOutputTimestampsTest.cpp)
quill_add_test(TEST_MonotonicOutputTimestampsDisabled MonotonicOutputTimestampsDisabledTest.cpp)
quill_add_test(TEST_MultiFrontendThreads MultiFrontendThreadsTest.cpp)
quill_add_test(TEST_MultiFrontendThreadsTimestampOrderTest MultiFrontendThreadsTimestampOrderTest.cpp)
quill_add_test(TEST_MultilineMetadata MultilineMetadataTest.cpp)
quill_add_test(TEST_MultilineMetadataOverrideFormatTest MultilineMetadataOverrideFormatTest.cpp)
quill_add_test(TEST_MultipleSinksSameLogger MultipleSinksSameLoggerTest.cpp)
quill_add_test(TEST_OverrideSinkFormatter OverrideSinkFormatterTest.cpp)
quill_add_test(TEST_PeriodicSinkException PeriodicSinkExceptionTest.cpp)
quill_add_test(TEST_RemoveLoggerBlocking RemoveLoggerBlockingTest.cpp)
quill_add_test(TEST_RemoveLoggerBlockingQueueFull RemoveLoggerBlockingQueueFullTest.cpp)
quill_add_test(TEST_RotatingSinkDelayedRotation RotatingSinkDelayedRotationTest.cpp)
quill_add_test(TEST_RotatingSinkKeepOldest RotatingSinkKeepOldestTest.cpp)
quill_add_test(TEST_RotatingSinkOverwriteOldest RotatingSinkOverwriteOldestTest.cpp)
quill_add_test(TEST_RotatingSinkSizeRotation RotatingSinkSizeRotationTest.cpp)
quill_add_test(TEST_RuntimeMetadata RuntimeMetadataTest.cpp)
quill_add_test(TEST_RuntimeMetadataBlockingQueueNotifier RuntimeMetadataBlockingQueueNotifierTest.cpp)
quill_add_test(TEST_RuntimeMetadataDroppingQueueNotifier RuntimeMetadataDroppingQueueNotifierTest.cpp)
quill_add_test(TEST_ShrinkThreadLocalQueueTest ShrinkThreadLocalQueueTest.cpp)
quill_add_test(TEST_SignalHandler SignalHandlerTest.cpp)
quill_add_test(TEST_SignalHandlerLogger SignalHandlerLoggerTest.cpp)
quill_add_test(TEST_SignalHandlerWithoutLogger SignalHandlerWithoutLoggerTest.cpp)
quill_add_test(TEST_SimpleSetupConsoleStream SimpleSetupConsoleStreamTest.cpp)
quill_add_test(TEST_SingleFrontendThreadMultipleLoggers SingleFrontendThreadMultipleLoggersTest.cpp)
quill_add_test(TEST_SingleFrontendThread SingleFrontendThreadTest.cpp)
quill_add_test(TEST_SinkFilter SinkFilterTest.cpp)
quill_add_test(TEST_SinkFilterOverrideFormat SinkFilterOverrideFormatTest.cpp)
quill_add_test(TEST_StdArrayLogging StdArrayLoggingTest.cpp)
quill_add_test(TEST_StdBitsetLogging StdBitsetLoggingTest.cpp)
quill_add_test(TEST_StdChronoLogging StdChronoLoggingTest.cpp)
quill_add_test(TEST_StdComplexLogging StdComplexLoggingTest.cpp)
quill_add_test(TEST_StdDequeLogging StdDequeLoggingTest.cpp)
quill_add_test(TEST_StdFilesystemPathLogging StdFilesystemPathLoggingTest.cpp)
quill_add_test(TEST_StdForwardListLogging StdForwardListLoggingTest.cpp)
quill_add_test(TEST_StdListLogging StdListLoggingTest.cpp)
quill_add_test(TEST_StdMapLogging StdMapLoggingTest.cpp)
quill_add_test(TEST_StdMultiMapLogging StdMultiMapLoggingTest.cpp)
quill_add_test(TEST_StdMultiSetLogging StdMultiSetLoggingTest.cpp)
quill_add_test(TEST_StdOptionalLogging StdOptionalLoggingTest.cpp)
quill_add_test(TEST_StdPairLogging StdPairLoggingTest.cpp)
quill_add_test(TEST_StdSetLogging StdSetLoggingTest.cpp)
quill_add_test(TEST_StdSystemErrorLogging StdSystemErrorLoggingTest.cpp)
quill_add_test(TEST_StdTupleLogging StdTupleLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMapLogging StdUnorderedMapLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMultiMapLogging StdUnorderedMultiMapLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMultiSetLogging StdUnorderedMultiSetLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedSetLogging StdUnorderedSetLoggingTest.cpp)
quill_add_test(TEST_StdVariantLogging StdVariantLoggingTest.cpp)
quill_add_test(TEST_StdVectorLogging StdVectorLoggingTest.cpp)
quill_add_test(TEST_SinkLogLevelFilter SinkLogLevelFilterTest.cpp)
quill_add_test(TEST_StartStopBackendWorker StartStopBackendWorkerTest.cpp)
quill_add_test(TEST_StopWatchLogging StopWatchLoggingTest.cpp)
quill_add_test(TEST_StringLargeLogging StringLargeLoggingTest.cpp)
quill_add_test(TEST_StringLoggingDynamicLogLevel StringLoggingDynamicLogLevelTest.cpp)
quill_add_test(TEST_StringLogging StringLoggingTest.cpp)
quill_add_test(TEST_StringRandomLargeLogging StringRandomLargeLoggingTest.cpp)
quill_add_test(TEST_StringRandomLogging StringRandomLoggingTest.cpp)
quill_add_test(TEST_StringRandomSmallLogging StringRandomSmallLoggingTest.cpp)
quill_add_test(TEST_StringRef StringRefTest.cpp)
quill_add_test(TEST_TagsLogging TagsLoggingTest.cpp)
quill_add_test(TEST_UnboundedUnlimitedQueue UnboundedUnlimitedQueueTest.cpp)
quill_add_test(TEST_UnboundedDroppingQueueMaxCapacityNotifier UnboundedDroppingQueueMaxCapacityNotifierTest.cpp)
quill_add_test(TEST_UserClockSource UserClockSourceTest.cpp)
quill_add_test(TEST_UserDefinedTypeLoggingDeferredFormatTest UserDefinedTypeLoggingDeferredFormatTest.cpp)
quill_add_test(TEST_UserDefinedTypeDeferredFormatCopyMove UserDefinedTypeDeferredFormatCopyMoveTest.cpp)
quill_add_test(TEST_UserDefinedTypeLoggingDirectFormatTest UserDefinedTypeLoggingDirectFormatTest.cpp)
quill_add_test(TEST_UserDefinedTypeLogging UserDefinedTypeLoggingTest.cpp)
quill_add_test(TEST_UserSink UserSinkTest.cpp)
quill_add_test(TEST_VariableLogging VariableLoggingTest.cpp)

quill_add_test(TEST_CompileActiveLogLevel CompileActiveLogLevelTest.cpp)
target_compile_definitions(TEST_CompileActiveLogLevel PRIVATE -DQUILL_COMPILE_ACTIVE_LOG_LEVEL=QUILL_COMPILE_ACTIVE_LOG_LEVEL_WARNING)

if (WIN32)
    quill_add_test(TEST_WideStdTypesLogging WideStdTypesLoggingTest.cpp)
    quill_add_test(TEST_WideStringLogging WideStringLoggingTest.cpp)
    quill_add_test(TEST_WideStringLargeLogging WideStringLargeLoggingTest.cpp)
    quill_add_test(TEST_WideStringWindowsHeaderMacros WideStringWindowsHeaderMacrosTest.cpp)
    quill_add_test(TEST_WindowsConsoleSignalHandlerUnhandled WindowsConsoleSignalHandlerUnhandledTest.cpp)
endif ()
