From 6b180d6221445450b55af47d5d2d7290cc9bb98f Mon Sep 17 00:00:00 2001 From: "Pascal J. Bourguignon" Date: Tue, 2 May 2023 11:40:03 +0200 Subject: [PATCH] Added macros to support noreturn functions Added TEST_PROTECT_NORETURN(), TEST_DO_NOT_RETURN(), and TEST_NOT_RETURNING(call) to test for non-returning functions. Mock functions that are declared noreturn shall use TEST_DO_NOT_RETURN() instead of return. --- docs/UnityAssertionsReference.md | 44 ++++++++++++++++++++++++++++++++ src/unity_internals.h | 20 +++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/docs/UnityAssertionsReference.md b/docs/UnityAssertionsReference.md index 99880d84..3745b21b 100644 --- a/docs/UnityAssertionsReference.md +++ b/docs/UnityAssertionsReference.md @@ -222,6 +222,50 @@ This can be useful for outputting `INFO` messages into the Unity output stream without actually ending the test. Like pass and fail messages, it will be output with the filename and line number. +#### `TEST_PROTECT_NORETURN()` + +This macro prepares an environment to test a function that is declared `noreturn`. + +``` + if(TEST_PROTECT_NORETURN()){ + } +``` + +The function `mock_go_elsewhere()` would use `TEST_DO_NOT_RETURN()` +instead of returning. + +#### `TEST_NOT_RETURNING(call)` + +Calls a function, and the test fails if the function returns. +Instead, the called function should use `TEST_DO_NOT_RETURN()`. + +``` + /* prepare the test here */ + TEST_NOT_RETURNING(go_elsewhere(42)); +``` + +Note: this can be used to call a mock function (that uses +`TEST_NOT_RETURNING()` instead of returning), or an actual function +that effectively does not return. In the later case, the control +won't resume to the caller test (unless there's a failure), so the +test should expect that and have set up things accordingly. + +This cannot be used if `UNITY_EXCLUDE_SETJMP_H` is defined. + +#### `TEST_DO_NOT_RETURN()` + +Aborts the execution, and resume after the current +`TEST_NOT_RETURNING()`, successfully. + +This should be used in mock functions declared `noreturn` instead of +returning (explicitely or implicitely). + +Note: actual functions that don't return will go wherever they shoud +go and it's assumed this is handled in the test. These macros are +intended to be used by mock functions. + +This cannot be used if `UNITY_EXCLUDE_SETJMP_H` is defined. + ### Boolean #### `TEST_ASSERT (condition)` diff --git a/src/unity_internals.h b/src/unity_internals.h index 98e298fc..5c80eda7 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -509,6 +509,7 @@ struct UNITY_STORAGE_T #endif #ifndef UNITY_EXCLUDE_SETJMP_H jmp_buf AbortFrame; + jmp_buf NoReturnFrame; #endif }; @@ -762,9 +763,28 @@ extern const char UnityStrErrShorthand[]; #ifndef UNITY_EXCLUDE_SETJMP_H #define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) #define TEST_ABORT() longjmp(Unity.AbortFrame, 1) + +#define TEST_PROTECT_NORETURN() (setjmp(Unity.NoReturnFrame) == 0) +#define TEST_DO_NOT_RETURN() longjmp(Unity.NoReturnFrame, 1) + +/* +TEST_NOT_RETURNING(call) +This macro uses TEST_PROTECT_NORETURN to protect the call. +If the call returns, then the test fails. +*/ +#define TEST_NOT_RETURNING(call) \ + if (TEST_PROTECT_NORETURN()) \ + { \ + call; \ + UnityFail("Call Was Expected Not To Return: " #call, __LINE__); \ + } + #else #define TEST_PROTECT() 1 #define TEST_ABORT() return +#define TEST_PROTECT_NORETURN() _Static_assert(false, "TEST_PROTECT_NORETURN() cannot be used when UNITY_EXCLUDE_SETJMP_H is defined" +#define TEST_DO_NOT_RETURN() _Static_assert(false, "TEST_DO_NOT_RETURN() cannot be used when UNITY_EXCLUDE_SETJMP_H is defined" +#define TEST_NOT_RETURNING(call) _Static_assert(false, "TEST_NOT_RETURNING(call) cannot be used when UNITY_EXCLUDE_SETJMP_H is defined" #endif /* Automatically enable variadic macros support, if it not enabled before */