From e5e542efa8ddeb84f259ad74090d9280dbe91d9b Mon Sep 17 00:00:00 2001 From: Alfi Maulana Date: Tue, 2 Jul 2024 21:13:23 +0700 Subject: [PATCH 1/2] feat: add `fail` macro --- CMakeLists.txt | 5 ++ cmake/Assertion.cmake | 150 +++++++++++++++++++----------------------- test/Fail.cmake | 7 ++ 3 files changed, 79 insertions(+), 83 deletions(-) create mode 100644 test/Fail.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ecc90c..0da438a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,11 @@ if(ASSERT_ENABLE_TESTS) COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" -- ${CMAKE_CURRENT_SOURCE_DIR}/test/IncludeOtherModules.cmake) + add_test( + NAME "failure invocation" + COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" + -- ${CMAKE_CURRENT_SOURCE_DIR}/test/Fail.cmake) + add_test( NAME "condition assertions" COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" diff --git a/cmake/Assertion.cmake b/cmake/Assertion.cmake index c1c4e9d..781cab1 100644 --- a/cmake/Assertion.cmake +++ b/cmake/Assertion.cmake @@ -31,6 +31,19 @@ macro(_assert_internal_format_message OUT_VAR FIRST_LINE) endforeach() endmacro() +# Throws a formatted fatal error message. +# +# fail(...) +# +# This macro throws a fatal error message formatted from the given lines. +# +# Refer to the `_assert_internal_format_message` macro for more information on +# how the fatal error message is formatted. +macro(fail FIRST_LINE) + _assert_internal_format_message(MESSAGE "${FIRST_LINE}" ${ARGN}) + message(FATAL_ERROR "${MESSAGE}") +endmacro() + # Asserts the given condition. # # assert() @@ -45,117 +58,102 @@ function(assert) if(${ARG_UNPARSED_ARGUMENTS}) # Do nothing if the assertion succeeds. else() - string(REPLACE ";" " " ARGS "${ARG_UNPARSED_ARGUMENTS}") - _assert_internal_format_message( - MESSAGE "expected:" ARGS "to resolve to true") - if(ARGC EQUAL 2) if(NOT ARGV0 STREQUAL NOT) if(ARGV0 STREQUAL DEFINED) - _assert_internal_format_message( - MESSAGE "expected variable:" ARGV1 "to be defined") + fail("expected variable:" ARGV1 "to be defined") elseif(ARGV0 STREQUAL EXISTS) - _assert_internal_format_message( - MESSAGE "expected path:" ARGV1 "to exist") + fail("expected path:" ARGV1 "to exist") elseif(ARGV0 STREQUAL IS_DIRECTORY) - _assert_internal_format_message( - MESSAGE "expected path:" ARGV1 "to be a directory") + fail("expected path:" ARGV1 "to be a directory") + else() + set(ARGS "${ARGV0} ${ARGV1}") + fail("expected:" ARGS "to resolve to true") endif() + else() + set(ARGS "${ARGV0} ${ARGV1}") + fail("expected:" ARGS "to resolve to true") endif() elseif(ARGC EQUAL 3) if(ARGV0 STREQUAL NOT) if(ARGV1 STREQUAL DEFINED) - _assert_internal_format_message( - MESSAGE "expected variable:" ARGV2 "not to be defined") + fail("expected variable:" ARGV2 "not to be defined") elseif(ARGV1 STREQUAL EXISTS) - _assert_internal_format_message( - MESSAGE "expected path:" ARGV2 "not to exist") + fail("expected path:" ARGV2 "not to exist") elseif(ARGV1 STREQUAL IS_DIRECTORY) - _assert_internal_format_message( - MESSAGE "expected path:" ARGV2 "not to be a directory") + fail("expected path:" ARGV2 "not to be a directory") + else() + set(ARGS "${ARGV0} ${ARGV1} ${ARGV2}") + fail("expected:" ARGS "to resolve to true") endif() else() if(ARGV1 STREQUAL MATCHES) if(DEFINED "${ARGV0}") - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV0}" - "of variable:" ARGV0 - "to match:" ARGV2) + fail("expected string:" "${ARGV0}" "of variable:" ARGV0 + "to match:" ARGV2) else() - _assert_internal_format_message( - MESSAGE "expected string:" ARGV0 "to match:" ARGV2) + fail("expected string:" ARGV0 "to match:" ARGV2) endif() elseif(ARGV1 STREQUAL STREQUAL) if(DEFINED "${ARGV0}") if(DEFINED "${ARGV2}") - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV0}" - "of variable:" ARGV0 - "to be equal to string:" "${ARGV2}" - "of variable:" ARGV2) + fail("expected string:" "${ARGV0}" "of variable:" ARGV0 + "to be equal to string:" "${ARGV2}" "of variable:" ARGV2) else() - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV0}" - "of variable:" ARGV0 - "to be equal to:" ARGV2) + fail("expected string:" "${ARGV0}" "of variable:" ARGV0 + "to be equal to:" ARGV2) endif() else() if(DEFINED "${ARGV2}") - _assert_internal_format_message( - MESSAGE "expected string:" ARGV0 - "to be equal to string:" "${ARGV2}" - "of variable:" ARGV2) + fail("expected string:" ARGV0 + "to be equal to string:" "${ARGV2}" "of variable:" ARGV2) else() - _assert_internal_format_message( - MESSAGE "expected string:" ARGV0 - "to be equal to:" ARGV2) + fail("expected string:" ARGV0 "to be equal to:" ARGV2) endif() endif() + else() + set(ARGS "${ARGV0} ${ARGV1} ${ARGV2}") + fail("expected:" ARGS "to resolve to true") endif() endif() elseif(ARGC EQUAL 4) if(ARGV0 STREQUAL NOT) if(ARGV2 STREQUAL MATCHES) if(DEFINED "${ARGV1}") - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV1}" - "of variable:" ARGV1 - "not to match:" ARGV3) + fail("expected string:" "${ARGV1}" "of variable:" ARGV1 + "not to match:" ARGV3) else() - _assert_internal_format_message( - MESSAGE "expected string:" ARGV1 "not to match:" ARGV3) + fail("expected string:" ARGV1 "not to match:" ARGV3) endif() elseif(ARGV2 STREQUAL STREQUAL) if(DEFINED "${ARGV1}") if(DEFINED "${ARGV3}") - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV1}" - "of variable:" ARGV1 - "not to be equal to string:" "${ARGV3}" - "of variable:" ARGV3) + fail("expected string:" "${ARGV1}" "of variable:" ARGV1 + "not to be equal to string:" "${ARGV3}" "of variable:" ARGV3) else() - _assert_internal_format_message( - MESSAGE "expected string:" "${ARGV1}" - "of variable:" ARGV1 - "not to be equal to:" ARGV3) + fail("expected string:" "${ARGV1}" "of variable:" ARGV1 + "not to be equal to:" ARGV3) endif() else() if(DEFINED "${ARGV3}") - _assert_internal_format_message( - MESSAGE "expected string:" ARGV1 - "not to be equal to string:" "${ARGV3}" - "of variable:" ARGV3) + fail("expected string:" ARGV1 + "not to be equal to string:" "${ARGV3}" "of variable:" ARGV3) else() - _assert_internal_format_message( - MESSAGE "expected string:" ARGV1 - "not to be equal to:" ARGV3) + fail("expected string:" ARGV1 "not to be equal to:" ARGV3) endif() endif() + else() + set(ARGS "${ARGV0} ${ARGV1} ${ARGV2} ${ARGV3}") + fail("expected:" ARGS "to resolve to true") endif() + else() + set(ARGS "${ARGV0} ${ARGV1} ${ARGV2} ${ARGV3}") + fail("expected:" ARGS "to resolve to true") endif() + else() + string(REPLACE ";" " " ARGS "${ARG_UNPARSED_ARGUMENTS}") + fail("expected:" ARGS "to resolve to true") endif() - - message(FATAL_ERROR "${MESSAGE}") endif() endfunction() @@ -180,11 +178,8 @@ function(assert_fatal_error) if(EXPECTED_MESSAGE_LENGTH GREATER 0 AND ARG0 STREQUAL FATAL_ERROR) list(POP_BACK _ASSERT_INTERNAL_EXPECTED_MESSAGES EXPECTED_MESSAGE) if(NOT "${ARG_UNPARSED_ARGUMENTS}" MATCHES "${EXPECTED_MESSAGE}") - _assert_internal_format_message( - ASSERT_MESSAGE - "expected fatal error message:" ARG_UNPARSED_ARGUMENTS + fail("expected fatal error message:" ARG_UNPARSED_ARGUMENTS "to match:" EXPECTED_MESSAGE) - message(FATAL_ERROR "${ASSERT_MESSAGE}") endif() else() _message("${ARG0}" ${ARG_UNPARSED_ARGUMENTS}) @@ -236,29 +231,18 @@ function(assert_execute_process) if(DEFINED ARG_ERROR AND RES EQUAL 0) string(REPLACE ";" " " COMMAND "${ARG_COMMAND}") - _assert_internal_format_message( - MESSAGE "expected command:" COMMAND "to fail") - message(FATAL_ERROR "${MESSAGE}") + fail("expected command:" COMMAND "to fail") elseif(NOT DEFINED ARG_ERROR AND NOT RES EQUAL 0) string(REPLACE ";" " " COMMAND "${ARG_COMMAND}") - _assert_internal_format_message( - MESSAGE "expected command:" COMMAND - "not to fail with error:" ERR) - message(FATAL_ERROR "${MESSAGE}") + fail("expected command:" COMMAND "not to fail with error:" ERR) elseif(DEFINED EXPECTED_OUTPUT AND NOT "${OUT}" MATCHES "${EXPECTED_OUTPUT}") string(REPLACE ";" " " COMMAND "${ARG_COMMAND}") - _assert_internal_format_message( - MESSAGE "expected the output:" OUT - "of command:" COMMAND - "to match:" EXPECTED_OUTPUT) - message(FATAL_ERROR "${MESSAGE}") + fail("expected the output:" OUT "of command:" COMMAND + "to match:" EXPECTED_OUTPUT) elseif(DEFINED EXPECTED_ERROR AND NOT "${ERR}" MATCHES "${EXPECTED_ERROR}") string(REPLACE ";" " " COMMAND "${ARG_COMMAND}") - _assert_internal_format_message( - MESSAGE "expected the error:" ERR - "of command:" COMMAND - "to match:" EXPECTED_ERROR) - message(FATAL_ERROR "${MESSAGE}") + fail("expected the error:" ERR "of command:" COMMAND + "to match:" EXPECTED_ERROR) endif() endfunction() diff --git a/test/Fail.cmake b/test/Fail.cmake new file mode 100644 index 0000000..8e34667 --- /dev/null +++ b/test/Fail.cmake @@ -0,0 +1,7 @@ +section("it should fail with a formatted fatal error message") + set(REASON "some reason") + + assert_fatal_error( + CALL fail "something happened:" REASON + MESSAGE "something happened:\n some reason") +endsection() From 9adc2dd68625463ed2760426af3dbba88e48a572 Mon Sep 17 00:00:00 2001 From: Alfi Maulana Date: Tue, 2 Jul 2024 21:30:15 +0700 Subject: [PATCH 2/2] refactor: merge `_assert_internal_format_message` macro to `fail` macro --- CMakeLists.txt | 5 ---- cmake/Assertion.cmake | 34 ++++++++++----------------- test/Fail.cmake | 40 ++++++++++++++++++++++++++++++++ test/InternalFormatMessage.cmake | 33 -------------------------- 4 files changed, 52 insertions(+), 60 deletions(-) delete mode 100644 test/InternalFormatMessage.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 0da438a..9df5c4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,11 +40,6 @@ if(ASSERT_ENABLE_TESTS) COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" -- ${CMAKE_CURRENT_SOURCE_DIR}/test/AssertExecuteProcess.cmake) - add_test( - NAME "internal assertion message formatting" - COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" - -- ${CMAKE_CURRENT_SOURCE_DIR}/test/InternalFormatMessage.cmake) - add_test( NAME "section creation" COMMAND "${CMAKE_COMMAND}" -P "${ASSERTION_LIST_FILE}" diff --git a/cmake/Assertion.cmake b/cmake/Assertion.cmake index 781cab1..5dde01b 100644 --- a/cmake/Assertion.cmake +++ b/cmake/Assertion.cmake @@ -6,41 +6,31 @@ cmake_minimum_required(VERSION 3.17) # This variable contains the path to the included `Assertion.cmake` module. set(ASSERTION_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}") -# Formats lines for an assertion message. +# Throws a formatted fatal error message. +# +# fail(...) # -# _assert_internal_format_message( [...]) +# This macro throws a fatal error message formatted from the given lines. # -# This macro formats the given lines by appending all of them into a single -# string. For each given line, if it is a variable, it will be expanded and -# indented by 2 spaces. The formatted string will then be stored in the -# `` variable. -macro(_assert_internal_format_message OUT_VAR FIRST_LINE) +# It formats the given `` by appending all of them into a single string. +# For each given line, if it is a variable, it will be expanded and indented by +# 2 spaces. +macro(fail FIRST_LINE) if(DEFINED "${FIRST_LINE}") - set("${OUT_VAR}" "${${FIRST_LINE}}") + set(MESSAGE "${${FIRST_LINE}}") else() - set("${OUT_VAR}" "${FIRST_LINE}") + set(MESSAGE "${FIRST_LINE}") endif() foreach(LINE IN ITEMS ${ARGN}) if(DEFINED "${LINE}") string(REPLACE "\n" "\n " LINE "${${LINE}}") - string(APPEND "${OUT_VAR}" "\n ${LINE}") + string(APPEND MESSAGE "\n ${LINE}") else() - string(APPEND "${OUT_VAR}" "\n${LINE}") + string(APPEND MESSAGE "\n${LINE}") endif() endforeach() -endmacro() -# Throws a formatted fatal error message. -# -# fail(...) -# -# This macro throws a fatal error message formatted from the given lines. -# -# Refer to the `_assert_internal_format_message` macro for more information on -# how the fatal error message is formatted. -macro(fail FIRST_LINE) - _assert_internal_format_message(MESSAGE "${FIRST_LINE}" ${ARGN}) message(FATAL_ERROR "${MESSAGE}") endmacro() diff --git a/test/Fail.cmake b/test/Fail.cmake index 8e34667..be4568d 100644 --- a/test/Fail.cmake +++ b/test/Fail.cmake @@ -1,7 +1,47 @@ section("it should fail with a formatted fatal error message") + assert_fatal_error( + CALL fail "something happened" + MESSAGE "something happened") + + assert_fatal_error( + CALL fail "something happened\non multiple lines" + MESSAGE "something happened\non multiple lines") + + assert_fatal_error( + CALL fail "something happened" "on multiple lines" + MESSAGE "something happened\non multiple lines") +endsection() + +section("it should fail with a formatted fatal error message " + "that contains values") set(REASON "some reason") + set(REASON_MULTILINE "some reason\non multiple lines") assert_fatal_error( CALL fail "something happened:" REASON MESSAGE "something happened:\n some reason") + + assert_fatal_error( + CALL fail "something happened:" REASON_MULTILINE + MESSAGE "something happened:\n some reason\n on multiple lines") + + assert_fatal_error( + CALL fail "something happened\non multiple lines:" REASON + MESSAGE "something happened\non multiple lines:\n some reason") + + assert_fatal_error( + CALL fail "something happened\non multiple lines:" REASON_MULTILINE + MESSAGE "something happened\non multiple lines:\n" + " some reason\n on multiple lines") + + assert_fatal_error( + CALL fail "something happened" "on multiple lines:" REASON + MESSAGE "something happened\non multiple lines:\n some reason") + + assert_fatal_error( + CALL fail + "something happened" "on multiple lines:" REASON + "something else happened:" REASON_MULTILINE + MESSAGE "something happened\non multiple lines:\n some reason\n" + "something else happened:\n some reason\n on multiple lines") endsection() diff --git a/test/InternalFormatMessage.cmake b/test/InternalFormatMessage.cmake deleted file mode 100644 index f226310..0000000 --- a/test/InternalFormatMessage.cmake +++ /dev/null @@ -1,33 +0,0 @@ -section("it should format lines for an assertion message") - _assert_internal_format_message( - ACTUAL_MESSAGE "first line" "second line" "third line\nthird line") - - string(JOIN "\n" EXPECTED_MESSAGE - "first line" - "second line" - "third line" - "third line") - assert(ACTUAL_MESSAGE STREQUAL EXPECTED_MESSAGE) -endsection() - -section("it should format lines that contain variables for an assertion message") - set(FIRST_VALUE "first value") - set(SECOND_VALUE "second value") - set(THIRD_VALUE "third value\nthird value") - - _assert_internal_format_message( - ACTUAL_MESSAGE "first line" FIRST_VALUE - "second line" SECOND_VALUE - THIRD_VALUE "third line\nthird line") - - string(JOIN "\n" EXPECTED_MESSAGE - "first line" - " first value" - "second line" - " second value" - " third value" - " third value" - "third line" - "third line") - assert(ACTUAL_MESSAGE STREQUAL EXPECTED_MESSAGE) -endsection()