From 855a4a8a7edfad7d037b35ca8b4cb05c3197f835 Mon Sep 17 00:00:00 2001 From: Alfi Maulana Date: Mon, 21 Oct 2024 22:19:41 +0700 Subject: [PATCH] feat: add support to assert commands call not to receive errors (#287) Signed-off-by: Alfi Maulana --- README.md | 10 ++-- cmake/Assertion.cmake | 75 +++++++++++++++----------- test/test_assert_call.cmake | 104 ++++++++++++++++++++---------------- 3 files changed, 104 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index f39dfde..9f95f55 100644 --- a/README.md +++ b/README.md @@ -175,14 +175,12 @@ Performs an assertion on the given command call. ```cmake assert_call( [CALL] [...] - EXPECT_ERROR [MATCHES|STREQUAL] ...) + [EXPECT_ERROR [MATCHES|STREQUAL] ...]) ``` -This function asserts the behavior of the function or macro named ``, called with the specified ``. It currently only supports asserting whether the given command receives error messages that satisfy the expected message. It captures all errors from the `message` function and compares them with the expected message. Each captured error is concatenated with new lines as separators. +This function asserts whether the function or macro named ``, called with the specified ``, does not receive any errors. Internally, the function captures all errors from the `message` function. Each captured error is concatenated with new lines as separators. -If `MATCHES` is specified, it asserts whether the captured messages match ``. If `STREQUAL` is specified, it asserts whether the captured messages are equal to ``. If neither is specified, it defaults to the `MATCHES` parameter. - -If more than one `` string is given, they are concatenated into a single message with no separators. +If `EXPECT_ERROR` is specified, it instead asserts whether the call to the function or macro received errors that satisfy the expected message. If `MATCHES` is specified, it asserts whether the received errors match ``. If `STREQUAL` is specified, it asserts whether the received errors are equal to ``. If neither is specified, it defaults to the `MATCHES` parameter. If more than one `` string is given, they are concatenated into a single message with no separators. #### Example @@ -201,7 +199,7 @@ assert_call( The above example asserts whether the call to `send_errors(first second)` receives errors equal to `first error\nsecond error`. If it does not receive any errors, it will throw the following error: ``` -expected to receive an error message +expected to receive errors ``` ### `assert_execute_process` diff --git a/cmake/Assertion.cmake b/cmake/Assertion.cmake index 0f5047f..ec90d1d 100644 --- a/cmake/Assertion.cmake +++ b/cmake/Assertion.cmake @@ -358,22 +358,20 @@ endfunction() # # assert_call( # [CALL] [...] -# EXPECT_ERROR [MATCHES|STREQUAL] ...) +# [EXPECT_ERROR [MATCHES|STREQUAL] ...]) # -# This function asserts the behavior of the function or macro named ``, -# called with the specified ``. It currently only supports asserting -# whether the given command receives error messages that satisfy the expected -# message. It captures all errors from the `message` function and compares them -# with the expected message. Each captured error is concatenated with new lines -# as separators. +# This function asserts whether the function or macro named ``, called +# with the specified ``, does not receive any errors. Internally, the +# function captures all errors from the `message` function. Each captured error +# is concatenated with new lines as separators. # -# If `MATCHES` is specified, it asserts whether the captured messages match -# ``. If `STREQUAL` is specified, it asserts whether the captured -# messages are equal to ``. If neither is specified, it defaults to the -# `MATCHES` parameter. -# -# If more than one `` string is given, they are concatenated into a -# single message with no separators. +# If `EXPECT_ERROR` is specified, it instead asserts whether the call to the +# function or macro received errors that satisfy the expected message. If +# `MATCHES` is specified, it asserts whether the received errors match +# ``. If `STREQUAL` is specified, it asserts whether the received +# errors are equal to ``. If neither is specified, it defaults to the +# `MATCHES` parameter. If more than one `` string is given, they are +# concatenated into a single message with no separators. function(assert_call) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "" "CALL;EXPECT_ERROR") @@ -381,19 +379,24 @@ function(assert_call) set(ARG_CALL ${ARG_UNPARSED_ARGUMENTS}) endif() - list(GET ARG_EXPECT_ERROR 0 OPERATOR) - if(OPERATOR MATCHES ^MATCHES|STREQUAL$) - list(REMOVE_AT ARG_EXPECT_ERROR 0) + if(DEFINED ARG_EXPECT_ERROR) + list(GET ARG_EXPECT_ERROR 0 EXPECTED_ERROR_OPERATOR) + if(EXPECTED_ERROR_OPERATOR MATCHES ^MATCHES|STREQUAL$) + list(REMOVE_AT ARG_EXPECT_ERROR 0) + else() + set(EXPECTED_ERROR_OPERATOR "MATCHES") + endif() + string(JOIN "" EXPECTED_ERROR ${ARG_EXPECT_ERROR}) else() - set(OPERATOR "MATCHES") + unset(EXPECTED_ERROR_OPERATOR) + unset(EXPECTED_ERROR) endif() - string(JOIN "" EXPECTED_ERROR ${ARG_EXPECT_ERROR}) # Override the `message` function if it has not been overridden. get_property(MESSAGE_MOCKED GLOBAL PROPERTY _message_mocked) if(NOT MESSAGE_MOCKED) # Override the `message` function to allow the behavior to be mocked by - # capturing an error message. + # capturing an error. function(message MODE) cmake_parse_arguments(PARSE_ARGV 1 ARG "" "" "") @@ -410,14 +413,14 @@ function(assert_call) set_property(GLOBAL PROPERTY _message_mocked ON) endif() - # Increase the level for capturing error messages. + # Increase the level for capturing errors. if(_CAPTURE_LEVEL GREATER_EQUAL 0) math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} + 1") else() set(_CAPTURE_LEVEL 1) endif() - # Clear global property that hold the captured messages. + # Clear global property that hold the captured errors. set_property(GLOBAL PROPERTY assert_captured_error_${_CAPTURE_LEVEL}) # Call the command with the specified arguments. @@ -430,21 +433,29 @@ function(assert_call) if(CAPTURED_ERROR_SET) get_property(CAPTURED_ERROR GLOBAL PROPERTY assert_captured_error_${_CAPTURE_LEVEL}) - string(STRIP "${CAPTURED_ERROR}" CAPTURED_ERROR) - if(NOT "${CAPTURED_ERROR}" ${OPERATOR} "${EXPECTED_ERROR}") - math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} - 1") - if(OPERATOR STREQUAL "MATCHES") - fail("expected error message" CAPTURED_ERROR - "to match" EXPECTED_ERROR) + if(DEFINED EXPECTED_ERROR) + string(STRIP "${CAPTURED_ERROR}" CAPTURED_ERROR) + if(EXPECTED_ERROR_OPERATOR STREQUAL "MATCHES") + if(NOT "${CAPTURED_ERROR}" MATCHES "${EXPECTED_ERROR}") + math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} - 1") + fail("expected errors" CAPTURED_ERROR + "to match" EXPECTED_ERROR) + endif() else() - fail("expected error message" CAPTURED_ERROR - "to be equal to" EXPECTED_ERROR) + if(NOT "${CAPTURED_ERROR}" STREQUAL "${EXPECTED_ERROR}") + math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} - 1") + fail("expected errors" CAPTURED_ERROR + "to be equal to" EXPECTED_ERROR) + endif() endif() + else() + math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} - 1") + fail("expected not to receive errors" CAPTURED_ERROR) endif() - else() + elseif(DEFINED EXPECTED_ERROR) math(EXPR _CAPTURE_LEVEL "${_CAPTURE_LEVEL} - 1") - fail("expected to receive an error message") + fail("expected to receive errors") endif() endfunction() diff --git a/test/test_assert_call.cmake b/test/test_assert_call.cmake index 6805679..5ba1d49 100644 --- a/test/test_assert_call.cmake +++ b/test/test_assert_call.cmake @@ -7,60 +7,70 @@ function(throw_errors) message(FATAL_ERROR "a fatal error message") endfunction() -section("it should assert error messages") - assert_call(throw_errors EXPECT_ERROR - "a se.*or message\n" - "a fa.*or message") +section("assert command calls") + section("it should assert command calls") + assert_call(message DEBUG "a debug message") + assert_call(CALL message DEBUG "a debug message") + endsection() - assert_call(CALL throw_errors EXPECT_ERROR - "a se.*or message\n" - "a fa.*or message") - - assert_call(throw_errors EXPECT_ERROR MATCHES - "a se.*or message\n" - "a fa.*or message") - - assert_call(throw_errors EXPECT_ERROR STREQUAL - "a send error message\n" - "a fatal error message") + section("it should fail to assert a command call") + assert_call(assert_call throw_errors EXPECT_ERROR STREQUAL + "expected not to receive errors:\n" + " a send error message\n" + " a fatal error message") + endsection() endsection() -section("it should fail to assert error messages") - macro(assert_failures) +section("assert command call errors") + section("it should assert command call errors") assert_call(throw_errors EXPECT_ERROR - "another se.*or message\n" - "another fa.*or message") - endmacro() + "a se.*or message\n" + "a fa.*or message") - assert_call(assert_failures EXPECT_ERROR STREQUAL - "expected error message:\n" - " a send error message\n" - " a fatal error message\n" - "to match:\n" - " another se.*or message\n" - " another fa.*or message") + assert_call(throw_errors EXPECT_ERROR MATCHES + "a se.*or message\n" + "a fa.*or message") - macro(assert_failures) - assert_call(throw_errors EXPECT_ERROR - "another send error message\n" - "another fatal error message") - endmacro() + assert_call(throw_errors EXPECT_ERROR STREQUAL + "a send error message\n" + "a fatal error message") + endsection() - assert_call(assert_failures EXPECT_ERROR STREQUAL - "expected error message:\n" - " a send error message\n" - " a fatal error message\n" - "to match:\n" - " another send error message\n" - " another fatal error message") -endsection() + section("it should fail to assert command call errors") + macro(assert_failures) + assert_call(message DEBUG "a debug message" + EXPECT_ERROR "a debug message") + endmacro() + + assert_call(assert_failures EXPECT_ERROR STREQUAL + "expected to receive errors") + + macro(assert_failures) + assert_call(throw_errors EXPECT_ERROR + "another se.*or message\n" + "another fa.*or message") + endmacro() + + assert_call(assert_failures EXPECT_ERROR STREQUAL + "expected errors:\n" + " a send error message\n" + " a fatal error message\n" + "to match:\n" + " another se.*or message\n" + " another fa.*or message") -section("it should fail to assert error messages " - "due to no error being received") - macro(failed_assertion) - assert_call(message "a message" EXPECT_ERROR "a message") - endmacro() + macro(assert_failures) + assert_call(throw_errors EXPECT_ERROR + "another send error message\n" + "another fatal error message") + endmacro() - assert_call(failed_assertion EXPECT_ERROR - "expected to receive an error message") + assert_call(assert_failures EXPECT_ERROR STREQUAL + "expected errors:\n" + " a send error message\n" + " a fatal error message\n" + "to match:\n" + " another send error message\n" + " another fatal error message") + endsection() endsection()