diff --git a/features/frameworks/unity/source/unity.c b/features/frameworks/unity/source/unity.c index 1b0d14e4a7..a1e6f3aa94 100644 --- a/features/frameworks/unity/source/unity.c +++ b/features/frameworks/unity/source/unity.c @@ -29,6 +29,7 @@ static const char UnityStrOk[] = "OK"; static const char UnityStrPass[] = "PASS"; static const char UnityStrFail[] = "FAIL"; static const char UnityStrIgnore[] = "IGNORE"; +static const char UnityStrSkip[] = "SKIP"; static const char UnityStrNull[] = "NULL"; static const char UnityStrSpacer[] = ". "; static const char UnityStrExpected[] = " Expected "; @@ -1228,6 +1229,19 @@ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) UNITY_IGNORE_AND_BAIL; } +/*-----------------------------------------------*/ +void UnitySkipPrint(const char* msg, const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrSkip); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } +} + /*-----------------------------------------------*/ #if defined(UNITY_WEAK_ATTRIBUTE) UNITY_WEAK_ATTRIBUTE void setUp(void) { } diff --git a/features/frameworks/unity/unity/unity.h b/features/frameworks/unity/unity/unity.h index 45d6a065f9..85992fec04 100644 --- a/features/frameworks/unity/unity/unity.h +++ b/features/frameworks/unity/unity/unity.h @@ -294,6 +294,17 @@ void tearDown(void); #define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) #define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) +/*------------------------------------------------------- + * Test skipping + *-------------------------------------------------------*/ + +// Use these to skip the test case (marking it successful). +// Use only in test case function itself, and only if it returns nothing (void). +#define TEST_SKIP_MESSAGE(message) UNITY_TEST_SKIP(__LINE__, (message)) +#define TEST_SKIP() UNITY_TEST_SKIP(__LINE__, NULL) +#define TEST_SKIP_UNLESS(condition) UNITY_TEST_SKIP_UNLESS((condition), __LINE__, NULL) +#define TEST_SKIP_UNLESS_MESSAGE(condition, message) UNITY_TEST_SKIP_UNLESS((condition), __LINE__, (message)) + /* end of UNITY_FRAMEWORK_H */ #ifdef __cplusplus } diff --git a/features/frameworks/unity/unity/unity_internals.h b/features/frameworks/unity/unity/unity_internals.h index 4ec311343e..337e9f30cc 100644 --- a/features/frameworks/unity/unity/unity_internals.h +++ b/features/frameworks/unity/unity/unity_internals.h @@ -554,6 +554,8 @@ void UnityFail(const char* message, const UNITY_LINE_TYPE line); void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +void UnitySkipPrint(const char* message, const UNITY_LINE_TYPE line); + #ifndef UNITY_EXCLUDE_FLOAT void UnityAssertFloatsWithin(const _UF delta, const _UF expected, @@ -785,6 +787,13 @@ extern const char UnityStrErr64[]; #define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) #endif +/*------------------------------------------------------- + * Test skip + *-------------------------------------------------------*/ + +#define UNITY_TEST_SKIP(line, message) { UnitySkipPrint( (message), (UNITY_LINE_TYPE)(line)); return; } +#define UNITY_TEST_SKIP_UNLESS(condition, line, message) if (!(condition)) UNITY_TEST_SKIP((line), (message)) + /* End of UNITY_INTERNALS_H */ #endif diff --git a/features/frameworks/utest/TESTS/unit_tests/test_skip/main.cpp b/features/frameworks/utest/TESTS/unit_tests/test_skip/main.cpp new file mode 100644 index 0000000000..19e2fffe93 --- /dev/null +++ b/features/frameworks/utest/TESTS/unit_tests/test_skip/main.cpp @@ -0,0 +1,74 @@ +/* +* Copyright (c) 2018 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" + +using namespace utest::v1; + +int skipped_at_right_place = 0; + +utest::v1::status_t test_skip_case_teardown(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +{ + TEST_ASSERT_EQUAL(1, skipped_at_right_place); + greentea_case_teardown_handler(source, passed, failed, failure); + return STATUS_CONTINUE; +} + +// Aborting Teardown Handler ------------------------------------------------------------------------------------------ +void unconditional_test_skip_test() +{ + TEST_SKIP(); + // Should not get here + TEST_ASSERT(0); +} + +void conditional_test_skip_test() +{ + skipped_at_right_place = 0; + TEST_SKIP_UNLESS_MESSAGE(1, "Test skipped at the wrong place!"); + + skipped_at_right_place = 1; + TEST_SKIP_UNLESS_MESSAGE(0, "Test skipped at the right place."); + + // Should not get here + skipped_at_right_place = 0; + TEST_ASSERT(0); +} + +// Cases -------------------------------------------------------------------------------------------------------------- +Case cases[] = { + Case("Unconditional test skip macro test", unconditional_test_skip_test), + Case("Conditional test skip macro test", conditional_test_skip_test, test_skip_case_teardown), +}; + +// Specification: Setup & Teardown ------------------------------------------------------------------------------------ +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(15, "default_auto"); + + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_setup, cases); + +int main() +{ + // Run the specification only AFTER setting the custom scheduler(if required). + Harness::run(specification); +}