From 47390727e58721787b7cb3457ace51c981cf64c7 Mon Sep 17 00:00:00 2001 From: Martin Kojtal Date: Thu, 7 Apr 2016 15:51:19 +0100 Subject: [PATCH 01/88] Add unity to frameworks --- frameworks/unity.lib | 1 + 1 file changed, 1 insertion(+) create mode 100644 frameworks/unity.lib diff --git a/frameworks/unity.lib b/frameworks/unity.lib new file mode 100644 index 0000000000..bd2fffb638 --- /dev/null +++ b/frameworks/unity.lib @@ -0,0 +1 @@ +https://github.com/ARMmbed/unity.git#3b2fef7fcf60abcc From e4354b2c1afabb17c197bb26c519ba44ff778262 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 10 Nov 2015 10:51:52 +0000 Subject: [PATCH 02/88] Add interface and implementation of a list based unit test harness. --- "frameworks\\utest/source/case.cpp" | 54 ++++++ .../source/failure_handler.cpp" | 51 ++++++ "frameworks\\utest/source/test_harness.cpp" | 157 ++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 "frameworks\\utest/source/case.cpp" create mode 100644 "frameworks\\utest/source/failure_handler.cpp" create mode 100644 "frameworks\\utest/source/test_harness.cpp" diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" new file mode 100644 index 0000000000..add3d8e861 --- /dev/null +++ "b/frameworks\\utest/source/case.cpp" @@ -0,0 +1,54 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/async_test.h" + +using namespace mbed::test::v0; + + +Case::Case(const char *description, const case_handler_t case_handler) : + description(description), case_handler(case_handler), repeats(0), failure_handler(default_failure_handler), timeout_ms(0) {} + +Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats) : + description(description), case_handler(case_handler), repeats(repeats), failure_handler(default_failure_handler), timeout_ms(0) {} + +Case::Case(const char *description, const case_handler_t case_handler, const case_failure_handler_t failure_handler) : + description(description), case_handler(case_handler), repeats(0), failure_handler(failure_handler), timeout_ms(0) {} + +Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler) : + description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(0) {} + +Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : + description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(timeout_ms) {} + +const char* +Case::getDescription() const +{ return description; } + + +AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t timeout_ms) : + Case(description, case_handler, 0, default_failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t repeats, const uint32_t timeout_ms) : + Case(description, case_handler, repeats, default_failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : + Case(description, case_handler, 0, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : + Case(description, case_handler, repeats, failure_handler, timeout_ms) {} diff --git "a/frameworks\\utest/source/failure_handler.cpp" "b/frameworks\\utest/source/failure_handler.cpp" new file mode 100644 index 0000000000..0ab2c98615 --- /dev/null +++ "b/frameworks\\utest/source/failure_handler.cpp" @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/async_test.h" + +using namespace mbed::test::v0; + +const char* +statusToString(status_t status) +{ + switch(status) + { + case STATUS_SUCCESS: + return "Success/Continue"; + case STATUS_ABORT: + return "Abort"; + + case STATUS_EXPECT_ASYNC_CALL: + return "Expect Asynchronous Call"; + + case STATUS_FAILURE: + return "Failure"; + case STATUS_FAILURE_TIMEOUT: + return "Failure (Timed Out)"; + case STATUS_FAILURE_ASSERTION: + return "Failure (Assertion Failed)"; + } + return "Unknown"; +} + +status_t mbed::test::v0::default_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::status_t reason) +{ + if (reason == STATUS_FAILURE_ASSERTION) printf("\n"); + printf(">>> '%s' failed with reason '%s'\n", source->getDescription(), statusToString(reason)); + return STATUS_CONTINUE; +} diff --git "a/frameworks\\utest/source/test_harness.cpp" "b/frameworks\\utest/source/test_harness.cpp" new file mode 100644 index 0000000000..32a7f3d1db --- /dev/null +++ "b/frameworks\\utest/source/test_harness.cpp" @@ -0,0 +1,157 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/async_test.h" + #include "minar/minar.h" + +using namespace mbed::test::v0; + +namespace +{ + const Test *specification = NULL; + size_t length = 0; + size_t number_of_tests = 0; + size_t index_of_tests = 0; + const Case *current = NULL; + set_up_handler_t set_up = NULL; + tear_down_handler_t tear_down = NULL; + int32_t repeats = 0; + + size_t passed = 0; + size_t failed = 0; + minar::callback_handle_t timeout_handle = NULL; +} + +static void die() { + while(1) ; +} + +mbed::test::v0::status_t mbed::test::v0::default_set_up_handler(const size_t number_of_tests) { + printf("\n>>> Running %u tests...\n", number_of_tests); + return STATUS_SUCCESS; +} + +void mbed::test::v0::default_tear_down_handler(const size_t _passed, const size_t _failed) { + printf("\n>>> Tear Down: %u passed, %u failed\n", _passed, _failed); + if (_failed) printf(">>> TESTS FAILED!\n"); +} + +void TestHarness::run(const Test *const _specification, + const size_t _length, + const set_up_handler_t _set_up, + const tear_down_handler_t _tear_down) +{ + specification = _specification; + length = _length; + set_up = _set_up; + tear_down = _tear_down; + number_of_tests = 0; + index_of_tests = 0; + + for (current = specification; current != (specification + length); current++) { + number_of_tests += 1 + current->repeats; + } + + current = specification; + repeats = current->repeats; + + if (set_up && (set_up(number_of_tests) != STATUS_SUCCESS)) { + printf(">>> Setup failed!\n"); + if (tear_down) tear_down(passed, failed); + die(); + } + + minar::Scheduler::postCallback(run_next_test); +} + +void TestHarness::handle_failure(status_t reason) +{ + failed++; + status_t fail_status = current->failure_handler(current, reason); + if (fail_status == STATUS_CONTINUE) { + current++; + minar::Scheduler::postCallback(run_next_test); + return; + } + if (tear_down) tear_down(passed, failed); + die(); +} + +void TestHarness::handle_timeout() +{ + if (timeout_handle != NULL) + { + handle_failure(STATUS_FAILURE_TIMEOUT); + timeout_handle = NULL; + } +} + +void TestHarness::validateCallback() +{ + if (timeout_handle != NULL) + { + minar::Scheduler::cancelCallback(timeout_handle); + printf(">>> Validated Callback...\n"); + passed++; + current++; + timeout_handle = NULL; + minar::Scheduler::postCallback(run_next_test); + } +} + +void TestHarness::run_next_test() +{ + if(current != (specification + length)) + { + Unity.CurrentTestFailed = false; + + TEST_PROTECT(); + if (Unity.CurrentTestFailed) { + if (timeout_handle) { + minar::Scheduler::cancelCallback(timeout_handle); + timeout_handle = NULL; + } + handle_failure(STATUS_FAILURE_ASSERTION); + return; + } + + printf("\n>>> Running #%u: '%s'...\n", ++index_of_tests, current->description); + + status_t status = current->case_handler(); + + if (status == STATUS_EXPECT_ASYNC_CALL) { + timeout_handle = minar::Scheduler::postCallback(handle_timeout) + .delay(minar::milliseconds(current->timeout_ms)) + .tolerance(0) + .getHandle(); + } + else if (status != STATUS_SUCCESS) { + handle_failure(status); + return; + } + else { + passed++; + if (repeats-- <= 0) { + current++; + repeats = current->repeats; + } + minar::Scheduler::postCallback(run_next_test); + } + } + else if (tear_down) tear_down(passed, failed); +} From eef649e49886a14e4f9acee0cef1435c21801258 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 10 Nov 2015 12:00:45 +0000 Subject: [PATCH 03/88] Remove return type from case handler. Use AsyncCase constructor to signal waiting for a async callback. --- "frameworks\\utest/source/case.cpp" | 10 +++++----- "frameworks\\utest/source/failure_handler.cpp" | 3 --- "frameworks\\utest/source/test_harness.cpp" | 14 +++++--------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index add3d8e861..2fb412267a 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -22,18 +22,18 @@ using namespace mbed::test::v0; Case::Case(const char *description, const case_handler_t case_handler) : - description(description), case_handler(case_handler), repeats(0), failure_handler(default_failure_handler), timeout_ms(0) {} + description(description), case_handler(case_handler), repeats(0), failure_handler(default_failure_handler), timeout_ms(-1) {} Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats) : - description(description), case_handler(case_handler), repeats(repeats), failure_handler(default_failure_handler), timeout_ms(0) {} + description(description), case_handler(case_handler), repeats(repeats), failure_handler(default_failure_handler), timeout_ms(-1) {} Case::Case(const char *description, const case_handler_t case_handler, const case_failure_handler_t failure_handler) : - description(description), case_handler(case_handler), repeats(0), failure_handler(failure_handler), timeout_ms(0) {} + description(description), case_handler(case_handler), repeats(0), failure_handler(failure_handler), timeout_ms(-1) {} Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler) : - description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(0) {} + description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(-1) {} -Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : +Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const int32_t timeout_ms) : description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(timeout_ms) {} const char* diff --git "a/frameworks\\utest/source/failure_handler.cpp" "b/frameworks\\utest/source/failure_handler.cpp" index 0ab2c98615..3256953e93 100644 --- "a/frameworks\\utest/source/failure_handler.cpp" +++ "b/frameworks\\utest/source/failure_handler.cpp" @@ -30,9 +30,6 @@ statusToString(status_t status) case STATUS_ABORT: return "Abort"; - case STATUS_EXPECT_ASYNC_CALL: - return "Expect Asynchronous Call"; - case STATUS_FAILURE: return "Failure"; case STATUS_FAILURE_TIMEOUT: diff --git "a/frameworks\\utest/source/test_harness.cpp" "b/frameworks\\utest/source/test_harness.cpp" index 32a7f3d1db..7826aa3424 100644 --- "a/frameworks\\utest/source/test_harness.cpp" +++ "b/frameworks\\utest/source/test_harness.cpp" @@ -132,17 +132,13 @@ void TestHarness::run_next_test() printf("\n>>> Running #%u: '%s'...\n", ++index_of_tests, current->description); - status_t status = current->case_handler(); + current->case_handler(); - if (status == STATUS_EXPECT_ASYNC_CALL) { + if (current->timeout_ms >= 0) { timeout_handle = minar::Scheduler::postCallback(handle_timeout) - .delay(minar::milliseconds(current->timeout_ms)) - .tolerance(0) - .getHandle(); - } - else if (status != STATUS_SUCCESS) { - handle_failure(status); - return; + .delay(minar::milliseconds(current->timeout_ms)) + .tolerance(0) + .getHandle(); } else { passed++; From 9f770f8ec8766445c408d3585647d38922988243 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 10 Nov 2015 17:41:12 +0000 Subject: [PATCH 04/88] This commits gets rid of all dependencies on unity. Failures will not longjmp, but are reported on top of the stack, by calling the case failure handler, which then decides whether to continue or abort testing. Other changes: - Individual cases can have their own setup and teardown handlers, - Case repeats are now handled by the case handler returning `control_flow_t`, - Separates `status_t` and `failure_t`, - Implements useful default case setup and teardown, and - Keeps score of passes and failures on per case and test basis. --- "frameworks\\utest/source/case.cpp" | 84 +++++--- .../source/default_handlers.cpp" | 81 ++++++++ .../source/failure_handler.cpp" | 48 ----- "frameworks\\utest/source/test_harness.cpp" | 186 ++++++++++-------- 4 files changed, 240 insertions(+), 159 deletions(-) create mode 100644 "frameworks\\utest/source/default_handlers.cpp" delete mode 100644 "frameworks\\utest/source/failure_handler.cpp" diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 2fb412267a..f4b4c25565 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -21,34 +21,70 @@ using namespace mbed::test::v0; -Case::Case(const char *description, const case_handler_t case_handler) : - description(description), case_handler(case_handler), repeats(0), failure_handler(default_failure_handler), timeout_ms(-1) {} +Case::Case(const char *description, + const case_handler_t handler, + const case_set_up_handler_t set_up_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(handler), + control_flow_handler(NULL), + set_up_handler(set_up_handler), + tear_down_handler(tear_down_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} -Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats) : - description(description), case_handler(case_handler), repeats(repeats), failure_handler(default_failure_handler), timeout_ms(-1) {} +Case::Case(const char *description, + const case_control_flow_handler_t control_flow_handler, + const case_set_up_handler_t set_up_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(NULL), + control_flow_handler(control_flow_handler), + set_up_handler(set_up_handler), + tear_down_handler(tear_down_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} -Case::Case(const char *description, const case_handler_t case_handler, const case_failure_handler_t failure_handler) : - description(description), case_handler(case_handler), repeats(0), failure_handler(failure_handler), timeout_ms(-1) {} - -Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler) : - description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(-1) {} - -Case::Case(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const int32_t timeout_ms) : - description(description), case_handler(case_handler), repeats(repeats), failure_handler(failure_handler), timeout_ms(timeout_ms) {} +Case::Case(const char *description, + const case_handler_t handler, + const case_control_flow_handler_t control_flow_handler, + const case_set_up_handler_t set_up_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler, + const int32_t timeout_ms) : + description(description), + handler(handler), + control_flow_handler(control_flow_handler), + set_up_handler(set_up_handler), + tear_down_handler(tear_down_handler), + failure_handler(failure_handler), + timeout_ms(timeout_ms) +{} const char* -Case::getDescription() const -{ return description; } +Case::get_description() const { + return description; +} -AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t timeout_ms) : - Case(description, case_handler, 0, default_failure_handler, timeout_ms) {} +AsyncCase::AsyncCase(const char *description, + const case_handler_t handler, + const uint32_t timeout_ms, + const case_set_up_handler_t set_up_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + Case(description, handler, NULL, set_up_handler, tear_down_handler, failure_handler, timeout_ms) +{} -AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t repeats, const uint32_t timeout_ms) : - Case(description, case_handler, repeats, default_failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, case_handler, 0, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, const uint32_t repeats, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, case_handler, repeats, failure_handler, timeout_ms) {} +AsyncCase::AsyncCase(const char *description, + const case_control_flow_handler_t control_flow_handler, + const uint32_t timeout_ms, + const case_set_up_handler_t set_up_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + Case(description, NULL, control_flow_handler, set_up_handler, tear_down_handler, failure_handler, timeout_ms) +{} diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" new file mode 100644 index 0000000000..a7e0b460fa --- /dev/null +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/async_test.h" + +using namespace mbed::test::v0; + +const char* +failureToString(failure_t failure) +{ + switch(failure) + { + case FAILURE_NONE: + return "No Failure"; + case FAILURE: + return "Unspecified Failure"; + case FAILURE_SETUP: + return "Setup Failed"; + case FAILURE_TEARDOWN: + return "Teardown Failed"; + case FAILURE_TIMEOUT: + return "Timed Out"; + case FAILURE_ASSERTION: + return "Assertion Failed"; + } + return "Unknown Failure"; +} + +mbed::test::v0::status_t mbed::test::v0::default_test_set_up_handler(const size_t number_of_cases) +{ + printf("\n>>> Running %u test cases...\n", number_of_cases); + return STATUS_CONTINUE; +} + +void mbed::test::v0::default_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) +{ + printf("\n>>> Test Cases: %u passed, %u failed", passed, failed); + if (failure == FAILURE_NONE) { + printf("\n"); + } else { + printf(" with reason '%s'\n", failureToString(failure)); + } + if (failed) printf(">>> TESTS FAILED!\n"); +} + +mbed::test::v0::status_t mbed::test::v0::default_case_set_up_handler(const mbed::test::v0::Case *const source, const size_t index_of_case) +{ + printf("\n>>> Running #%u: '%s'...\n", index_of_case, source->get_description()); + return STATUS_CONTINUE; +} + +mbed::test::v0::status_t mbed::test::v0::default_case_tear_down_handler(const mbed::test::v0::Case *const source, const size_t passed, const size_t failed) +{ + printf(">>> '%s': %u passed, %u failed\n", source->get_description(), passed, failed); + return STATUS_CONTINUE; +} + +status_t mbed::test::v0::default_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) +{ + if (reason == FAILURE_ASSERTION) { + printf("\n"); + } else { + printf(">>> '%s' failed with reason '%s'\n", source->get_description(), failureToString(reason)); + } + return STATUS_CONTINUE; +} diff --git "a/frameworks\\utest/source/failure_handler.cpp" "b/frameworks\\utest/source/failure_handler.cpp" deleted file mode 100644 index 3256953e93..0000000000 --- "a/frameworks\\utest/source/failure_handler.cpp" +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - * Copyright (c) 2015, 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-test-async/async_test.h" - -using namespace mbed::test::v0; - -const char* -statusToString(status_t status) -{ - switch(status) - { - case STATUS_SUCCESS: - return "Success/Continue"; - case STATUS_ABORT: - return "Abort"; - - case STATUS_FAILURE: - return "Failure"; - case STATUS_FAILURE_TIMEOUT: - return "Failure (Timed Out)"; - case STATUS_FAILURE_ASSERTION: - return "Failure (Assertion Failed)"; - } - return "Unknown"; -} - -status_t mbed::test::v0::default_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::status_t reason) -{ - if (reason == STATUS_FAILURE_ASSERTION) printf("\n"); - printf(">>> '%s' failed with reason '%s'\n", source->getDescription(), statusToString(reason)); - return STATUS_CONTINUE; -} diff --git "a/frameworks\\utest/source/test_harness.cpp" "b/frameworks\\utest/source/test_harness.cpp" index 7826aa3424..4d03b3ce98 100644 --- "a/frameworks\\utest/source/test_harness.cpp" +++ "b/frameworks\\utest/source/test_harness.cpp" @@ -21,133 +21,145 @@ using namespace mbed::test::v0; + namespace { - const Test *specification = NULL; - size_t length = 0; - size_t number_of_tests = 0; - size_t index_of_tests = 0; - const Case *current = NULL; - set_up_handler_t set_up = NULL; - tear_down_handler_t tear_down = NULL; - int32_t repeats = 0; + const Test *test_specification = NULL; + size_t test_length = 0; - size_t passed = 0; - size_t failed = 0; - minar::callback_handle_t timeout_handle = NULL; + test_set_up_handler_t test_set_up_handler = NULL; + test_tear_down_handler_t test_tear_down_handler = NULL; + + size_t test_index_of_case = 0; + + size_t test_passed = 0; + size_t test_failed = 0; + + const Case *case_current = NULL; + control_flow_t case_control_flow = CONTROL_FLOW_NEXT; + + minar::callback_handle_t case_timeout_handle = NULL; + + size_t case_passed = 0; + size_t case_failed = 0; + size_t case_failed_before = 0; } static void die() { while(1) ; } -mbed::test::v0::status_t mbed::test::v0::default_set_up_handler(const size_t number_of_tests) { - printf("\n>>> Running %u tests...\n", number_of_tests); - return STATUS_SUCCESS; -} - -void mbed::test::v0::default_tear_down_handler(const size_t _passed, const size_t _failed) { - printf("\n>>> Tear Down: %u passed, %u failed\n", _passed, _failed); - if (_failed) printf(">>> TESTS FAILED!\n"); -} - -void TestHarness::run(const Test *const _specification, - const size_t _length, - const set_up_handler_t _set_up, - const tear_down_handler_t _tear_down) +void TestHarness::run(const Test *const specification, + const size_t length, + const test_set_up_handler_t set_up_handler, + const test_tear_down_handler_t tear_down_handler) { - specification = _specification; - length = _length; - set_up = _set_up; - tear_down = _tear_down; - number_of_tests = 0; - index_of_tests = 0; + test_specification = specification; + test_length = length; + test_set_up_handler = set_up_handler; + test_tear_down_handler = tear_down_handler; - for (current = specification; current != (specification + length); current++) { - number_of_tests += 1 + current->repeats; - } + test_index_of_case = 0; + test_passed = 0; + test_failed = 0; - current = specification; - repeats = current->repeats; + case_passed = 0; + case_failed = 0; + case_failed_before = 0; + case_current = specification; - if (set_up && (set_up(number_of_tests) != STATUS_SUCCESS)) { - printf(">>> Setup failed!\n"); - if (tear_down) tear_down(passed, failed); + if (test_set_up_handler && (test_set_up_handler(test_length) != STATUS_CONTINUE)) { + if (test_tear_down_handler) test_tear_down_handler(0, 0, FAILURE_SETUP); die(); } - minar::Scheduler::postCallback(run_next_test); + minar::Scheduler::postCallback(run_next_case); } -void TestHarness::handle_failure(status_t reason) +void TestHarness::raise_failure(failure_t reason) { - failed++; - status_t fail_status = current->failure_handler(current, reason); - if (fail_status == STATUS_CONTINUE) { - current++; - minar::Scheduler::postCallback(run_next_test); - return; + case_failed++; + status_t fail_status = case_current->failure_handler(case_current, reason); + if (fail_status != STATUS_CONTINUE) { + if (case_current->tear_down_handler) case_current->tear_down_handler(case_current, case_passed, case_failed); + test_failed++; + if (test_tear_down_handler) test_tear_down_handler(test_passed, test_failed, reason); + die(); } - if (tear_down) tear_down(passed, failed); - die(); +} + +void TestHarness::schedule_next_case() +{ + if (case_failed_before == case_failed) case_passed++; + if(case_control_flow == CONTROL_FLOW_NEXT) { + if (case_current->tear_down_handler) { + if (case_current->tear_down_handler(case_current, case_passed, case_failed) != STATUS_CONTINUE) { + raise_failure(FAILURE_TEARDOWN); + } + } + + if (case_failed > 0) test_failed++; + else test_passed++; + + case_current++; + case_passed = 0; + case_failed = 0; + case_failed_before = 0; + } + minar::Scheduler::postCallback(run_next_case); } void TestHarness::handle_timeout() { - if (timeout_handle != NULL) + if (case_timeout_handle != NULL) { - handle_failure(STATUS_FAILURE_TIMEOUT); - timeout_handle = NULL; + raise_failure(FAILURE_TIMEOUT); + case_timeout_handle = NULL; + schedule_next_case(); } } -void TestHarness::validateCallback() +void TestHarness::validate_callback() { - if (timeout_handle != NULL) + if (case_timeout_handle != NULL) { - minar::Scheduler::cancelCallback(timeout_handle); - printf(">>> Validated Callback...\n"); - passed++; - current++; - timeout_handle = NULL; - minar::Scheduler::postCallback(run_next_test); + minar::Scheduler::cancelCallback(case_timeout_handle); + case_timeout_handle = NULL; + schedule_next_case(); } } -void TestHarness::run_next_test() +void TestHarness::run_next_case() { - if(current != (specification + length)) + if(case_current != (test_specification + test_length)) { - Unity.CurrentTestFailed = false; - - TEST_PROTECT(); - if (Unity.CurrentTestFailed) { - if (timeout_handle) { - minar::Scheduler::cancelCallback(timeout_handle); - timeout_handle = NULL; + if (case_current->set_up_handler) { + if (case_current->set_up_handler(case_current, test_index_of_case) != STATUS_CONTINUE) { + raise_failure(FAILURE_SETUP); } - handle_failure(STATUS_FAILURE_ASSERTION); - return; + } + test_index_of_case++; + + case_failed_before = case_failed; + + if (case_current->handler) { + case_control_flow = CONTROL_FLOW_NEXT; + case_current->handler(); + } else if (case_current->control_flow_handler) { + case_control_flow = case_current->control_flow_handler(); } - printf("\n>>> Running #%u: '%s'...\n", ++index_of_tests, current->description); - - current->case_handler(); - - if (current->timeout_ms >= 0) { - timeout_handle = minar::Scheduler::postCallback(handle_timeout) - .delay(minar::milliseconds(current->timeout_ms)) - .tolerance(0) - .getHandle(); + if (case_current->timeout_ms >= 0) { + case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) + .delay(minar::milliseconds(case_current->timeout_ms)) + .tolerance(0) + .getHandle(); } else { - passed++; - if (repeats-- <= 0) { - current++; - repeats = current->repeats; - } - minar::Scheduler::postCallback(run_next_test); + schedule_next_case(); } } - else if (tear_down) tear_down(passed, failed); + else if (test_tear_down_handler) { + test_tear_down_handler(test_passed, test_failed, FAILURE_NONE); + } } From ded41049fba3195e2c8a2e6b2017ca26ac28da9a Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 10 Nov 2015 17:41:35 +0000 Subject: [PATCH 05/88] Add unity assertion failure callback handler. --- "frameworks\\utest/source/unity_handler.cpp" | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 "frameworks\\utest/source/unity_handler.cpp" diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" new file mode 100644 index 0000000000..199b66e7fe --- /dev/null +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -0,0 +1,25 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/async_test.h" + +extern "C" +void mbed_test_unity_assert_failure() +{ + mbed::test::v0::TestHarness::raise_failure(mbed::test::v0::FAILURE_ASSERTION); +} From 171033622ba125ac6301f1b86f312374764ffdf4 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 11:15:21 +0000 Subject: [PATCH 06/88] Move types and classes into seperate header files. Rename TestHarness to Harness. --- "frameworks\\utest/source/case.cpp" | 2 +- "frameworks\\utest/source/default_handlers.cpp" | 3 ++- .../source/harness.cpp" | 14 +++++++------- "frameworks\\utest/source/unity_handler.cpp" | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) rename "frameworks\\utest/source/test_harness.cpp" => "frameworks\\utest/source/harness.cpp" (94%) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index f4b4c25565..c783318ded 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/async_test.h" + #include "mbed-test-async/case.h" using namespace mbed::test::v0; diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index a7e0b460fa..70e7c4381f 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -16,7 +16,8 @@ **************************************************************************** */ - #include "mbed-test-async/async_test.h" + #include "mbed-test-async/default_handlers.h" + #include "mbed-test-async/case.h" using namespace mbed::test::v0; diff --git "a/frameworks\\utest/source/test_harness.cpp" "b/frameworks\\utest/source/harness.cpp" similarity index 94% rename from "frameworks\\utest/source/test_harness.cpp" rename to "frameworks\\utest/source/harness.cpp" index 4d03b3ce98..21c54396c4 100644 --- "a/frameworks\\utest/source/test_harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/async_test.h" + #include "mbed-test-async/harness.h" #include "minar/minar.h" using namespace mbed::test::v0; @@ -49,7 +49,7 @@ static void die() { while(1) ; } -void TestHarness::run(const Test *const specification, +void Harness::run(const Test *const specification, const size_t length, const test_set_up_handler_t set_up_handler, const test_tear_down_handler_t tear_down_handler) @@ -76,7 +76,7 @@ void TestHarness::run(const Test *const specification, minar::Scheduler::postCallback(run_next_case); } -void TestHarness::raise_failure(failure_t reason) +void Harness::raise_failure(failure_t reason) { case_failed++; status_t fail_status = case_current->failure_handler(case_current, reason); @@ -88,7 +88,7 @@ void TestHarness::raise_failure(failure_t reason) } } -void TestHarness::schedule_next_case() +void Harness::schedule_next_case() { if (case_failed_before == case_failed) case_passed++; if(case_control_flow == CONTROL_FLOW_NEXT) { @@ -109,7 +109,7 @@ void TestHarness::schedule_next_case() minar::Scheduler::postCallback(run_next_case); } -void TestHarness::handle_timeout() +void Harness::handle_timeout() { if (case_timeout_handle != NULL) { @@ -119,7 +119,7 @@ void TestHarness::handle_timeout() } } -void TestHarness::validate_callback() +void Harness::validate_callback() { if (case_timeout_handle != NULL) { @@ -129,7 +129,7 @@ void TestHarness::validate_callback() } } -void TestHarness::run_next_case() +void Harness::run_next_case() { if(case_current != (test_specification + test_length)) { diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index 199b66e7fe..d9fe591a86 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -16,10 +16,10 @@ **************************************************************************** */ - #include "mbed-test-async/async_test.h" + #include "mbed-test-async/harness.h" extern "C" void mbed_test_unity_assert_failure() { - mbed::test::v0::TestHarness::raise_failure(mbed::test::v0::FAILURE_ASSERTION); + mbed::test::v0::Harness::raise_failure(mbed::test::v0::FAILURE_ASSERTION); } From 06fc81f99d0a8b6b9eb70a3867171782d43aa703 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 13:27:09 +0000 Subject: [PATCH 07/88] Add much better default handler declaration and usage. --- .../source/default_handlers.cpp" | 10 ++-- "frameworks\\utest/source/harness.cpp" | 48 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 70e7c4381f..f400836f94 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -42,13 +42,13 @@ failureToString(failure_t failure) return "Unknown Failure"; } -mbed::test::v0::status_t mbed::test::v0::default_test_set_up_handler(const size_t number_of_cases) +mbed::test::v0::status_t mbed::test::v0::verbose_test_set_up_handler(const size_t number_of_cases) { printf("\n>>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; } -void mbed::test::v0::default_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) +void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) { printf("\n>>> Test Cases: %u passed, %u failed", passed, failed); if (failure == FAILURE_NONE) { @@ -59,19 +59,19 @@ void mbed::test::v0::default_test_tear_down_handler(const size_t passed, const s if (failed) printf(">>> TESTS FAILED!\n"); } -mbed::test::v0::status_t mbed::test::v0::default_case_set_up_handler(const mbed::test::v0::Case *const source, const size_t index_of_case) +mbed::test::v0::status_t mbed::test::v0::verbose_case_set_up_handler(const mbed::test::v0::Case *const source, const size_t index_of_case) { printf("\n>>> Running #%u: '%s'...\n", index_of_case, source->get_description()); return STATUS_CONTINUE; } -mbed::test::v0::status_t mbed::test::v0::default_case_tear_down_handler(const mbed::test::v0::Case *const source, const size_t passed, const size_t failed) +mbed::test::v0::status_t mbed::test::v0::verbose_case_tear_down_handler(const mbed::test::v0::Case *const source, const size_t passed, const size_t failed) { printf(">>> '%s': %u passed, %u failed\n", source->get_description(), passed, failed); return STATUS_CONTINUE; } -status_t mbed::test::v0::default_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) +status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) { if (reason == FAILURE_ASSERTION) { printf("\n"); diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 21c54396c4..6221519a63 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -27,9 +27,6 @@ namespace const Test *test_specification = NULL; size_t test_length = 0; - test_set_up_handler_t test_set_up_handler = NULL; - test_tear_down_handler_t test_tear_down_handler = NULL; - size_t test_index_of_case = 0; size_t test_passed = 0; @@ -43,12 +40,20 @@ namespace size_t case_passed = 0; size_t case_failed = 0; size_t case_failed_before = 0; + + handlers_t defaults = verbose_handlers; + handlers_t handlers = defaults; } static void die() { while(1) ; } +void Harness::set_default_handlers(const handlers_t defaults) +{ + ::defaults = defaults; +} + void Harness::run(const Test *const specification, const size_t length, const test_set_up_handler_t set_up_handler, @@ -56,8 +61,8 @@ void Harness::run(const Test *const specification, { test_specification = specification; test_length = length; - test_set_up_handler = set_up_handler; - test_tear_down_handler = tear_down_handler; + handlers.test_set_up = defaults.get_handler(set_up_handler); + handlers.test_tear_down = defaults.get_handler(tear_down_handler); test_index_of_case = 0; test_passed = 0; @@ -68,8 +73,8 @@ void Harness::run(const Test *const specification, case_failed_before = 0; case_current = specification; - if (test_set_up_handler && (test_set_up_handler(test_length) != STATUS_CONTINUE)) { - if (test_tear_down_handler) test_tear_down_handler(0, 0, FAILURE_SETUP); + if (handlers.test_set_up && (handlers.test_set_up(test_length) != STATUS_CONTINUE)) { + if (handlers.test_tear_down) handlers.test_tear_down(0, 0, FAILURE_SETUP); die(); } @@ -79,11 +84,13 @@ void Harness::run(const Test *const specification, void Harness::raise_failure(failure_t reason) { case_failed++; - status_t fail_status = case_current->failure_handler(case_current, reason); + if (!handlers.case_failure) return; + + status_t fail_status = handlers.case_failure(case_current, reason); if (fail_status != STATUS_CONTINUE) { - if (case_current->tear_down_handler) case_current->tear_down_handler(case_current, case_passed, case_failed); + if (handlers.case_tear_down) handlers.case_tear_down(case_current, case_passed, case_failed); test_failed++; - if (test_tear_down_handler) test_tear_down_handler(test_passed, test_failed, reason); + if (handlers.test_tear_down) handlers.test_tear_down(test_passed, test_failed, reason); die(); } } @@ -91,11 +98,10 @@ void Harness::raise_failure(failure_t reason) void Harness::schedule_next_case() { if (case_failed_before == case_failed) case_passed++; + if(case_control_flow == CONTROL_FLOW_NEXT) { - if (case_current->tear_down_handler) { - if (case_current->tear_down_handler(case_current, case_passed, case_failed) != STATUS_CONTINUE) { - raise_failure(FAILURE_TEARDOWN); - } + if (handlers.case_tear_down && (handlers.case_tear_down(case_current, case_passed, case_failed) != STATUS_CONTINUE)) { + raise_failure(FAILURE_TEARDOWN); } if (case_failed > 0) test_failed++; @@ -133,10 +139,12 @@ void Harness::run_next_case() { if(case_current != (test_specification + test_length)) { - if (case_current->set_up_handler) { - if (case_current->set_up_handler(case_current, test_index_of_case) != STATUS_CONTINUE) { - raise_failure(FAILURE_SETUP); - } + handlers.case_set_up = defaults.get_handler(case_current->set_up_handler); + handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); + handlers.case_failure = defaults.get_handler(case_current->failure_handler); + + if (handlers.case_set_up && (handlers.case_set_up(case_current, test_index_of_case) != STATUS_CONTINUE)) { + raise_failure(FAILURE_SETUP); } test_index_of_case++; @@ -159,7 +167,7 @@ void Harness::run_next_case() schedule_next_case(); } } - else if (test_tear_down_handler) { - test_tear_down_handler(test_passed, test_failed, FAILURE_NONE); + else if (handlers.test_tear_down) { + handlers.test_tear_down(test_passed, test_failed, FAILURE_NONE); } } From 64f54ed35c587ec695b9efea42a6eadb89948f04 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 13:49:03 +0000 Subject: [PATCH 08/88] Harness: Call case setup only once for control flow cases. --- "frameworks\\utest/source/default_handlers.cpp" | 2 +- "frameworks\\utest/source/harness.cpp" | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index f400836f94..76b1151b14 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -61,7 +61,7 @@ void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const s mbed::test::v0::status_t mbed::test::v0::verbose_case_set_up_handler(const mbed::test::v0::Case *const source, const size_t index_of_case) { - printf("\n>>> Running #%u: '%s'...\n", index_of_case, source->get_description()); + printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); return STATUS_CONTINUE; } diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 6221519a63..658fdd044f 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -143,10 +143,12 @@ void Harness::run_next_case() handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); handlers.case_failure = defaults.get_handler(case_current->failure_handler); - if (handlers.case_set_up && (handlers.case_set_up(case_current, test_index_of_case) != STATUS_CONTINUE)) { - raise_failure(FAILURE_SETUP); + if (!case_failed && !case_passed) { + if (handlers.case_set_up && (handlers.case_set_up(case_current, test_index_of_case) != STATUS_CONTINUE)) { + raise_failure(FAILURE_SETUP); + } + test_index_of_case++; } - test_index_of_case++; case_failed_before = case_failed; From ad8fdc62d6f2c5debd8bbfef0f94055fbd6dd957 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 13:53:45 +0000 Subject: [PATCH 09/88] Defaults: Set greentea default handlers. --- .../source/default_handlers.cpp" | 41 +++++++++++++++++++ "frameworks\\utest/source/harness.cpp" | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 76b1151b14..5c9196b470 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -80,3 +80,44 @@ status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case } return STATUS_CONTINUE; } + + + +mbed::test::v0::status_t mbed::test::v0::greentea_test_set_up_handler(const size_t number_of_cases) +{ + printf("{{timeout;%u}}\n", number_of_cases); + printf("{{host_test_name;default_auto}}\n"); + printf("{{description;default_greentea_handler_test}}\n"); + printf("{{test_id;default_greentea_handler_test}}\n"); + printf("{{start}}\n"); + + return STATUS_CONTINUE; +} + +void mbed::test::v0::greentea_test_tear_down_handler(const size_t /*passed*/, const size_t failed, const failure_t failure) +{ + if (failed || failure != FAILURE_NONE) { + printf("{{failure}}\n"); + } else { + printf("{{success}}\n"); + } + printf("{{end}}\n"); +} + +mbed::test::v0::status_t mbed::test::v0::greentea_case_set_up_handler(const mbed::test::v0::Case *const /*source*/, const size_t /*index_of_case*/) +{ + return STATUS_CONTINUE; +} + +mbed::test::v0::status_t mbed::test::v0::greentea_case_tear_down_handler(const mbed::test::v0::Case *const /*source*/, const size_t /*passed*/, const size_t /*failed*/) +{ + return STATUS_CONTINUE; +} + +status_t mbed::test::v0::greentea_case_failure_handler(const mbed::test::v0::Case *const /*source*/, const mbed::test::v0::failure_t reason) +{ + if (reason == FAILURE_ASSERTION) { + printf("\n"); + } + return STATUS_ABORT; +} diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 658fdd044f..247219fe2f 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -41,7 +41,7 @@ namespace size_t case_failed = 0; size_t case_failed_before = 0; - handlers_t defaults = verbose_handlers; + handlers_t defaults = greentea_handlers; handlers_t handlers = defaults; } From 303fa5a3a0b43e72eb6155980f70279079598e3a Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 14:10:18 +0000 Subject: [PATCH 10/88] Defaults: Make Greentea handlers more verbose. --- .../source/default_handlers.cpp" | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 5c9196b470..b4ef75b36a 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -44,7 +44,7 @@ failureToString(failure_t failure) mbed::test::v0::status_t mbed::test::v0::verbose_test_set_up_handler(const size_t number_of_cases) { - printf("\n>>> Running %u test cases...\n", number_of_cases); + printf(">>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; } @@ -71,12 +71,12 @@ mbed::test::v0::status_t mbed::test::v0::verbose_case_tear_down_handler(const mb return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) +status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case *const /*source*/, const mbed::test::v0::failure_t reason) { if (reason == FAILURE_ASSERTION) { printf("\n"); } else { - printf(">>> '%s' failed with reason '%s'\n", source->get_description(), failureToString(reason)); + printf(">>> failed with reason '%s'\n", failureToString(reason)); } return STATUS_CONTINUE; } @@ -91,11 +91,14 @@ mbed::test::v0::status_t mbed::test::v0::greentea_test_set_up_handler(const size printf("{{test_id;default_greentea_handler_test}}\n"); printf("{{start}}\n"); + verbose_test_set_up_handler(number_of_cases); + return STATUS_CONTINUE; } -void mbed::test::v0::greentea_test_tear_down_handler(const size_t /*passed*/, const size_t failed, const failure_t failure) +void mbed::test::v0::greentea_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) { + verbose_test_tear_down_handler(passed, failed, failure); if (failed || failure != FAILURE_NONE) { printf("{{failure}}\n"); } else { @@ -104,20 +107,8 @@ void mbed::test::v0::greentea_test_tear_down_handler(const size_t /*passed*/, co printf("{{end}}\n"); } -mbed::test::v0::status_t mbed::test::v0::greentea_case_set_up_handler(const mbed::test::v0::Case *const /*source*/, const size_t /*index_of_case*/) +status_t mbed::test::v0::greentea_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) { - return STATUS_CONTINUE; -} - -mbed::test::v0::status_t mbed::test::v0::greentea_case_tear_down_handler(const mbed::test::v0::Case *const /*source*/, const size_t /*passed*/, const size_t /*failed*/) -{ - return STATUS_CONTINUE; -} - -status_t mbed::test::v0::greentea_case_failure_handler(const mbed::test::v0::Case *const /*source*/, const mbed::test::v0::failure_t reason) -{ - if (reason == FAILURE_ASSERTION) { - printf("\n"); - } + verbose_case_failure_handler(source, reason); return STATUS_ABORT; } From cbac633aa577820e27867f2d864f3040073a57ac Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 15:32:04 +0000 Subject: [PATCH 11/88] Defaults: Remove unnecessary namespaces. --- "frameworks\\utest/source/default_handlers.cpp" | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index b4ef75b36a..5747df5c38 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -21,8 +21,7 @@ using namespace mbed::test::v0; -const char* -failureToString(failure_t failure) +const char* failureToString(failure_t failure) { switch(failure) { @@ -42,7 +41,7 @@ failureToString(failure_t failure) return "Unknown Failure"; } -mbed::test::v0::status_t mbed::test::v0::verbose_test_set_up_handler(const size_t number_of_cases) +status_t mbed::test::v0::verbose_test_set_up_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; @@ -50,7 +49,7 @@ mbed::test::v0::status_t mbed::test::v0::verbose_test_set_up_handler(const size_ void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) { - printf("\n>>> Test Cases: %u passed, %u failed", passed, failed); + printf("\n>>> Test cases: %u passed, %u failed", passed, failed); if (failure == FAILURE_NONE) { printf("\n"); } else { @@ -59,19 +58,19 @@ void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const s if (failed) printf(">>> TESTS FAILED!\n"); } -mbed::test::v0::status_t mbed::test::v0::verbose_case_set_up_handler(const mbed::test::v0::Case *const source, const size_t index_of_case) +status_t mbed::test::v0::verbose_case_set_up_handler(const Case *const source, const size_t index_of_case) { printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); return STATUS_CONTINUE; } -mbed::test::v0::status_t mbed::test::v0::verbose_case_tear_down_handler(const mbed::test::v0::Case *const source, const size_t passed, const size_t failed) +status_t mbed::test::v0::verbose_case_tear_down_handler(const Case *const source, const size_t passed, const size_t failed) { printf(">>> '%s': %u passed, %u failed\n", source->get_description(), passed, failed); return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case *const /*source*/, const mbed::test::v0::failure_t reason) +status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { if (reason == FAILURE_ASSERTION) { printf("\n"); @@ -83,7 +82,7 @@ status_t mbed::test::v0::verbose_case_failure_handler(const mbed::test::v0::Case -mbed::test::v0::status_t mbed::test::v0::greentea_test_set_up_handler(const size_t number_of_cases) +status_t mbed::test::v0::greentea_test_set_up_handler(const size_t number_of_cases) { printf("{{timeout;%u}}\n", number_of_cases); printf("{{host_test_name;default_auto}}\n"); @@ -107,7 +106,7 @@ void mbed::test::v0::greentea_test_tear_down_handler(const size_t passed, const printf("{{end}}\n"); } -status_t mbed::test::v0::greentea_case_failure_handler(const mbed::test::v0::Case *const source, const mbed::test::v0::failure_t reason) +status_t mbed::test::v0::greentea_case_failure_handler(const Case *const source, const failure_t reason) { verbose_case_failure_handler(source, reason); return STATUS_ABORT; From 8d8461247236a7a28f7fbde55caa49874e4a7420 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 15:33:46 +0000 Subject: [PATCH 12/88] Harness: Add correct handling of failures in setup and teardown handlers. --- .../source/default_handlers.cpp" | 13 +++++++-- "frameworks\\utest/source/harness.cpp" | 28 ++++++++++++++----- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 5747df5c38..ddf3eafc27 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -29,6 +29,8 @@ const char* failureToString(failure_t failure) return "No Failure"; case FAILURE: return "Unspecified Failure"; + case FAILURE_CASES: + return "Test Cases Failed"; case FAILURE_SETUP: return "Setup Failed"; case FAILURE_TEARDOWN: @@ -64,9 +66,14 @@ status_t mbed::test::v0::verbose_case_set_up_handler(const Case *const source, c return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_tear_down_handler(const Case *const source, const size_t passed, const size_t failed) +status_t mbed::test::v0::verbose_case_tear_down_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) { - printf(">>> '%s': %u passed, %u failed\n", source->get_description(), passed, failed); + printf(">>> '%s': %u passed, %u failed", source->get_description(), passed, failed); + if (failure == FAILURE_NONE) { + printf("\n"); + } else { + printf(" with reason '%s'\n", failureToString(failure)); + } return STATUS_CONTINUE; } @@ -77,7 +84,7 @@ status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source } else { printf(">>> failed with reason '%s'\n", failureToString(reason)); } - return STATUS_CONTINUE; + return (reason == FAILURE_TEARDOWN) ? STATUS_ABORT : STATUS_CONTINUE; } diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 247219fe2f..76f07649ec 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -84,11 +84,20 @@ void Harness::run(const Test *const specification, void Harness::raise_failure(failure_t reason) { case_failed++; - if (!handlers.case_failure) return; + status_t fail_status = STATUS_ABORT; - status_t fail_status = handlers.case_failure(case_current, reason); + if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); + + if (fail_status != STATUS_CONTINUE || reason == FAILURE_SETUP) { + if (handlers.case_tear_down && reason != FAILURE_TEARDOWN) { + status_t teardown_status = handlers.case_tear_down(case_current, case_passed, case_failed, reason); + if (teardown_status != STATUS_CONTINUE) { + raise_failure(FAILURE_TEARDOWN); + } + else handlers.case_tear_down = NULL; + } + } if (fail_status != STATUS_CONTINUE) { - if (handlers.case_tear_down) handlers.case_tear_down(case_current, case_passed, case_failed); test_failed++; if (handlers.test_tear_down) handlers.test_tear_down(test_passed, test_failed, reason); die(); @@ -100,7 +109,9 @@ void Harness::schedule_next_case() if (case_failed_before == case_failed) case_passed++; if(case_control_flow == CONTROL_FLOW_NEXT) { - if (handlers.case_tear_down && (handlers.case_tear_down(case_current, case_passed, case_failed) != STATUS_CONTINUE)) { + if (handlers.case_tear_down && + (handlers.case_tear_down(case_current, case_passed, case_failed, + case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { raise_failure(FAILURE_TEARDOWN); } @@ -144,10 +155,12 @@ void Harness::run_next_case() handlers.case_failure = defaults.get_handler(case_current->failure_handler); if (!case_failed && !case_passed) { - if (handlers.case_set_up && (handlers.case_set_up(case_current, test_index_of_case) != STATUS_CONTINUE)) { + size_t index = test_index_of_case++; + if (handlers.case_set_up && (handlers.case_set_up(case_current, index) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); + schedule_next_case(); + return; } - test_index_of_case++; } case_failed_before = case_failed; @@ -170,6 +183,7 @@ void Harness::run_next_case() } } else if (handlers.test_tear_down) { - handlers.test_tear_down(test_passed, test_failed, FAILURE_NONE); + handlers.test_tear_down(test_passed, test_failed, test_failed ? FAILURE_CASES : FAILURE_NONE); + die(); } } From 2bbf725bcc66a7dcf923248f5feeedac5eba8ac5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 11 Nov 2015 18:30:29 +0000 Subject: [PATCH 13/88] Harness: Make it interrupt safe. We do not want to have a call to `validate_callback()` before `run_next_case()` is finished or while `handle_timeout()` is executing. --- "frameworks\\utest/source/harness.cpp" | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 76f07649ec..f2d9371c77 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -18,6 +18,7 @@ #include "mbed-test-async/harness.h" #include "minar/minar.h" + #include "core-util/CriticalSectionLock.h" using namespace mbed::test::v0; @@ -59,6 +60,8 @@ void Harness::run(const Test *const specification, const test_set_up_handler_t set_up_handler, const test_tear_down_handler_t tear_down_handler) { + util::CriticalSectionLock lock; + test_specification = specification; test_length = length; handlers.test_set_up = defaults.get_handler(set_up_handler); @@ -83,6 +86,8 @@ void Harness::run(const Test *const specification, void Harness::raise_failure(failure_t reason) { + util::CriticalSectionLock lock; + case_failed++; status_t fail_status = STATUS_ABORT; @@ -128,6 +133,8 @@ void Harness::schedule_next_case() void Harness::handle_timeout() { + util::CriticalSectionLock lock; + if (case_timeout_handle != NULL) { raise_failure(FAILURE_TIMEOUT); @@ -138,6 +145,8 @@ void Harness::handle_timeout() void Harness::validate_callback() { + util::CriticalSectionLock lock; + if (case_timeout_handle != NULL) { minar::Scheduler::cancelCallback(case_timeout_handle); @@ -148,6 +157,8 @@ void Harness::validate_callback() void Harness::run_next_case() { + util::CriticalSectionLock lock; + if(case_current != (test_specification + test_length)) { handlers.case_set_up = defaults.get_handler(case_current->set_up_handler); From e2a5d97f777ae4a6b42a568a5f065469938d5009 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 12 Nov 2015 11:39:44 +0000 Subject: [PATCH 14/88] Harness: Add empty test case detection. --- "frameworks\\utest/source/case.cpp" | 5 +++++ "frameworks\\utest/source/default_handlers.cpp" | 2 ++ "frameworks\\utest/source/harness.cpp" | 6 ++++++ 3 files changed, 13 insertions(+) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index c783318ded..6ca5e6be74 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -70,6 +70,11 @@ Case::get_description() const { return description; } +bool +Case::is_empty() const { + return !(handler || control_flow_handler || set_up_handler || tear_down_handler); +} + AsyncCase::AsyncCase(const char *description, const case_handler_t handler, diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index ddf3eafc27..cfb37eec99 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -31,6 +31,8 @@ const char* failureToString(failure_t failure) return "Unspecified Failure"; case FAILURE_CASES: return "Test Cases Failed"; + case FAILURE_EMPTY_CASE: + return "Test Case is Empty"; case FAILURE_SETUP: return "Setup Failed"; case FAILURE_TEARDOWN: diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index f2d9371c77..c217c7b359 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -165,6 +165,12 @@ void Harness::run_next_case() handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); handlers.case_failure = defaults.get_handler(case_current->failure_handler); + if (case_current->is_empty()) { + raise_failure(FAILURE_EMPTY_CASE); + schedule_next_case(); + return; + } + if (!case_failed && !case_passed) { size_t index = test_index_of_case++; if (handlers.case_set_up && (handlers.case_set_up(case_current, index) != STATUS_CONTINUE)) { From 9a4e0d2da85905d24d000502218b34bf0e9d5659 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 13 Nov 2015 11:21:23 +0000 Subject: [PATCH 15/88] Add Specification class with common setup and teardown handlers. --- "frameworks\\utest/source/harness.cpp" | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index c217c7b359..eac7c0257c 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -25,7 +25,7 @@ using namespace mbed::test::v0; namespace { - const Test *test_specification = NULL; + const Case *test_cases = NULL; size_t test_length = 0; size_t test_index_of_case = 0; @@ -55,17 +55,14 @@ void Harness::set_default_handlers(const handlers_t defaults) ::defaults = defaults; } -void Harness::run(const Test *const specification, - const size_t length, - const test_set_up_handler_t set_up_handler, - const test_tear_down_handler_t tear_down_handler) +void Harness::run(const Specification specification) { util::CriticalSectionLock lock; - test_specification = specification; - test_length = length; - handlers.test_set_up = defaults.get_handler(set_up_handler); - handlers.test_tear_down = defaults.get_handler(tear_down_handler); + test_cases = specification.cases; + test_length = specification.length; + handlers.test_set_up = defaults.get_handler(specification.set_up_handler); + handlers.test_tear_down = defaults.get_handler(specification.tear_down_handler); test_index_of_case = 0; test_passed = 0; @@ -74,7 +71,7 @@ void Harness::run(const Test *const specification, case_passed = 0; case_failed = 0; case_failed_before = 0; - case_current = specification; + case_current = test_cases; if (handlers.test_set_up && (handlers.test_set_up(test_length) != STATUS_CONTINUE)) { if (handlers.test_tear_down) handlers.test_tear_down(0, 0, FAILURE_SETUP); @@ -159,7 +156,7 @@ void Harness::run_next_case() { util::CriticalSectionLock lock; - if(case_current != (test_specification + test_length)) + if(case_current != (test_cases + test_length)) { handlers.case_set_up = defaults.get_handler(case_current->set_up_handler); handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); From 2cf2ef54154ad6a8278ceb034ac1a9f663d56a1f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 13 Nov 2015 13:20:20 +0000 Subject: [PATCH 16/88] Move default handlers into specification. --- "frameworks\\utest/source/harness.cpp" | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index eac7c0257c..bbebf6bc7d 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -42,7 +42,7 @@ namespace size_t case_failed = 0; size_t case_failed_before = 0; - handlers_t defaults = greentea_handlers; + handlers_t defaults = default_handlers; handlers_t handlers = defaults; } @@ -50,17 +50,13 @@ static void die() { while(1) ; } -void Harness::set_default_handlers(const handlers_t defaults) -{ - ::defaults = defaults; -} - void Harness::run(const Specification specification) { util::CriticalSectionLock lock; test_cases = specification.cases; test_length = specification.length; + defaults = specification.defaults; handlers.test_set_up = defaults.get_handler(specification.set_up_handler); handlers.test_tear_down = defaults.get_handler(specification.tear_down_handler); From 7e321f8f81082f1ecc62714c581aa74681e6d2d0 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 13 Nov 2015 14:12:28 +0000 Subject: [PATCH 17/88] Defaults: Force users to provide a greentea setup handler. It displays a helpful message in case you forgot. --- "frameworks\\utest/source/default_handlers.cpp" | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index cfb37eec99..8cdf2a3961 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -91,17 +91,12 @@ status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source -status_t mbed::test::v0::greentea_test_set_up_handler(const size_t number_of_cases) +status_t mbed::test::v0::greentea_test_set_up_handler(const size_t /*number_of_cases*/) { - printf("{{timeout;%u}}\n", number_of_cases); - printf("{{host_test_name;default_auto}}\n"); - printf("{{description;default_greentea_handler_test}}\n"); - printf("{{test_id;default_greentea_handler_test}}\n"); - printf("{{start}}\n"); + printf(">>> I do not know how to tell greentea that the test started, since\n"); + printf(">>> you forgot to override the `test_set_up_handler` in your specification.\n"); - verbose_test_set_up_handler(number_of_cases); - - return STATUS_CONTINUE; + return STATUS_ABORT; } void mbed::test::v0::greentea_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) From b3e30294ccbd2e774b22b98dddd63d2c5eb071d5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 13 Nov 2015 17:33:49 +0000 Subject: [PATCH 18/88] Overload the (Async-)Case class to take the handlers in a semantically meaningful way. --- "frameworks\\utest/source/case.cpp" | 185 ++++++++++++++++++++++++---- 1 file changed, 164 insertions(+), 21 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 6ca5e6be74..55bbde90bc 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -20,15 +20,15 @@ using namespace mbed::test::v0; - +// normal handler Case::Case(const char *description, - const case_handler_t handler, const case_set_up_handler_t set_up_handler, + const case_handler_t handler, const case_tear_down_handler_t tear_down_handler, const case_failure_handler_t failure_handler) : description(description), handler(handler), - control_flow_handler(NULL), + control_flow_handler(ignore_handler), set_up_handler(set_up_handler), tear_down_handler(tear_down_handler), failure_handler(failure_handler), @@ -36,12 +36,38 @@ Case::Case(const char *description, {} Case::Case(const char *description, - const case_control_flow_handler_t control_flow_handler, - const case_set_up_handler_t set_up_handler, + const case_handler_t handler, const case_tear_down_handler_t tear_down_handler, const case_failure_handler_t failure_handler) : description(description), - handler(NULL), + handler(handler), + control_flow_handler(ignore_handler), + set_up_handler(default_handler), + tear_down_handler(tear_down_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} + +Case::Case(const char *description, + const case_handler_t handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(handler), + control_flow_handler(ignore_handler), + set_up_handler(default_handler), + tear_down_handler(default_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} + +// control flow handler +Case::Case(const char *description, + const case_set_up_handler_t set_up_handler, + const case_control_flow_handler_t control_flow_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), control_flow_handler(control_flow_handler), set_up_handler(set_up_handler), tear_down_handler(tear_down_handler), @@ -50,9 +76,34 @@ Case::Case(const char *description, {} Case::Case(const char *description, + const case_control_flow_handler_t control_flow_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), + control_flow_handler(control_flow_handler), + set_up_handler(default_handler), + tear_down_handler(default_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} + +Case::Case(const char *description, + const case_control_flow_handler_t control_flow_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), + control_flow_handler(control_flow_handler), + set_up_handler(default_handler), + tear_down_handler(tear_down_handler), + failure_handler(failure_handler), + timeout_ms(-1) +{} + +Case::Case(const char *description, + const case_set_up_handler_t set_up_handler, const case_handler_t handler, const case_control_flow_handler_t control_flow_handler, - const case_set_up_handler_t set_up_handler, const case_tear_down_handler_t tear_down_handler, const case_failure_handler_t failure_handler, const int32_t timeout_ms) : @@ -77,19 +128,111 @@ Case::is_empty() const { AsyncCase::AsyncCase(const char *description, - const case_handler_t handler, - const uint32_t timeout_ms, - const case_set_up_handler_t set_up_handler, - const case_tear_down_handler_t tear_down_handler, - const case_failure_handler_t failure_handler) : - Case(description, handler, NULL, set_up_handler, tear_down_handler, failure_handler, timeout_ms) -{} + const case_handler_t case_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_control_flow_handler_t control_flow_handler, - const uint32_t timeout_ms, - const case_set_up_handler_t set_up_handler, - const case_tear_down_handler_t tear_down_handler, - const case_failure_handler_t failure_handler) : - Case(description, NULL, control_flow_handler, set_up_handler, tear_down_handler, failure_handler, timeout_ms) -{} + const case_set_up_handler_t set_up_handler, + const case_handler_t case_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, case_handler, ignore_handler, tear_down_handler, default_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, case_handler, ignore_handler, tear_down_handler, default_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_handler_t case_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_handler_t case_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, case_handler, ignore_handler, tear_down_handler, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, case_handler, ignore_handler, tear_down_handler, failure_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_control_flow_handler_t case_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_control_flow_handler_t case_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_control_flow_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, ignore_handler, case_handler, tear_down_handler, default_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_control_flow_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, ignore_handler, case_handler, tear_down_handler, default_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_control_flow_handler_t case_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_control_flow_handler_t case_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} + + +AsyncCase::AsyncCase(const char *description, + const case_control_flow_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, default_handler, ignore_handler, case_handler, tear_down_handler, failure_handler, timeout_ms) {} + +AsyncCase::AsyncCase(const char *description, + const case_set_up_handler_t set_up_handler, + const case_control_flow_handler_t case_handler, + const case_tear_down_handler_t tear_down_handler, + const case_failure_handler_t failure_handler, + const uint32_t timeout_ms) : + Case(description, set_up_handler, ignore_handler, case_handler, tear_down_handler, failure_handler, timeout_ms) {} From e77743d6a616f50831e678be04181a067ffc00b2 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 16 Nov 2015 11:09:19 +0000 Subject: [PATCH 19/88] Types: Add repeat count to `control_flow_handler_t`. --- "frameworks\\utest/source/harness.cpp" | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index bbebf6bc7d..040b007bc3 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -35,6 +35,7 @@ namespace const Case *case_current = NULL; control_flow_t case_control_flow = CONTROL_FLOW_NEXT; + size_t case_repeat_count = 0; minar::callback_handle_t case_timeout_handle = NULL; @@ -120,6 +121,7 @@ void Harness::schedule_next_case() case_passed = 0; case_failed = 0; case_failed_before = 0; + case_repeat_count = 0; } minar::Scheduler::postCallback(run_next_case); } @@ -152,7 +154,7 @@ void Harness::run_next_case() { util::CriticalSectionLock lock; - if(case_current != (test_cases + test_length)) + if(case_current < (test_cases + test_length)) { handlers.case_set_up = defaults.get_handler(case_current->set_up_handler); handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); @@ -179,7 +181,8 @@ void Harness::run_next_case() case_control_flow = CONTROL_FLOW_NEXT; case_current->handler(); } else if (case_current->control_flow_handler) { - case_control_flow = case_current->control_flow_handler(); + case_control_flow = case_current->control_flow_handler(case_repeat_count); + case_repeat_count++; } if (case_current->timeout_ms >= 0) { From 9c32e01d52645509213f9e79821658c49f1d3201 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 16 Nov 2015 11:09:34 +0000 Subject: [PATCH 20/88] Harness: Add `is_busy()` method. --- "frameworks\\utest/source/harness.cpp" | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 040b007bc3..c6c95d1edc 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -150,6 +150,15 @@ void Harness::validate_callback() } } +bool Harness::is_busy() +{ + util::CriticalSectionLock lock; + if (!test_cases) return false; + if (!case_current) return false; + + return (case_current < (test_cases + test_length)); +} + void Harness::run_next_case() { util::CriticalSectionLock lock; From a045c44f78f6a67d9c7723ce298a8854438b8a33 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 16 Nov 2015 16:18:59 +0000 Subject: [PATCH 21/88] Refactor `set_up` to `setup`, `tear_down` to `teardown`. It's a verb vs. noun thing. --- "frameworks\\utest/source/case.cpp" | 102 +++++++++--------- .../source/default_handlers.cpp" | 16 +-- "frameworks\\utest/source/harness.cpp" | 30 +++--- 3 files changed, 74 insertions(+), 74 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 55bbde90bc..7d7aa526f4 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -22,28 +22,28 @@ using namespace mbed::test::v0; // normal handler Case::Case(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(handler), control_flow_handler(ignore_handler), - set_up_handler(set_up_handler), - tear_down_handler(tear_down_handler), + setup_handler(setup_handler), + teardown_handler(teardown_handler), failure_handler(failure_handler), timeout_ms(-1) {} Case::Case(const char *description, const case_handler_t handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(handler), control_flow_handler(ignore_handler), - set_up_handler(default_handler), - tear_down_handler(tear_down_handler), + setup_handler(default_handler), + teardown_handler(teardown_handler), failure_handler(failure_handler), timeout_ms(-1) {} @@ -54,23 +54,23 @@ Case::Case(const char *description, description(description), handler(handler), control_flow_handler(ignore_handler), - set_up_handler(default_handler), - tear_down_handler(default_handler), + setup_handler(default_handler), + teardown_handler(default_handler), failure_handler(failure_handler), timeout_ms(-1) {} // control flow handler Case::Case(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_control_flow_handler_t control_flow_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), control_flow_handler(control_flow_handler), - set_up_handler(set_up_handler), - tear_down_handler(tear_down_handler), + setup_handler(setup_handler), + teardown_handler(teardown_handler), failure_handler(failure_handler), timeout_ms(-1) {} @@ -81,37 +81,37 @@ Case::Case(const char *description, description(description), handler(ignore_handler), control_flow_handler(control_flow_handler), - set_up_handler(default_handler), - tear_down_handler(default_handler), + setup_handler(default_handler), + teardown_handler(default_handler), failure_handler(failure_handler), timeout_ms(-1) {} Case::Case(const char *description, const case_control_flow_handler_t control_flow_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), control_flow_handler(control_flow_handler), - set_up_handler(default_handler), - tear_down_handler(tear_down_handler), + setup_handler(default_handler), + teardown_handler(teardown_handler), failure_handler(failure_handler), timeout_ms(-1) {} Case::Case(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t handler, const case_control_flow_handler_t control_flow_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler, const int32_t timeout_ms) : description(description), handler(handler), control_flow_handler(control_flow_handler), - set_up_handler(set_up_handler), - tear_down_handler(tear_down_handler), + setup_handler(setup_handler), + teardown_handler(teardown_handler), failure_handler(failure_handler), timeout_ms(timeout_ms) {} @@ -123,7 +123,7 @@ Case::get_description() const { bool Case::is_empty() const { - return !(handler || control_flow_handler || set_up_handler || tear_down_handler); + return !(handler || control_flow_handler || setup_handler || teardown_handler); } @@ -133,24 +133,24 @@ AsyncCase::AsyncCase(const char *description, Case(description, default_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t case_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} + Case(description, setup_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, tear_down_handler, default_handler, timeout_ms) {} + Case(description, default_handler, case_handler, ignore_handler, teardown_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, case_handler, ignore_handler, tear_down_handler, default_handler, timeout_ms) {} + Case(description, setup_handler, case_handler, ignore_handler, teardown_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, @@ -160,26 +160,26 @@ AsyncCase::AsyncCase(const char *description, Case(description, default_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t case_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} + Case(description, setup_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, const case_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, tear_down_handler, failure_handler, timeout_ms) {} + Case(description, default_handler, case_handler, ignore_handler, teardown_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, case_handler, ignore_handler, tear_down_handler, failure_handler, timeout_ms) {} + Case(description, setup_handler, case_handler, ignore_handler, teardown_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, @@ -188,24 +188,24 @@ AsyncCase::AsyncCase(const char *description, Case(description, default_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_control_flow_handler_t case_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} + Case(description, setup_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, const case_control_flow_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, tear_down_handler, default_handler, timeout_ms) {} + Case(description, default_handler, ignore_handler, case_handler, teardown_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_control_flow_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, ignore_handler, case_handler, tear_down_handler, default_handler, timeout_ms) {} + Case(description, setup_handler, ignore_handler, case_handler, teardown_handler, default_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, @@ -215,24 +215,24 @@ AsyncCase::AsyncCase(const char *description, Case(description, default_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_control_flow_handler_t case_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} + Case(description, setup_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, const case_control_flow_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, tear_down_handler, failure_handler, timeout_ms) {} + Case(description, default_handler, ignore_handler, case_handler, teardown_handler, failure_handler, timeout_ms) {} AsyncCase::AsyncCase(const char *description, - const case_set_up_handler_t set_up_handler, + const case_setup_handler_t setup_handler, const case_control_flow_handler_t case_handler, - const case_tear_down_handler_t tear_down_handler, + const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler, const uint32_t timeout_ms) : - Case(description, set_up_handler, ignore_handler, case_handler, tear_down_handler, failure_handler, timeout_ms) {} + Case(description, setup_handler, ignore_handler, case_handler, teardown_handler, failure_handler, timeout_ms) {} diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 8cdf2a3961..ad027b2afc 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -45,13 +45,13 @@ const char* failureToString(failure_t failure) return "Unknown Failure"; } -status_t mbed::test::v0::verbose_test_set_up_handler(const size_t number_of_cases) +status_t mbed::test::v0::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; } -void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) +void mbed::test::v0::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { printf("\n>>> Test cases: %u passed, %u failed", passed, failed); if (failure == FAILURE_NONE) { @@ -62,13 +62,13 @@ void mbed::test::v0::verbose_test_tear_down_handler(const size_t passed, const s if (failed) printf(">>> TESTS FAILED!\n"); } -status_t mbed::test::v0::verbose_case_set_up_handler(const Case *const source, const size_t index_of_case) +status_t mbed::test::v0::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) { printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_tear_down_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +status_t mbed::test::v0::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) { printf(">>> '%s': %u passed, %u failed", source->get_description(), passed, failed); if (failure == FAILURE_NONE) { @@ -91,17 +91,17 @@ status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source -status_t mbed::test::v0::greentea_test_set_up_handler(const size_t /*number_of_cases*/) +status_t mbed::test::v0::greentea_test_setup_handler(const size_t /*number_of_cases*/) { printf(">>> I do not know how to tell greentea that the test started, since\n"); - printf(">>> you forgot to override the `test_set_up_handler` in your specification.\n"); + printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); return STATUS_ABORT; } -void mbed::test::v0::greentea_test_tear_down_handler(const size_t passed, const size_t failed, const failure_t failure) +void mbed::test::v0::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { - verbose_test_tear_down_handler(passed, failed, failure); + verbose_test_teardown_handler(passed, failed, failure); if (failed || failure != FAILURE_NONE) { printf("{{failure}}\n"); } else { diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index c6c95d1edc..20797f5dd9 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -58,8 +58,8 @@ void Harness::run(const Specification specification) test_cases = specification.cases; test_length = specification.length; defaults = specification.defaults; - handlers.test_set_up = defaults.get_handler(specification.set_up_handler); - handlers.test_tear_down = defaults.get_handler(specification.tear_down_handler); + handlers.test_setup = defaults.get_handler(specification.setup_handler); + handlers.test_teardown = defaults.get_handler(specification.teardown_handler); test_index_of_case = 0; test_passed = 0; @@ -70,8 +70,8 @@ void Harness::run(const Specification specification) case_failed_before = 0; case_current = test_cases; - if (handlers.test_set_up && (handlers.test_set_up(test_length) != STATUS_CONTINUE)) { - if (handlers.test_tear_down) handlers.test_tear_down(0, 0, FAILURE_SETUP); + if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { + if (handlers.test_teardown) handlers.test_teardown(0, 0, FAILURE_SETUP); die(); } @@ -88,17 +88,17 @@ void Harness::raise_failure(failure_t reason) if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); if (fail_status != STATUS_CONTINUE || reason == FAILURE_SETUP) { - if (handlers.case_tear_down && reason != FAILURE_TEARDOWN) { - status_t teardown_status = handlers.case_tear_down(case_current, case_passed, case_failed, reason); + if (handlers.case_teardown && reason != FAILURE_TEARDOWN) { + status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, reason); if (teardown_status != STATUS_CONTINUE) { raise_failure(FAILURE_TEARDOWN); } - else handlers.case_tear_down = NULL; + else handlers.case_teardown = NULL; } } if (fail_status != STATUS_CONTINUE) { test_failed++; - if (handlers.test_tear_down) handlers.test_tear_down(test_passed, test_failed, reason); + if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, reason); die(); } } @@ -108,8 +108,8 @@ void Harness::schedule_next_case() if (case_failed_before == case_failed) case_passed++; if(case_control_flow == CONTROL_FLOW_NEXT) { - if (handlers.case_tear_down && - (handlers.case_tear_down(case_current, case_passed, case_failed, + if (handlers.case_teardown && + (handlers.case_teardown(case_current, case_passed, case_failed, case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { raise_failure(FAILURE_TEARDOWN); } @@ -165,8 +165,8 @@ void Harness::run_next_case() if(case_current < (test_cases + test_length)) { - handlers.case_set_up = defaults.get_handler(case_current->set_up_handler); - handlers.case_tear_down = defaults.get_handler(case_current->tear_down_handler); + handlers.case_setup = defaults.get_handler(case_current->setup_handler); + handlers.case_teardown = defaults.get_handler(case_current->teardown_handler); handlers.case_failure = defaults.get_handler(case_current->failure_handler); if (case_current->is_empty()) { @@ -177,7 +177,7 @@ void Harness::run_next_case() if (!case_failed && !case_passed) { size_t index = test_index_of_case++; - if (handlers.case_set_up && (handlers.case_set_up(case_current, index) != STATUS_CONTINUE)) { + if (handlers.case_setup && (handlers.case_setup(case_current, index) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); return; @@ -204,8 +204,8 @@ void Harness::run_next_case() schedule_next_case(); } } - else if (handlers.test_tear_down) { - handlers.test_tear_down(test_passed, test_failed, test_failed ? FAILURE_CASES : FAILURE_NONE); + else if (handlers.test_teardown) { + handlers.test_teardown(test_passed, test_failed, test_failed ? FAILURE_CASES : FAILURE_NONE); die(); } } From b119cb228082946ea4cdf0f50f563d9ae1d51210 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 10:31:06 +0000 Subject: [PATCH 22/88] Case: `timeout_ms` is unsigned, use 0 as do-not-use indicator. --- "frameworks\\utest/source/case.cpp" | 12 ++++++------ "frameworks\\utest/source/harness.cpp" | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 7d7aa526f4..2c391f6ab7 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -32,7 +32,7 @@ Case::Case(const char *description, setup_handler(setup_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} Case::Case(const char *description, @@ -45,7 +45,7 @@ Case::Case(const char *description, setup_handler(default_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} Case::Case(const char *description, @@ -57,7 +57,7 @@ Case::Case(const char *description, setup_handler(default_handler), teardown_handler(default_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} // control flow handler @@ -72,7 +72,7 @@ Case::Case(const char *description, setup_handler(setup_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} Case::Case(const char *description, @@ -84,7 +84,7 @@ Case::Case(const char *description, setup_handler(default_handler), teardown_handler(default_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} Case::Case(const char *description, @@ -97,7 +97,7 @@ Case::Case(const char *description, setup_handler(default_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), - timeout_ms(-1) + timeout_ms(0) {} Case::Case(const char *description, diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 20797f5dd9..0e2fdb6ce9 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -194,7 +194,7 @@ void Harness::run_next_case() case_repeat_count++; } - if (case_current->timeout_ms >= 0) { + if (case_current->timeout_ms > 0) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_current->timeout_ms)) .tolerance(0) From 64573c33d0992a447f1adf4794b674e818b48a85 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 10:39:36 +0000 Subject: [PATCH 23/88] Types: allow external access to `stringify` function. --- .../source/default_handlers.cpp" | 30 ++----------- "frameworks\\utest/source/types.cpp" | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 "frameworks\\utest/source/types.cpp" diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index ad027b2afc..ce7d0792f1 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -21,30 +21,6 @@ using namespace mbed::test::v0; -const char* failureToString(failure_t failure) -{ - switch(failure) - { - case FAILURE_NONE: - return "No Failure"; - case FAILURE: - return "Unspecified Failure"; - case FAILURE_CASES: - return "Test Cases Failed"; - case FAILURE_EMPTY_CASE: - return "Test Case is Empty"; - case FAILURE_SETUP: - return "Setup Failed"; - case FAILURE_TEARDOWN: - return "Teardown Failed"; - case FAILURE_TIMEOUT: - return "Timed Out"; - case FAILURE_ASSERTION: - return "Assertion Failed"; - } - return "Unknown Failure"; -} - status_t mbed::test::v0::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); @@ -57,7 +33,7 @@ void mbed::test::v0::verbose_test_teardown_handler(const size_t passed, const si if (failure == FAILURE_NONE) { printf("\n"); } else { - printf(" with reason '%s'\n", failureToString(failure)); + printf(" with reason '%s'\n", stringify(failure)); } if (failed) printf(">>> TESTS FAILED!\n"); } @@ -74,7 +50,7 @@ status_t mbed::test::v0::verbose_case_teardown_handler(const Case *const source, if (failure == FAILURE_NONE) { printf("\n"); } else { - printf(" with reason '%s'\n", failureToString(failure)); + printf(" with reason '%s'\n", stringify(failure)); } return STATUS_CONTINUE; } @@ -84,7 +60,7 @@ status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source if (reason == FAILURE_ASSERTION) { printf("\n"); } else { - printf(">>> failed with reason '%s'\n", failureToString(reason)); + printf(">>> failed with reason '%s'\n", stringify(reason)); } return (reason == FAILURE_TEARDOWN) ? STATUS_ABORT : STATUS_CONTINUE; } diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" new file mode 100644 index 0000000000..9c08fb95bb --- /dev/null +++ "b/frameworks\\utest/source/types.cpp" @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (c) 2015, 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-test-async/types.h" + +const char* mbed::test::v0::stringify(mbed::test::v0::failure_t failure) +{ + switch(failure) + { + case FAILURE_NONE: + return "No Failure"; + case FAILURE: + return "Unspecified Failure"; + case FAILURE_CASES: + return "Test Cases Failed"; + case FAILURE_EMPTY_CASE: + return "Test Case is Empty"; + case FAILURE_SETUP: + return "Setup Failed"; + case FAILURE_TEARDOWN: + return "Teardown Failed"; + case FAILURE_TIMEOUT: + return "Timed Out"; + case FAILURE_ASSERTION: + return "Assertion Failed"; + } + return "Unknown Failure"; +} From 61fe8e07a126fe06cac5078bc35a7568ed71e8f3 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 10:45:14 +0000 Subject: [PATCH 24/88] Handlers: Remove forced newline after assertion failure. This was a workaround for unity's failure to add a newline after printing an assertion failure. This has been fixed in unity. --- "frameworks\\utest/source/default_handlers.cpp" | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index ce7d0792f1..d3606ccca1 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -57,9 +57,7 @@ status_t mbed::test::v0::verbose_case_teardown_handler(const Case *const source, status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { - if (reason == FAILURE_ASSERTION) { - printf("\n"); - } else { + if (reason != FAILURE_ASSERTION) { printf(">>> failed with reason '%s'\n", stringify(reason)); } return (reason == FAILURE_TEARDOWN) ? STATUS_ABORT : STATUS_CONTINUE; From b72f18009b209d29bfbb2581abe97aa0f1394cc9 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 11:40:04 +0000 Subject: [PATCH 25/88] Harness: Remove `.tolerance(0)` as not required. --- "frameworks\\utest/source/harness.cpp" | 1 - 1 file changed, 1 deletion(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 0e2fdb6ce9..f174c66626 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -197,7 +197,6 @@ void Harness::run_next_case() if (case_current->timeout_ms > 0) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_current->timeout_ms)) - .tolerance(0) .getHandle(); } else { From dc4cb4585c98295a0ea1ab51d56515d5e80c988b Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 15:08:29 +0000 Subject: [PATCH 26/88] Unify `Case` and `AsyncCase` using return type. By letting the test case return a `control_t` type, it can decide itself if it repeats, and what timeouts are required. This removes the `AsyncCase` and allows a uniform declaration of test cases. --- "frameworks\\utest/source/case.cpp" | 211 ++++++++----------------- "frameworks\\utest/source/harness.cpp" | 28 ++-- 2 files changed, 78 insertions(+), 161 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 2c391f6ab7..5ebc501c46 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -28,11 +28,11 @@ Case::Case(const char *description, const case_failure_handler_t failure_handler) : description(description), handler(handler), - control_flow_handler(ignore_handler), + control_handler(ignore_handler), + repeat_count_handler(ignore_handler), setup_handler(setup_handler), teardown_handler(teardown_handler), - failure_handler(failure_handler), - timeout_ms(0) + failure_handler(failure_handler) {} Case::Case(const char *description, @@ -41,11 +41,11 @@ Case::Case(const char *description, const case_failure_handler_t failure_handler) : description(description), handler(handler), - control_flow_handler(ignore_handler), + control_handler(ignore_handler), + repeat_count_handler(ignore_handler), setup_handler(default_handler), teardown_handler(teardown_handler), - failure_handler(failure_handler), - timeout_ms(0) + failure_handler(failure_handler) {} Case::Case(const char *description, @@ -53,67 +53,91 @@ Case::Case(const char *description, const case_failure_handler_t failure_handler) : description(description), handler(handler), - control_flow_handler(ignore_handler), + control_handler(ignore_handler), + repeat_count_handler(ignore_handler), setup_handler(default_handler), teardown_handler(default_handler), - failure_handler(failure_handler), - timeout_ms(0) + failure_handler(failure_handler) +{} + +// control handler +Case::Case(const char *description, + const case_setup_handler_t setup_handler, + const case_control_handler_t handler, + const case_teardown_handler_t teardown_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), + control_handler(handler), + repeat_count_handler(ignore_handler), + setup_handler(setup_handler), + teardown_handler(teardown_handler), + failure_handler(failure_handler) +{} + +Case::Case(const char *description, + const case_control_handler_t handler, + const case_teardown_handler_t teardown_handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), + control_handler(handler), + repeat_count_handler(ignore_handler), + setup_handler(default_handler), + teardown_handler(teardown_handler), + failure_handler(failure_handler) +{} + +Case::Case(const char *description, + const case_control_handler_t handler, + const case_failure_handler_t failure_handler) : + description(description), + handler(ignore_handler), + control_handler(handler), + repeat_count_handler(ignore_handler), + setup_handler(default_handler), + teardown_handler(default_handler), + failure_handler(failure_handler) {} // control flow handler Case::Case(const char *description, const case_setup_handler_t setup_handler, - const case_control_flow_handler_t control_flow_handler, + const case_repeat_count_handler_t case_repeat_count_handler, const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), - control_flow_handler(control_flow_handler), + control_handler(ignore_handler), + repeat_count_handler(case_repeat_count_handler), setup_handler(setup_handler), teardown_handler(teardown_handler), - failure_handler(failure_handler), - timeout_ms(0) + failure_handler(failure_handler) {} Case::Case(const char *description, - const case_control_flow_handler_t control_flow_handler, + const case_repeat_count_handler_t case_repeat_count_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), - control_flow_handler(control_flow_handler), + control_handler(ignore_handler), + repeat_count_handler(case_repeat_count_handler), setup_handler(default_handler), teardown_handler(default_handler), - failure_handler(failure_handler), - timeout_ms(0) + failure_handler(failure_handler) {} Case::Case(const char *description, - const case_control_flow_handler_t control_flow_handler, + const case_repeat_count_handler_t case_repeat_count_handler, const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), - control_flow_handler(control_flow_handler), + control_handler(ignore_handler), + repeat_count_handler(case_repeat_count_handler), setup_handler(default_handler), teardown_handler(teardown_handler), - failure_handler(failure_handler), - timeout_ms(0) -{} - -Case::Case(const char *description, - const case_setup_handler_t setup_handler, - const case_handler_t handler, - const case_control_flow_handler_t control_flow_handler, - const case_teardown_handler_t teardown_handler, - const case_failure_handler_t failure_handler, - const int32_t timeout_ms) : - description(description), - handler(handler), - control_flow_handler(control_flow_handler), - setup_handler(setup_handler), - teardown_handler(teardown_handler), - failure_handler(failure_handler), - timeout_ms(timeout_ms) + failure_handler(failure_handler) {} const char* @@ -123,116 +147,5 @@ Case::get_description() const { bool Case::is_empty() const { - return !(handler || control_flow_handler || setup_handler || teardown_handler); + return !(handler || repeat_count_handler || setup_handler || teardown_handler); } - - -AsyncCase::AsyncCase(const char *description, - const case_handler_t case_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_handler_t case_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, case_handler, ignore_handler, default_handler, default_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, teardown_handler, default_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, case_handler, ignore_handler, teardown_handler, default_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_handler_t case_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_handler_t case_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, case_handler, ignore_handler, default_handler, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, case_handler, ignore_handler, teardown_handler, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, case_handler, ignore_handler, teardown_handler, failure_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_control_flow_handler_t case_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_control_flow_handler_t case_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, ignore_handler, case_handler, default_handler, default_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_control_flow_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, teardown_handler, default_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_control_flow_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, ignore_handler, case_handler, teardown_handler, default_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_control_flow_handler_t case_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_control_flow_handler_t case_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, ignore_handler, case_handler, default_handler, failure_handler, timeout_ms) {} - - -AsyncCase::AsyncCase(const char *description, - const case_control_flow_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, default_handler, ignore_handler, case_handler, teardown_handler, failure_handler, timeout_ms) {} - -AsyncCase::AsyncCase(const char *description, - const case_setup_handler_t setup_handler, - const case_control_flow_handler_t case_handler, - const case_teardown_handler_t teardown_handler, - const case_failure_handler_t failure_handler, - const uint32_t timeout_ms) : - Case(description, setup_handler, ignore_handler, case_handler, teardown_handler, failure_handler, timeout_ms) {} diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index f174c66626..17ed0e2008 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -34,7 +34,7 @@ namespace size_t test_failed = 0; const Case *case_current = NULL; - control_flow_t case_control_flow = CONTROL_FLOW_NEXT; + control_t case_control = control_t(); size_t case_repeat_count = 0; minar::callback_handle_t case_timeout_handle = NULL; @@ -107,16 +107,19 @@ void Harness::schedule_next_case() { if (case_failed_before == case_failed) case_passed++; - if(case_control_flow == CONTROL_FLOW_NEXT) { + if(case_control.repeat != REPEAT_CASE_ONLY) { if (handlers.case_teardown && (handlers.case_teardown(case_current, case_passed, case_failed, case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { raise_failure(FAILURE_TEARDOWN); } + } + if(case_control.repeat == REPEAT_NO_REPEAT) { if (case_failed > 0) test_failed++; else test_passed++; + case_control = control_t(); case_current++; case_passed = 0; case_failed = 0; @@ -167,7 +170,7 @@ void Harness::run_next_case() { handlers.case_setup = defaults.get_handler(case_current->setup_handler); handlers.case_teardown = defaults.get_handler(case_current->teardown_handler); - handlers.case_failure = defaults.get_handler(case_current->failure_handler); + handlers.case_failure = defaults.get_handler(case_current->failure_handler); if (case_current->is_empty()) { raise_failure(FAILURE_EMPTY_CASE); @@ -175,9 +178,9 @@ void Harness::run_next_case() return; } - if (!case_failed && !case_passed) { - size_t index = test_index_of_case++; - if (handlers.case_setup && (handlers.case_setup(case_current, index) != STATUS_CONTINUE)) { + if ((!case_failed && !case_passed) || case_control.repeat == REPEAT_ALL) { + if (case_control.repeat == REPEAT_NO_REPEAT) test_index_of_case++; + if (handlers.case_setup && (handlers.case_setup(case_current, test_index_of_case) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); return; @@ -187,16 +190,17 @@ void Harness::run_next_case() case_failed_before = case_failed; if (case_current->handler) { - case_control_flow = CONTROL_FLOW_NEXT; case_current->handler(); - } else if (case_current->control_flow_handler) { - case_control_flow = case_current->control_flow_handler(case_repeat_count); - case_repeat_count++; + } else if (case_current->control_handler) { + case_control = case_current->control_handler(); + } else if (case_current->repeat_count_handler) { + case_control = case_current->repeat_count_handler(case_repeat_count); } + case_repeat_count++; - if (case_current->timeout_ms > 0) { + if (case_control.timeout > 0) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) - .delay(minar::milliseconds(case_current->timeout_ms)) + .delay(minar::milliseconds(case_control.timeout)) .getHandle(); } else { From a83e54c9150d5714f94116bcf9acae86a47c50e6 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 17 Nov 2015 16:57:46 +0000 Subject: [PATCH 27/88] Types: Use largest value in timeout as inactive hint. This allows arbitrating to the more restrictive timeout. --- "frameworks\\utest/source/harness.cpp" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 17ed0e2008..b8634d3e26 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -198,7 +198,7 @@ void Harness::run_next_case() } case_repeat_count++; - if (case_control.timeout > 0) { + if (case_control.timeout != uint32_t(-1)) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_control.timeout)) .getHandle(); From 97bbff7ab217cedba037940defc45d75a4c93f3f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 23 Nov 2015 13:19:54 +0000 Subject: [PATCH 28/88] Refactor namespace `mbed::test` to `utest`. --- "frameworks\\utest/source/case.cpp" | 2 +- .../source/default_handlers.cpp" | 18 +++++++++--------- "frameworks\\utest/source/harness.cpp" | 14 +++++++------- "frameworks\\utest/source/types.cpp" | 2 +- "frameworks\\utest/source/unity_handler.cpp" | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 5ebc501c46..b57d3bef1e 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -18,7 +18,7 @@ #include "mbed-test-async/case.h" -using namespace mbed::test::v0; +using namespace utest::v0; // normal handler Case::Case(const char *description, diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index d3606ccca1..646b180701 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -19,15 +19,15 @@ #include "mbed-test-async/default_handlers.h" #include "mbed-test-async/case.h" -using namespace mbed::test::v0; +using namespace utest::v0; -status_t mbed::test::v0::verbose_test_setup_handler(const size_t number_of_cases) +status_t utest::v0::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; } -void mbed::test::v0::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) +void utest::v0::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { printf("\n>>> Test cases: %u passed, %u failed", passed, failed); if (failure == FAILURE_NONE) { @@ -38,13 +38,13 @@ void mbed::test::v0::verbose_test_teardown_handler(const size_t passed, const si if (failed) printf(">>> TESTS FAILED!\n"); } -status_t mbed::test::v0::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) +status_t utest::v0::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) { printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +status_t utest::v0::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) { printf(">>> '%s': %u passed, %u failed", source->get_description(), passed, failed); if (failure == FAILURE_NONE) { @@ -55,7 +55,7 @@ status_t mbed::test::v0::verbose_case_teardown_handler(const Case *const source, return STATUS_CONTINUE; } -status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) +status_t utest::v0::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { if (reason != FAILURE_ASSERTION) { printf(">>> failed with reason '%s'\n", stringify(reason)); @@ -65,7 +65,7 @@ status_t mbed::test::v0::verbose_case_failure_handler(const Case *const /*source -status_t mbed::test::v0::greentea_test_setup_handler(const size_t /*number_of_cases*/) +status_t utest::v0::greentea_test_setup_handler(const size_t /*number_of_cases*/) { printf(">>> I do not know how to tell greentea that the test started, since\n"); printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); @@ -73,7 +73,7 @@ status_t mbed::test::v0::greentea_test_setup_handler(const size_t /*number_of_ca return STATUS_ABORT; } -void mbed::test::v0::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) +void utest::v0::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { verbose_test_teardown_handler(passed, failed, failure); if (failed || failure != FAILURE_NONE) { @@ -84,7 +84,7 @@ void mbed::test::v0::greentea_test_teardown_handler(const size_t passed, const s printf("{{end}}\n"); } -status_t mbed::test::v0::greentea_case_failure_handler(const Case *const source, const failure_t reason) +status_t utest::v0::greentea_case_failure_handler(const Case *const source, const failure_t reason) { verbose_case_failure_handler(source, reason); return STATUS_ABORT; diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index b8634d3e26..25fedcc088 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -20,7 +20,7 @@ #include "minar/minar.h" #include "core-util/CriticalSectionLock.h" -using namespace mbed::test::v0; +using namespace utest::v0; namespace @@ -53,7 +53,7 @@ static void die() { void Harness::run(const Specification specification) { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; test_cases = specification.cases; test_length = specification.length; @@ -80,7 +80,7 @@ void Harness::run(const Specification specification) void Harness::raise_failure(failure_t reason) { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; case_failed++; status_t fail_status = STATUS_ABORT; @@ -131,7 +131,7 @@ void Harness::schedule_next_case() void Harness::handle_timeout() { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; if (case_timeout_handle != NULL) { @@ -143,7 +143,7 @@ void Harness::handle_timeout() void Harness::validate_callback() { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; if (case_timeout_handle != NULL) { @@ -155,7 +155,7 @@ void Harness::validate_callback() bool Harness::is_busy() { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; if (!test_cases) return false; if (!case_current) return false; @@ -164,7 +164,7 @@ bool Harness::is_busy() void Harness::run_next_case() { - util::CriticalSectionLock lock; + mbed::util::CriticalSectionLock lock; if(case_current < (test_cases + test_length)) { diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index 9c08fb95bb..f8330f2af5 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -18,7 +18,7 @@ #include "mbed-test-async/types.h" -const char* mbed::test::v0::stringify(mbed::test::v0::failure_t failure) +const char* utest::v0::stringify(utest::v0::failure_t failure) { switch(failure) { diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index d9fe591a86..8950791245 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -21,5 +21,5 @@ extern "C" void mbed_test_unity_assert_failure() { - mbed::test::v0::Harness::raise_failure(mbed::test::v0::FAILURE_ASSERTION); + utest::v0::Harness::raise_failure(utest::v0::FAILURE_ASSERTION); } From bfc61ce8ae489c532de01b53c8929021ab2f738f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 23 Nov 2015 13:35:34 +0000 Subject: [PATCH 29/88] Rename `mbed_test_*` failure handler to `utest_*`. --- "frameworks\\utest/source/unity_handler.cpp" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index 8950791245..8bd10ec996 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -19,7 +19,7 @@ #include "mbed-test-async/harness.h" extern "C" -void mbed_test_unity_assert_failure() +void utest_unity_assert_failure() { utest::v0::Harness::raise_failure(utest::v0::FAILURE_ASSERTION); } From a3129f204a43b724f7b07cb5f55f10fc427d1e32 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 23 Nov 2015 13:41:22 +0000 Subject: [PATCH 30/88] Move header files to `utest` folder. --- "frameworks\\utest/utest/case.h" | 129 +++++++++++ "frameworks\\utest/utest/default_handlers.h" | 173 ++++++++++++++ "frameworks\\utest/utest/harness.h" | 73 ++++++ "frameworks\\utest/utest/specification.h" | 97 ++++++++ "frameworks\\utest/utest/types.h" | 226 +++++++++++++++++++ "frameworks\\utest/utest/unity_handler.h" | 27 +++ "frameworks\\utest/utest/utest.h" | 27 +++ 7 files changed, 752 insertions(+) create mode 100644 "frameworks\\utest/utest/case.h" create mode 100644 "frameworks\\utest/utest/default_handlers.h" create mode 100644 "frameworks\\utest/utest/harness.h" create mode 100644 "frameworks\\utest/utest/specification.h" create mode 100644 "frameworks\\utest/utest/types.h" create mode 100644 "frameworks\\utest/utest/unity_handler.h" create mode 100644 "frameworks\\utest/utest/utest.h" diff --git "a/frameworks\\utest/utest/case.h" "b/frameworks\\utest/utest/case.h" new file mode 100644 index 0000000000..07106a4fc2 --- /dev/null +++ "b/frameworks\\utest/utest/case.h" @@ -0,0 +1,129 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_CASES_H +#define MBED_TEST_ASYNC_CASES_H + +#include +#include +#include +#include "types.h" +#include "default_handlers.h" + + +namespace utest { +namespace v0 { + + /** Test case wrapper class. + * + * This class contains the description of the test case and all handlers + * for setting up, running the test case, tearing down and handling failures. + * + * By default you only need to provide a description and a test case handler. + * You may override the setup, teardown and failure handlers, but you do not have to. + * If you do not override these handler, the specified default handlers will be called. + * + * These constructors are overloaded to allow you a comfortable declaration of all your + * callbacks. + * The order is always: + * - description (required) + * - setup handler (optional) + * - test case handler (required) + * - teardown handler (optional) + * - failure handler (optional) + * + * @note While you can specify an empty test case (ie. use `ignore_handler` for all callbacks), + * the harness will abort the test unconditionally. + */ + class Case + { + public: + // overloads for case_handler_t + Case(const char *description, + const case_setup_handler_t setup_handler, + const case_handler_t case_handler, + const case_teardown_handler_t teardown_handler = default_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_handler_t case_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_handler_t case_handler, + const case_teardown_handler_t teardown_handler, + const case_failure_handler_t failure_handler = default_handler); + + // overloads for case_control_handler_t + Case(const char *description, + const case_setup_handler_t setup_handler, + const case_control_handler_t case_handler, + const case_teardown_handler_t teardown_handler = default_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_control_handler_t case_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_control_handler_t case_handler, + const case_teardown_handler_t teardown_handler, + const case_failure_handler_t failure_handler = default_handler); + + // overloads for case_repeat_count_handler_t + Case(const char *description, + const case_setup_handler_t setup_handler, + const case_repeat_count_handler_t case_handler, + const case_teardown_handler_t teardown_handler = default_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_repeat_count_handler_t case_handler, + const case_failure_handler_t failure_handler = default_handler); + + Case(const char *description, + const case_repeat_count_handler_t case_handler, + const case_teardown_handler_t teardown_handler, + const case_failure_handler_t failure_handler = default_handler); + + + /// @returns the textual description of the test case + const char* get_description() const; + + /// @returns `true` if setup, test and teardown handlers are set to `ignore_handler` + bool is_empty() const; + + private: + const char *description; + + const case_handler_t handler; + const case_control_handler_t control_handler; + const case_repeat_count_handler_t repeat_count_handler; + + const case_setup_handler_t setup_handler; + const case_teardown_handler_t teardown_handler; + + const case_failure_handler_t failure_handler; + + friend class Harness; + }; + +} // namespace v0 +} // namespace utest + + #endif // MBED_TEST_ASYNC_CASES_H diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" new file mode 100644 index 0000000000..102a80bade --- /dev/null +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -0,0 +1,173 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_DEFAULT_HANDLER_H +#define MBED_TEST_ASYNC_DEFAULT_HANDLER_H + +#include +#include +#include +#include "types.h" + + +namespace utest { +namespace v0 { + + /** Default handler hint. + * + * Use this handler to indicate the you want the default handler to be called. + * This type automatically casts itself into the appropriate handler type. + */ + const struct + { + operator test_setup_handler_t() const { return test_setup_handler_t(1); } + operator test_teardown_handler_t() const { return test_teardown_handler_t(1); } + + operator case_setup_handler_t() const { return case_setup_handler_t(1); } + operator case_teardown_handler_t() const { return case_teardown_handler_t(1); } + operator case_failure_handler_t() const { return case_failure_handler_t(1); } + } default_handler; + + /** Ignore handler hint. + * + * Use this handler to indicate the you want to ignore this handler and it will not be called. + * This type automatically casts itself into the appropriate handler type. + */ + const struct + { + operator case_handler_t() const { return case_handler_t(NULL); } + operator case_control_handler_t() const { return case_control_handler_t(NULL); } + operator case_repeat_count_handler_t() const { return case_repeat_count_handler_t(NULL); } + + operator test_setup_handler_t() const { return test_setup_handler_t(NULL); } + operator test_teardown_handler_t() const { return test_teardown_handler_t(NULL); } + + operator case_setup_handler_t() const { return case_setup_handler_t(NULL); } + operator case_teardown_handler_t() const { return case_teardown_handler_t(NULL); } + operator case_failure_handler_t() const { return case_failure_handler_t(NULL); } + } ignore_handler; + + /** A table of handlers. + * + * This structure stores all modifyable handlers and provides accessors to + * filter out the default handler. + * So if this structure contains handlers, and you want to use these handlers + * as a default backup, you can use the `get_handler` function to choose the right handler. + * + * Example: + * @code + * const handler_t defaults = { ... }; // your default handlers + * // will return the handler in defaults. + * test_setup_handler_t handler = defaults.get_handler(default_handler); + * // you will still need to manually check the handler before executing it + * if (handler != ignore_handler) handler(...); + * + * extern test_teardown_handler_t custom_handler(...); + * // will return `custom_handler` + * test_teardown_handler_t handler = defaults.get_handler(custom_handler); + * // you will still need to manually check the handler before executing it + * if (handler != ignore_handler) handler(...); + * @endcode + */ + struct handlers_t + { + test_setup_handler_t test_setup; + test_teardown_handler_t test_teardown; + + case_setup_handler_t case_setup; + case_teardown_handler_t case_teardown; + case_failure_handler_t case_failure; + + inline test_setup_handler_t get_handler(test_setup_handler_t handler) const { + if (handler == default_handler) return test_setup; + return handler; + } + inline test_teardown_handler_t get_handler(test_teardown_handler_t handler) const { + if (handler == default_handler) return test_teardown; + return handler; + } + + inline case_setup_handler_t get_handler(case_setup_handler_t handler) const { + if (handler == default_handler) return case_setup; + return handler; + } + inline case_teardown_handler_t get_handler(case_teardown_handler_t handler) const { + if (handler == default_handler) return case_teardown; + return handler; + } + inline case_failure_handler_t get_handler(case_failure_handler_t handler) const { + if (handler == default_handler) return case_failure; + return handler; + } + }; + + /// Prints the number of tests to run and continues. + status_t verbose_test_setup_handler (const size_t number_of_cases); + /// Prints the number of tests that passed and failed with a reason if provided. + void verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); + + /// Prints the index and description of the case being run and continues. + status_t verbose_case_setup_handler (const Case *const source, const size_t index_of_case); + /// Prints the number of tests that passed and failed with a reason if provided within this case and continues. + status_t verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure); + /// Prints the reason of the failure and continues, unless the teardown handler failed, for which it aborts. + status_t verbose_case_failure_handler (const Case *const source, const failure_t reason); + + /// Prints a helpful error message and aborts. + /// This function **NEEDS** to be overridden by the user when using greentea. + status_t greentea_test_setup_handler (const size_t number_of_cases); + /// Calls `verbose_test_teardown_handler` and then prints the greentea failure and success and end strings. + void greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); + + /// Calls `verbose_case_failure_handler` but then aborts. + status_t greentea_case_failure_handler (const Case *const source, const failure_t reason); + + /// The verbose default handlers that always continue on failure + const handlers_t verbose_continue_handlers = { + verbose_test_setup_handler, + verbose_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + verbose_case_failure_handler + }; + + /// The greentea default handlers that always abort on the first encountered failure + const handlers_t greentea_abort_handlers = { + greentea_test_setup_handler, + greentea_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + greentea_case_failure_handler + }; + + /// The greentea default handlers that always continue on failure + const handlers_t greentea_continue_handlers = { + greentea_test_setup_handler, + greentea_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + verbose_case_failure_handler + }; + + /// The greentea aborting handlers are the default + const handlers_t default_handlers = greentea_abort_handlers; + +} // namespace v0 +} // namespace utest + +#endif // MBED_TEST_ASYNC_DEFAULT_HANDLER_H diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" new file mode 100644 index 0000000000..fea99d4104 --- /dev/null +++ "b/frameworks\\utest/utest/harness.h" @@ -0,0 +1,73 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_HARNESS_H +#define MBED_TEST_ASYNC_HARNESS_H + +#include +#include +#include + +#include "types.h" +#include "case.h" +#include "default_handlers.h" +#include "specification.h" + + +namespace utest { +namespace v0 { + + /** Test Harness. + * + * This class runs a test specification for you and calls all required handlers. + * The harness executes the test specification in an asynchronous fashion, therefore + * `run()` returns immediately. + * + * @note: In case of an test abort, the harness will busy-wait and never finish. + */ + class Harness + { + public: + /// Starts running a test specification + static void run(const Specification specification); + + /// @returns `true` if a test specification is being executed, `false` otherwise + static bool is_busy(); + + /** Call this function in the asynchronous callback that you have been waiting for. + * + * You can only validate a callback once, calling this function when no callback is expected + * has no side effects. + * After callback validation, the next test case is scheduled. + */ + static void validate_callback(); + + /// Raising a failure causes the failure to be counted and the failure handler to be called. + /// Further action then depends on its return state. + static void raise_failure(failure_t reason); + + protected: + static void run_next_case(); + static void handle_timeout(); + static void schedule_next_case(); + }; + +} // namespace v0 +} // namespace utest + +#endif // MBED_TEST_ASYNC_HARNESS_H diff --git "a/frameworks\\utest/utest/specification.h" "b/frameworks\\utest/utest/specification.h" new file mode 100644 index 0000000000..daec492d2e --- /dev/null +++ "b/frameworks\\utest/utest/specification.h" @@ -0,0 +1,97 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_SPECIFICATION_H +#define MBED_TEST_ASYNC_SPECIFICATION_H + +#include +#include +#include +#include "types.h" +#include "case.h" +#include "default_handlers.h" + + +namespace utest { +namespace v0 { + + /** Test specification containing the setup and teardown handlers and test cases. + * + * This class simply holds the test cases and allows you to specify default handlers, and + * override setup and teardown handlers. + * The order of arguments is: + * - test setup handler (optional) + * - array of test cases (required) + * - test teardown handler (optional) + * - default handlers (optional) + * + * @note You cannot set the size of the test case array dynamically, it is template deducted at compile + * time. Creating test specifications for unittests at runtime is explicitly not supported. + */ + class Specification + { + public: + template< size_t N > + Specification(const Case (&cases)[N], + const test_teardown_handler_t teardown_handler = default_handler, + const handlers_t defaults = default_handlers) : + setup_handler(default_handler), teardown_handler(teardown_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const Case (&cases)[N], const handlers_t defaults) : + setup_handler(default_handler), teardown_handler(default_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const test_setup_handler_t setup_handler, + const Case (&cases)[N], + const test_teardown_handler_t teardown_handler = default_handler, + const handlers_t defaults = default_handlers) : + setup_handler(setup_handler), teardown_handler(teardown_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const test_setup_handler_t setup_handler, + const Case (&cases)[N], + const handlers_t defaults) : + setup_handler(setup_handler), teardown_handler(default_handler), + cases(cases), length(N), + defaults(defaults) + {} + + private: + const test_setup_handler_t setup_handler; + const test_teardown_handler_t teardown_handler; + const Case *const cases; + const size_t length; + const handlers_t defaults; + + friend class Harness; + }; + +} // namespace v0 +} // namespace utest + + #endif // MBED_TEST_ASYNC_SPECIFICATION_H diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" new file mode 100644 index 0000000000..bdaf1653d6 --- /dev/null +++ "b/frameworks\\utest/utest/types.h" @@ -0,0 +1,226 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_TYPES_H +#define MBED_TEST_ASYNC_TYPES_H + +#include +#include +#include + + +namespace utest { +namespace v0 { + + enum repeat_t { + REPEAT_NO_REPEAT = 0, ///< continue with the next test case + REPEAT_CASE_ONLY, ///< repeat the current test case without the setup and teardown handlers + REPEAT_ALL, ///< repeat the current test case with the setup and teardown handlers + }; + + enum status_t { + STATUS_CONTINUE = 0, ///< continues testing + STATUS_ABORT, ///< stops testing + }; + + enum failure_t { + FAILURE_NONE = 0, ///< No failure occurred + FAILURE, ///< An unknown failure occurred + FAILURE_CASES, ///< A failure occurred in at least one test case + FAILURE_EMPTY_CASE, ///< The test case contains only empty handlers + FAILURE_SETUP, ///< A failure occurred on setup + FAILURE_TEARDOWN, ///< A failure occurred on teardown + FAILURE_TIMEOUT, ///< An expected asynchronous call timed out + FAILURE_ASSERTION, ///< An assertion failed + }; + + /// Stringifies a failure for understandable error messages. + const char* stringify(failure_t failure); + + /** Control class for specifying test case attributes + * + * This class encapsulated control information about test cases which, when returned from + * a test case influences the behavior of the test harness. + * Instead of using this class directly it is recommended to use the aliases for clearer + * semantics: + * @code + * control_t test_case(const size_t repeat_count) { + * // repeat 5 times for a total of 6 calls + * return (repeat_count < 5) ? CaseRepeat : CaseNext; + * } + * @endcode + * + * This class overloads the `+` operator to implement something similiar to saturated arbitration: + * - The lower timeout value "wins". + * - A more involved repeat "wins" (ie. `ALL` > 'CASE_ONLY' > 'NO_REPEAT'). + * + * You may then add timeouts and repeats together: + * @code + * control_t test_case(const size_t repeat_count) { + * // repeat 5 times for a total of 6 calls, each with a 500ms asynchronous timeout + * return CaseTimeout(500) + ((repeat_count < 5) ? CaseRepeat : CaseNoRepeat); + * } + * @endcode + * + * In the future, more control information may be added transparently and backwards compatible. + */ + struct control_t + { + control_t() : repeat(REPEAT_NO_REPEAT), timeout(-1) {} + + control_t(repeat_t repeat, uint32_t timeout_ms) : + repeat(repeat), timeout(timeout_ms) {} + + control_t(repeat_t repeat) : + repeat(repeat), timeout(-1) {} + + control_t(uint32_t timeout_ms) : + repeat(REPEAT_NO_REPEAT), timeout(timeout_ms) {} + + control_t & + operator+(const control_t &rhs) { + if (repeat == 0 || repeat < rhs.repeat) repeat = rhs.repeat; + if (timeout == uint32_t(-1) || timeout > rhs.timeout) timeout = rhs.timeout; + return *this; + } + + private: + repeat_t repeat; + uint32_t timeout; + friend class Harness; + }; + + /// Alias class for asynchronous timeout control in milliseconds + struct CaseTimeout : public control_t { + CaseTimeout(uint32_t ms) : control_t(ms) {} + }; + /// repeats only the test case handler without calling teardown and setup handlers + const control_t CaseRepeatHandlerOnly = control_t(REPEAT_CASE_ONLY); + /// repeats the test case handler with calling teardown and setup handlers + const control_t CaseRepeat = control_t(REPEAT_ALL); + /// does not repeat this test case, but moves on to the next one + const control_t CaseNext = control_t(REPEAT_NO_REPEAT); + + class Case; // forward declaration + + /** Test setup handler. + * + * This handler is called before execution of any test case and + * allows you to initialize your common test environment. + * + * @param number_of_cases the total number of test cases in the test specification + * + * @returns + * You can return `STATUS_ABORT` if you initialization failed and the test teardown handler will + * then be called with the `FAILURE_SETUP`. + */ + typedef status_t (*test_setup_handler_t)(const size_t number_of_cases); + + /** Test teardown handler. + * + * This handler is called after execution of all test case or if test execution is aborted. + * You can use this handler to de-initialize your test environment and output test statistics. + * The failure argument contains the immediate reason why this handler is called. + * If the test completed normally without failures, this will contain `FAILURE_NONE`. + * + * After execution of this handler, the test harness will stop execution. + * + * @param passed the number of cases without failures + * @param failed the number of cases with at least one failure + * @param failure the reason why this handler was called + */ + typedef void (*test_teardown_handler_t)(const size_t passed, const size_t failed, const failure_t failure); + + /** Test case setup handler. + * + * This handler is called before execution of each test case and + * allows you to modify your environment before each test case. + * + * @param source the test case to be setup + * @param index_of_case the current index of the test case within the specification + * + * @returns + * You can return `STATUS_ABORT` to indicate that your setup failed, which will call the case + * failure handler with `FAILURE_SETUP` and then the case teardown handler with `FAILURE_SETUP`. + * This gives the teardown handler a chance to clean up a failed setup. + */ + typedef status_t (*case_setup_handler_t)(const Case *const source, const size_t index_of_case); + + /** Primitive test case handler + * + * This handler is called only if the case setup succeeded and is followed by the test case teardown handler. + * + * @note This handler is executed only once. + */ + typedef void (*case_handler_t)(void); + + /** Complex test case handler + * + * This handler is called only if the case setup succeeded and then may be repeated or + * awaiting a asynchronous callback, depending on the return modifiers. + * + * @returns + * A combination of control modifiers. + */ + typedef control_t (*case_control_handler_t)(void); + + /** Test case handler (repeatable) + * + * This handler is called only if the case setup succeeded and then may be repeated or + * awaiting a asynchronous callback, depending on the return modifiers. + * + * @param repeat_count starting at `0`, contains the number of times this handler has been called + * + * @returns + * A combination of control modifiers. + */ + typedef control_t (*case_repeat_count_handler_t)(const size_t repeat_count); + + /** Test case teardown handler. + * + * This handler is called after execution of each test case or all repeated test cases and + * allows you to reset your environment after each test case. + * + * @param source the test case to be torn down + * @param passed the number of cases without failures (can be >1 for repeated test cases) + * @param failed the number failures (can be larger than the number of (repeated) test cases) + * @param failure the reason why this handler was called + * + * @returns + * You can return `STATUS_ABORT` to indicate that your teardown failed, which will call the case + * failure handler with `FAILURE_TEARDOWN`. + */ + typedef status_t (*case_teardown_handler_t)(const Case *const source, const size_t passed, const size_t failed, const failure_t reason); + + /** Test case failure handler. + * + * This handler is called whenever a failure occurred during the setup, execution or teardown. + * + * @param source the test case in which the failure occurred + * @param reason the reason why this handler was called + * + * @returns + * You can return `STATUS_ABORT` to indicate that this failure is non-recoverable, which will call the case + * teardown handler with reason. If a failure occurs during teardown, the teardown will not be called again. + */ + typedef status_t (*case_failure_handler_t)(const Case *const source, const failure_t reason); + +} // namespace v0 +} // namespace utest + +#endif // MBED_TEST_ASYNC_TYPES_H diff --git "a/frameworks\\utest/utest/unity_handler.h" "b/frameworks\\utest/utest/unity_handler.h" new file mode 100644 index 0000000000..ac7a332d82 --- /dev/null +++ "b/frameworks\\utest/utest/unity_handler.h" @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_UNITY_ASSERT_FAILURE_H +#define MBED_TEST_ASYNC_UNITY_ASSERT_FAILURE_H + +#include + +/// this function is called from the unity module when an assertion failed. +void utest_unity_assert_failure(); + +#endif // MBED_ASYNC_TEST_UNITY_ASSERT_FAILURE_H diff --git "a/frameworks\\utest/utest/utest.h" "b/frameworks\\utest/utest/utest.h" new file mode 100644 index 0000000000..8d85983cbf --- /dev/null +++ "b/frameworks\\utest/utest/utest.h" @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef MBED_TEST_ASYNC_H +#define MBED_TEST_ASYNC_H + +#include "types.h" +#include "case.h" +#include "default_handlers.h" +#include "harness.h" + +#endif // MBED_TEST_ASYNC_H From 13987f8101929c305d2802af675567a5b21d5b9c Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 23 Nov 2015 13:42:18 +0000 Subject: [PATCH 31/88] Adapt include path for header file move to `utest`. --- "frameworks\\utest/source/case.cpp" | 2 +- "frameworks\\utest/source/default_handlers.cpp" | 4 ++-- "frameworks\\utest/source/harness.cpp" | 2 +- "frameworks\\utest/source/types.cpp" | 2 +- "frameworks\\utest/source/unity_handler.cpp" | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index b57d3bef1e..9a25d8aeeb 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/case.h" + #include "utest/case.h" using namespace utest::v0; diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 646b180701..3a79b4bcf0 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -16,8 +16,8 @@ **************************************************************************** */ - #include "mbed-test-async/default_handlers.h" - #include "mbed-test-async/case.h" + #include "utest/default_handlers.h" + #include "utest/case.h" using namespace utest::v0; diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 25fedcc088..3c0846df97 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/harness.h" + #include "utest/harness.h" #include "minar/minar.h" #include "core-util/CriticalSectionLock.h" diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index f8330f2af5..946e041de2 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/types.h" + #include "utest/types.h" const char* utest::v0::stringify(utest::v0::failure_t failure) { diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index 8bd10ec996..f333e21df7 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -16,7 +16,7 @@ **************************************************************************** */ - #include "mbed-test-async/harness.h" + #include "utest/harness.h" extern "C" void utest_unity_assert_failure() From dc8c33665202f350570190ab9ffab68d34f60c4a Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 23 Nov 2015 14:21:26 +0000 Subject: [PATCH 32/88] Refactor all include guards to `UTEST_*`. --- "frameworks\\utest/utest/case.h" | 6 +++--- "frameworks\\utest/utest/default_handlers.h" | 6 +++--- "frameworks\\utest/utest/harness.h" | 6 +++--- "frameworks\\utest/utest/specification.h" | 6 +++--- "frameworks\\utest/utest/types.h" | 6 +++--- "frameworks\\utest/utest/unity_handler.h" | 6 +++--- "frameworks\\utest/utest/utest.h" | 7 ++++--- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git "a/frameworks\\utest/utest/case.h" "b/frameworks\\utest/utest/case.h" index 07106a4fc2..273dc5fc21 100644 --- "a/frameworks\\utest/utest/case.h" +++ "b/frameworks\\utest/utest/case.h" @@ -16,8 +16,8 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_CASES_H -#define MBED_TEST_ASYNC_CASES_H +#ifndef UTEST_CASES_H +#define UTEST_CASES_H #include #include @@ -126,4 +126,4 @@ namespace v0 { } // namespace v0 } // namespace utest - #endif // MBED_TEST_ASYNC_CASES_H + #endif // UTEST_CASES_H diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 102a80bade..c3d4e62613 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -16,8 +16,8 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_DEFAULT_HANDLER_H -#define MBED_TEST_ASYNC_DEFAULT_HANDLER_H +#ifndef UTEST_DEFAULT_HANDLER_H +#define UTEST_DEFAULT_HANDLER_H #include #include @@ -170,4 +170,4 @@ namespace v0 { } // namespace v0 } // namespace utest -#endif // MBED_TEST_ASYNC_DEFAULT_HANDLER_H +#endif // UTEST_DEFAULT_HANDLER_H diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index fea99d4104..ea6aaf60ab 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -16,8 +16,8 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_HARNESS_H -#define MBED_TEST_ASYNC_HARNESS_H +#ifndef UTEST_HARNESS_H +#define UTEST_HARNESS_H #include #include @@ -70,4 +70,4 @@ namespace v0 { } // namespace v0 } // namespace utest -#endif // MBED_TEST_ASYNC_HARNESS_H +#endif // UTEST_HARNESS_H diff --git "a/frameworks\\utest/utest/specification.h" "b/frameworks\\utest/utest/specification.h" index daec492d2e..6b49bfe758 100644 --- "a/frameworks\\utest/utest/specification.h" +++ "b/frameworks\\utest/utest/specification.h" @@ -16,8 +16,8 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_SPECIFICATION_H -#define MBED_TEST_ASYNC_SPECIFICATION_H +#ifndef UTEST_SPECIFICATION_H +#define UTEST_SPECIFICATION_H #include #include @@ -94,4 +94,4 @@ namespace v0 { } // namespace v0 } // namespace utest - #endif // MBED_TEST_ASYNC_SPECIFICATION_H + #endif // UTEST_SPECIFICATION_H diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index bdaf1653d6..b65a0ddcac 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -16,8 +16,8 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_TYPES_H -#define MBED_TEST_ASYNC_TYPES_H +#ifndef UTEST_TYPES_H +#define UTEST_TYPES_H #include #include @@ -223,4 +223,4 @@ namespace v0 { } // namespace v0 } // namespace utest -#endif // MBED_TEST_ASYNC_TYPES_H +#endif // UTEST_TYPES_H diff --git "a/frameworks\\utest/utest/unity_handler.h" "b/frameworks\\utest/utest/unity_handler.h" index ac7a332d82..8ce3d06a3f 100644 --- "a/frameworks\\utest/utest/unity_handler.h" +++ "b/frameworks\\utest/utest/unity_handler.h" @@ -16,12 +16,12 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_UNITY_ASSERT_FAILURE_H -#define MBED_TEST_ASYNC_UNITY_ASSERT_FAILURE_H +#ifndef UTEST_UNITY_ASSERT_FAILURE_H +#define UTEST_UNITY_ASSERT_FAILURE_H #include /// this function is called from the unity module when an assertion failed. void utest_unity_assert_failure(); -#endif // MBED_ASYNC_TEST_UNITY_ASSERT_FAILURE_H +#endif // UTEST_UNITY_ASSERT_FAILURE_H diff --git "a/frameworks\\utest/utest/utest.h" "b/frameworks\\utest/utest/utest.h" index 8d85983cbf..98e20055aa 100644 --- "a/frameworks\\utest/utest/utest.h" +++ "b/frameworks\\utest/utest/utest.h" @@ -16,12 +16,13 @@ **************************************************************************** */ -#ifndef MBED_TEST_ASYNC_H -#define MBED_TEST_ASYNC_H +#ifndef UTEST_H +#define UTEST_H #include "types.h" #include "case.h" #include "default_handlers.h" #include "harness.h" -#endif // MBED_TEST_ASYNC_H + +#endif // UTEST_H From d59284850db8bb5b2518e1c84e4de25bb617a66f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 25 Nov 2015 15:41:33 +0000 Subject: [PATCH 33/88] Fix off-by-one error in case indexing. --- "frameworks\\utest/source/harness.cpp" | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 3c0846df97..11a9e283ea 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -179,8 +179,9 @@ void Harness::run_next_case() } if ((!case_failed && !case_passed) || case_control.repeat == REPEAT_ALL) { + uint32_t index_of_case = test_index_of_case; if (case_control.repeat == REPEAT_NO_REPEAT) test_index_of_case++; - if (handlers.case_setup && (handlers.case_setup(case_current, test_index_of_case) != STATUS_CONTINUE)) { + if (handlers.case_setup && (handlers.case_setup(case_current, index_of_case) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); return; From c2343b223b3955a0bd3152d742d8e0ec0a3616bb Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 25 Nov 2015 15:57:27 +0000 Subject: [PATCH 34/88] Update namespace from v0 to v1. --- "frameworks\\utest/source/case.cpp" | 2 +- .../source/default_handlers.cpp" | 18 +++++++++--------- "frameworks\\utest/source/harness.cpp" | 2 +- "frameworks\\utest/source/types.cpp" | 2 +- "frameworks\\utest/source/unity_handler.cpp" | 2 +- "frameworks\\utest/utest/case.h" | 4 ++-- "frameworks\\utest/utest/default_handlers.h" | 4 ++-- "frameworks\\utest/utest/harness.h" | 4 ++-- "frameworks\\utest/utest/specification.h" | 4 ++-- "frameworks\\utest/utest/types.h" | 4 ++-- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index 9a25d8aeeb..b5f5a93a3d 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -18,7 +18,7 @@ #include "utest/case.h" -using namespace utest::v0; +using namespace utest::v1; // normal handler Case::Case(const char *description, diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 3a79b4bcf0..e7d2183281 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -19,15 +19,15 @@ #include "utest/default_handlers.h" #include "utest/case.h" -using namespace utest::v0; +using namespace utest::v1; -status_t utest::v0::verbose_test_setup_handler(const size_t number_of_cases) +status_t utest::v1::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); return STATUS_CONTINUE; } -void utest::v0::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) +void utest::v1::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { printf("\n>>> Test cases: %u passed, %u failed", passed, failed); if (failure == FAILURE_NONE) { @@ -38,13 +38,13 @@ void utest::v0::verbose_test_teardown_handler(const size_t passed, const size_t if (failed) printf(">>> TESTS FAILED!\n"); } -status_t utest::v0::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) +status_t utest::v1::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) { printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); return STATUS_CONTINUE; } -status_t utest::v0::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +status_t utest::v1::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) { printf(">>> '%s': %u passed, %u failed", source->get_description(), passed, failed); if (failure == FAILURE_NONE) { @@ -55,7 +55,7 @@ status_t utest::v0::verbose_case_teardown_handler(const Case *const source, cons return STATUS_CONTINUE; } -status_t utest::v0::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) +status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { if (reason != FAILURE_ASSERTION) { printf(">>> failed with reason '%s'\n", stringify(reason)); @@ -65,7 +65,7 @@ status_t utest::v0::verbose_case_failure_handler(const Case *const /*source*/, c -status_t utest::v0::greentea_test_setup_handler(const size_t /*number_of_cases*/) +status_t utest::v1::greentea_test_setup_handler(const size_t /*number_of_cases*/) { printf(">>> I do not know how to tell greentea that the test started, since\n"); printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); @@ -73,7 +73,7 @@ status_t utest::v0::greentea_test_setup_handler(const size_t /*number_of_cases*/ return STATUS_ABORT; } -void utest::v0::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) +void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { verbose_test_teardown_handler(passed, failed, failure); if (failed || failure != FAILURE_NONE) { @@ -84,7 +84,7 @@ void utest::v0::greentea_test_teardown_handler(const size_t passed, const size_t printf("{{end}}\n"); } -status_t utest::v0::greentea_case_failure_handler(const Case *const source, const failure_t reason) +status_t utest::v1::greentea_case_failure_handler(const Case *const source, const failure_t reason) { verbose_case_failure_handler(source, reason); return STATUS_ABORT; diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 11a9e283ea..094fba640b 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -20,7 +20,7 @@ #include "minar/minar.h" #include "core-util/CriticalSectionLock.h" -using namespace utest::v0; +using namespace utest::v1; namespace diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index 946e041de2..6e0d643cf1 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -18,7 +18,7 @@ #include "utest/types.h" -const char* utest::v0::stringify(utest::v0::failure_t failure) +const char* utest::v1::stringify(utest::v1::failure_t failure) { switch(failure) { diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index f333e21df7..5baaa6cb8f 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -21,5 +21,5 @@ extern "C" void utest_unity_assert_failure() { - utest::v0::Harness::raise_failure(utest::v0::FAILURE_ASSERTION); + utest::v1::Harness::raise_failure(utest::v1::FAILURE_ASSERTION); } diff --git "a/frameworks\\utest/utest/case.h" "b/frameworks\\utest/utest/case.h" index 273dc5fc21..35b6639d12 100644 --- "a/frameworks\\utest/utest/case.h" +++ "b/frameworks\\utest/utest/case.h" @@ -27,7 +27,7 @@ namespace utest { -namespace v0 { +namespace v1 { /** Test case wrapper class. * @@ -123,7 +123,7 @@ namespace v0 { friend class Harness; }; -} // namespace v0 +} // namespace v1 } // namespace utest #endif // UTEST_CASES_H diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index c3d4e62613..f4af713e8e 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -26,7 +26,7 @@ namespace utest { -namespace v0 { +namespace v1 { /** Default handler hint. * @@ -167,7 +167,7 @@ namespace v0 { /// The greentea aborting handlers are the default const handlers_t default_handlers = greentea_abort_handlers; -} // namespace v0 +} // namespace v1 } // namespace utest #endif // UTEST_DEFAULT_HANDLER_H diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index ea6aaf60ab..bb6769ba8e 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -30,7 +30,7 @@ namespace utest { -namespace v0 { +namespace v1 { /** Test Harness. * @@ -67,7 +67,7 @@ namespace v0 { static void schedule_next_case(); }; -} // namespace v0 +} // namespace v1 } // namespace utest #endif // UTEST_HARNESS_H diff --git "a/frameworks\\utest/utest/specification.h" "b/frameworks\\utest/utest/specification.h" index 6b49bfe758..4ba520d9b9 100644 --- "a/frameworks\\utest/utest/specification.h" +++ "b/frameworks\\utest/utest/specification.h" @@ -28,7 +28,7 @@ namespace utest { -namespace v0 { +namespace v1 { /** Test specification containing the setup and teardown handlers and test cases. * @@ -91,7 +91,7 @@ namespace v0 { friend class Harness; }; -} // namespace v0 +} // namespace v1 } // namespace utest #endif // UTEST_SPECIFICATION_H diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index b65a0ddcac..7ef5543c54 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -25,7 +25,7 @@ namespace utest { -namespace v0 { +namespace v1 { enum repeat_t { REPEAT_NO_REPEAT = 0, ///< continue with the next test case @@ -220,7 +220,7 @@ namespace v0 { */ typedef status_t (*case_failure_handler_t)(const Case *const source, const failure_t reason); -} // namespace v0 +} // namespace v1 } // namespace utest #endif // UTEST_TYPES_H From 4e5996ceeab7c134a16eb39e7f03da84087bd3c3 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 4 Dec 2015 17:38:40 +0000 Subject: [PATCH 35/88] Allow starting a specification at a different case. This can be used to skip failing test cases with external support from a test runner like greentea. It would reset the device and execute the specification again, but start at the next test case. --- "frameworks\\utest/source/harness.cpp" | 11 ++++++++++- "frameworks\\utest/utest/harness.h" | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 094fba640b..fe6dd62c63 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -52,9 +52,18 @@ static void die() { } void Harness::run(const Specification specification) +{ + run(specification, 0); +} + +void Harness::run(const Specification specification, std::size_t start_case) { mbed::util::CriticalSectionLock lock; + // ignore any invalid start index + if (start_case >= specification.length) + return; + test_cases = specification.cases; test_length = specification.length; defaults = specification.defaults; @@ -68,7 +77,7 @@ void Harness::run(const Specification specification) case_passed = 0; case_failed = 0; case_failed_before = 0; - case_current = test_cases; + case_current = &test_cases[start_case]; if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { if (handlers.test_teardown) handlers.test_teardown(0, 0, FAILURE_SETUP); diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index bb6769ba8e..f2c228b6ff 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -43,9 +43,13 @@ namespace v1 { class Harness { public: - /// Starts running a test specification + /// Runs a test specification static void run(const Specification specification); + /// Runs a test specification starting at the specified case index + /// @warning if the start index is out of bounds, the call has no effect! + static void run(const Specification specification, size_t start_case); + /// @returns `true` if a test specification is being executed, `false` otherwise static bool is_busy(); From 0b93efe7f6f63425e00036932d3887397945714e Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 8 Dec 2015 13:32:59 +0000 Subject: [PATCH 36/88] Return whether the specification can be run or not. Do not die after specification teardown handler. --- "frameworks\\utest/source/harness.cpp" | 18 ++++++++++++------ "frameworks\\utest/utest/harness.h" | 8 ++++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index fe6dd62c63..a40ae9fc00 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -51,18 +51,22 @@ static void die() { while(1) ; } -void Harness::run(const Specification specification) +bool Harness::run(const Specification specification) { - run(specification, 0); + return run(specification, 0); } -void Harness::run(const Specification specification, std::size_t start_case) +bool Harness::run(const Specification specification, std::size_t start_case) { mbed::util::CriticalSectionLock lock; // ignore any invalid start index if (start_case >= specification.length) - return; + return false; + + // check if a specification is currently running + if (is_busy()) + return false; test_cases = specification.cases; test_length = specification.length; @@ -81,10 +85,12 @@ void Harness::run(const Specification specification, std::size_t start_case) if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { if (handlers.test_teardown) handlers.test_teardown(0, 0, FAILURE_SETUP); - die(); + test_cases = NULL; + return true; } minar::Scheduler::postCallback(run_next_case); + return true; } void Harness::raise_failure(failure_t reason) @@ -219,6 +225,6 @@ void Harness::run_next_case() } else if (handlers.test_teardown) { handlers.test_teardown(test_passed, test_failed, test_failed ? FAILURE_CASES : FAILURE_NONE); - die(); + test_cases = NULL; } } diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index f2c228b6ff..ddb65dbdc4 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -44,11 +44,15 @@ namespace v1 { { public: /// Runs a test specification - static void run(const Specification specification); + /// @retval `true` if the specification can be run + /// @retval `false` if another specification is currently running + static bool run(const Specification specification); /// Runs a test specification starting at the specified case index /// @warning if the start index is out of bounds, the call has no effect! - static void run(const Specification specification, size_t start_case); + /// @retval `true` if the specification can be run + /// @retval `false` if another specification is currently running, or the start index was out of bounds + static bool run(const Specification specification, size_t start_case); /// @returns `true` if a test specification is being executed, `false` otherwise static bool is_busy(); From dc242ee280231cbcb1f743e0bc681a4f5653bdb2 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 8 Dec 2015 17:45:25 +0000 Subject: [PATCH 37/88] Harness: Atomic execution of handlers not necessary. --- "frameworks\\utest/source/harness.cpp" | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index a40ae9fc00..c4b3c84f2f 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -38,6 +38,7 @@ namespace size_t case_repeat_count = 0; minar::callback_handle_t case_timeout_handle = NULL; + size_t case_validation_count = 0; size_t case_passed = 0; size_t case_failed = 0; @@ -58,8 +59,6 @@ bool Harness::run(const Specification specification) bool Harness::run(const Specification specification, std::size_t start_case) { - mbed::util::CriticalSectionLock lock; - // ignore any invalid start index if (start_case >= specification.length) return false; @@ -95,12 +94,18 @@ bool Harness::run(const Specification specification, std::size_t start_case) void Harness::raise_failure(failure_t reason) { - mbed::util::CriticalSectionLock lock; - - case_failed++; status_t fail_status = STATUS_ABORT; + { + mbed::util::CriticalSectionLock lock; + case_failed++; - if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); + if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); + if (fail_status != STATUS_CONTINUE && case_timeout_handle != NULL) + { + minar::Scheduler::cancelCallback(case_timeout_handle); + case_timeout_handle = NULL; + } + } if (fail_status != STATUS_CONTINUE || reason == FAILURE_SETUP) { if (handlers.case_teardown && reason != FAILURE_TEARDOWN) { @@ -152,19 +157,20 @@ void Harness::handle_timeout() { raise_failure(FAILURE_TIMEOUT); case_timeout_handle = NULL; - schedule_next_case(); + minar::Scheduler::postCallback(schedule_next_case); } } void Harness::validate_callback() { mbed::util::CriticalSectionLock lock; + case_validation_count++; if (case_timeout_handle != NULL) { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; - schedule_next_case(); + minar::Scheduler::postCallback(schedule_next_case); } } @@ -179,8 +185,6 @@ bool Harness::is_busy() void Harness::run_next_case() { - mbed::util::CriticalSectionLock lock; - if(case_current < (test_cases + test_length)) { handlers.case_setup = defaults.get_handler(case_current->setup_handler); @@ -193,6 +197,8 @@ void Harness::run_next_case() return; } + case_validation_count = 0; + if ((!case_failed && !case_passed) || case_control.repeat == REPEAT_ALL) { uint32_t index_of_case = test_index_of_case; if (case_control.repeat == REPEAT_NO_REPEAT) test_index_of_case++; @@ -202,6 +208,7 @@ void Harness::run_next_case() return; } } + // printf("running test case %p\n", case_current); case_failed_before = case_failed; @@ -214,13 +221,16 @@ void Harness::run_next_case() } case_repeat_count++; - if (case_control.timeout != uint32_t(-1)) { - case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) - .delay(minar::milliseconds(case_control.timeout)) - .getHandle(); - } - else { - schedule_next_case(); + { + mbed::util::CriticalSectionLock lock; + if (case_control.timeout != uint32_t(-1) && case_validation_count == 0) { + case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) + .delay(minar::milliseconds(case_control.timeout)) + .getHandle(); + } + else { + minar::Scheduler::postCallback(schedule_next_case); + } } } else if (handlers.test_teardown) { From 67e271f2929dcbf369dd938fdfd2b174ca15ee28 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 9 Dec 2015 17:57:45 +0000 Subject: [PATCH 38/88] Harness: Implement test case repeat on timeout. This is particularly useful for network unittests that may timeout, but are allowed to retry a number of times, before being declared a failure. --- .../source/default_handlers.cpp" | 10 ++-- "frameworks\\utest/source/harness.cpp" | 43 ++++++++++------- "frameworks\\utest/source/types.cpp" | 47 +++++++++++++++---- "frameworks\\utest/utest/types.h" | 31 +++++++++--- 4 files changed, 92 insertions(+), 39 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index e7d2183281..c750779269 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -58,9 +58,11 @@ status_t utest::v1::verbose_case_teardown_handler(const Case *const source, cons status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { if (reason != FAILURE_ASSERTION) { - printf(">>> failed with reason '%s'\n", stringify(reason)); + printf(">>> failure with reason '%s'\n", stringify(reason)); } - return (reason == FAILURE_TEARDOWN) ? STATUS_ABORT : STATUS_CONTINUE; + if (reason == FAILURE_TEARDOWN) return STATUS_ABORT; + if (reason & FAILURE_IGNORE) return STATUS_IGNORE; + return STATUS_CONTINUE; } @@ -86,6 +88,6 @@ void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t status_t utest::v1::greentea_case_failure_handler(const Case *const source, const failure_t reason) { - verbose_case_failure_handler(source, reason); - return STATUS_ABORT; + status_t status = verbose_case_failure_handler(source, reason); + return (status == STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; } diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index c4b3c84f2f..636ec4878a 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -34,7 +34,7 @@ namespace size_t test_failed = 0; const Case *case_current = NULL; - control_t case_control = control_t(); + control_t case_control = control_t(REPEAT_ALL); size_t case_repeat_count = 0; minar::callback_handle_t case_timeout_handle = NULL; @@ -97,17 +97,18 @@ void Harness::raise_failure(failure_t reason) status_t fail_status = STATUS_ABORT; { mbed::util::CriticalSectionLock lock; - case_failed++; if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); - if (fail_status != STATUS_CONTINUE && case_timeout_handle != NULL) + if (fail_status != STATUS_IGNORE) case_failed++; + + if (fail_status == STATUS_ABORT && case_timeout_handle) { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; } } - if (fail_status != STATUS_CONTINUE || reason == FAILURE_SETUP) { + if (fail_status == STATUS_ABORT || reason == FAILURE_SETUP) { if (handlers.case_teardown && reason != FAILURE_TEARDOWN) { status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, reason); if (teardown_status != STATUS_CONTINUE) { @@ -116,7 +117,7 @@ void Harness::raise_failure(failure_t reason) else handlers.case_teardown = NULL; } } - if (fail_status != STATUS_CONTINUE) { + if (fail_status == STATUS_ABORT) { test_failed++; if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, reason); die(); @@ -125,9 +126,10 @@ void Harness::raise_failure(failure_t reason) void Harness::schedule_next_case() { - if (case_failed_before == case_failed) case_passed++; + if (!(case_control.repeat & REPEAT_ON_TIMEOUT) && + case_failed_before == case_failed) case_passed++; - if(case_control.repeat != REPEAT_CASE_ONLY) { + if (case_control.repeat & REPEAT_ALL || case_control.repeat == REPEAT_NO_REPEAT) { if (handlers.case_teardown && (handlers.case_teardown(case_current, case_passed, case_failed, case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { @@ -135,11 +137,11 @@ void Harness::schedule_next_case() } } - if(case_control.repeat == REPEAT_NO_REPEAT) { + if (case_control.repeat == REPEAT_NO_REPEAT) { if (case_failed > 0) test_failed++; else test_passed++; - case_control = control_t(); + case_control = control_t(REPEAT_ALL); case_current++; case_passed = 0; case_failed = 0; @@ -151,12 +153,17 @@ void Harness::schedule_next_case() void Harness::handle_timeout() { - mbed::util::CriticalSectionLock lock; - - if (case_timeout_handle != NULL) + bool timeout_occurred = false; { - raise_failure(FAILURE_TIMEOUT); - case_timeout_handle = NULL; + mbed::util::CriticalSectionLock lock; + + if (case_timeout_handle != NULL) { + case_timeout_handle = NULL; + timeout_occurred = true; + } + } + if (timeout_occurred) { + raise_failure(failure_t(FAILURE_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? FAILURE_IGNORE : 0))); minar::Scheduler::postCallback(schedule_next_case); } } @@ -170,6 +177,7 @@ void Harness::validate_callback() { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; + if (case_control.repeat & REPEAT_ON_TIMEOUT) case_control = control_t(); minar::Scheduler::postCallback(schedule_next_case); } } @@ -199,16 +207,15 @@ void Harness::run_next_case() case_validation_count = 0; - if ((!case_failed && !case_passed) || case_control.repeat == REPEAT_ALL) { - uint32_t index_of_case = test_index_of_case; - if (case_control.repeat == REPEAT_NO_REPEAT) test_index_of_case++; + if (case_control.repeat == REPEAT_ALL) { + case_control = control_t(); + uint32_t index_of_case = test_index_of_case++; if (handlers.case_setup && (handlers.case_setup(case_current, index_of_case) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); return; } } - // printf("running test case %p\n", case_current); case_failed_before = case_failed; diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index 6e0d643cf1..8ef482b5e6 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -20,24 +20,51 @@ const char* utest::v1::stringify(utest::v1::failure_t failure) { - switch(failure) + const char *string; + switch(failure & ~FAILURE_IGNORE) { case FAILURE_NONE: - return "No Failure"; + string = "Ignored: No Failure"; + break; case FAILURE: - return "Unspecified Failure"; + string = "Ignored: Unspecified Failure"; + break; case FAILURE_CASES: - return "Test Cases Failed"; + string = "Ignored: Test Cases Failed"; + break; case FAILURE_EMPTY_CASE: - return "Test Case is Empty"; + string = "Ignored: Test Case is Empty"; + break; case FAILURE_SETUP: - return "Setup Failed"; + string = "Ignored: Setup Failed"; + break; case FAILURE_TEARDOWN: - return "Teardown Failed"; + string = "Ignored: Teardown Failed"; + break; case FAILURE_TIMEOUT: - return "Timed Out"; + string = "Ignored: Timed Out"; + break; case FAILURE_ASSERTION: - return "Assertion Failed"; + string = "Ignored: Assertion Failed"; + break; + default: + string = "Ignored: Unknown Failure"; + break; } - return "Unknown Failure"; + if (!(failure & FAILURE_IGNORE)) string += 9; + return string; +} + +const char* utest::v1::stringify(utest::v1::status_t status) +{ + switch(status) + { + case STATUS_CONTINUE: + return "Continue"; + case STATUS_IGNORE: + return "Ignore"; + case STATUS_ABORT: + return "Abort"; + } + return "Unknown Status"; } diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 7ef5543c54..3b44f6f595 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -22,19 +22,21 @@ #include #include #include - +#include "compiler-polyfill/attributes.h" namespace utest { namespace v1 { enum repeat_t { - REPEAT_NO_REPEAT = 0, ///< continue with the next test case - REPEAT_CASE_ONLY, ///< repeat the current test case without the setup and teardown handlers - REPEAT_ALL, ///< repeat the current test case with the setup and teardown handlers + REPEAT_NO_REPEAT = 0, ///< continue with the next test case + REPEAT_CASE_ONLY = 1, ///< repeat the current test case without the setup and teardown handlers + REPEAT_ALL = 2, ///< repeat the current test case with the setup and teardown handlers + REPEAT_ON_TIMEOUT = 4 ///< repeat the current on timeout only89 }; enum status_t { STATUS_CONTINUE = 0, ///< continues testing + STATUS_IGNORE, ///< ignores failure and continues testing STATUS_ABORT, ///< stops testing }; @@ -47,10 +49,13 @@ namespace v1 { FAILURE_TEARDOWN, ///< A failure occurred on teardown FAILURE_TIMEOUT, ///< An expected asynchronous call timed out FAILURE_ASSERTION, ///< An assertion failed + FAILURE_IGNORE = 0x8000, ///< A failure occurred, but may be ignored }; /// Stringifies a failure for understandable error messages. const char* stringify(failure_t failure); + /// Stringifies a status for understandable status messages. + const char* stringify(status_t status); /** Control class for specifying test case attributes * @@ -107,12 +112,24 @@ namespace v1 { /// Alias class for asynchronous timeout control in milliseconds struct CaseTimeout : public control_t { - CaseTimeout(uint32_t ms) : control_t(ms) {} + inline CaseTimeout(uint32_t ms) : control_t(ms) {} + }; + /// Alias class for asynchronous timeout control in milliseconds and + /// repeats the test case handler with calling teardown and setup handlers + struct CaseRepeatAllOnTimeout : public control_t { + inline CaseRepeatAllOnTimeout(uint32_t ms) : control_t(repeat_t(REPEAT_ALL | REPEAT_ON_TIMEOUT), ms) {} + }; + /// Alias class for asynchronous timeout control in milliseconds and + /// repeats only the test case handler without calling teardown and setup handlers + struct CaseRepeatHandlerOnTimeout : public control_t { + inline CaseRepeatHandlerOnTimeout(uint32_t ms) : control_t(repeat_t(REPEAT_CASE_ONLY | REPEAT_ON_TIMEOUT), ms) {} }; /// repeats only the test case handler without calling teardown and setup handlers - const control_t CaseRepeatHandlerOnly = control_t(REPEAT_CASE_ONLY); + const control_t CaseRepeatHandler = control_t(REPEAT_CASE_ONLY); + const control_t CaseRepeatHandlerOnly __deprecated = CaseRepeatHandler; // [[deprecated("use CaseRepeatHandler instead")]] /// repeats the test case handler with calling teardown and setup handlers - const control_t CaseRepeat = control_t(REPEAT_ALL); + const control_t CaseRepeatAll = control_t(REPEAT_ALL); + const control_t CaseRepeat __deprecated = CaseRepeatAll; // [[deprecated("use CaseRepeatAll instead")]] /// does not repeat this test case, but moves on to the next one const control_t CaseNext = control_t(REPEAT_NO_REPEAT); From 105d07b55251a504c2ce0c1679647100eec9f6b5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 11:42:40 +0000 Subject: [PATCH 39/88] Harness: Allow generic ignoring of failures. --- .../source/default_handlers.cpp" | 32 ++++++++++++++++--- "frameworks\\utest/source/harness.cpp" | 19 +++++------ "frameworks\\utest/utest/default_handlers.h" | 24 ++------------ "frameworks\\utest/utest/harness.h" | 4 +-- "frameworks\\utest/utest/types.h" | 26 +++++++-------- 5 files changed, 55 insertions(+), 50 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index c750779269..d9c9847f1a 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -21,6 +21,28 @@ using namespace utest::v1; +const handlers_t utest::v1::verbose_continue_handlers = { + verbose_test_setup_handler, + verbose_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + verbose_case_failure_handler +}; +const handlers_t utest::v1::greentea_abort_handlers = { + greentea_test_setup_handler, + greentea_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + greentea_case_failure_handler +}; +const handlers_t utest::v1::greentea_continue_handlers = { + greentea_test_setup_handler, + greentea_test_teardown_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + verbose_case_failure_handler +}; + status_t utest::v1::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); @@ -57,11 +79,11 @@ status_t utest::v1::verbose_case_teardown_handler(const Case *const source, cons status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { - if (reason != FAILURE_ASSERTION) { + if (!(reason & FAILURE_ASSERTION)) { printf(">>> failure with reason '%s'\n", stringify(reason)); } - if (reason == FAILURE_TEARDOWN) return STATUS_ABORT; - if (reason & FAILURE_IGNORE) return STATUS_IGNORE; + if (reason & FAILURE_TEARDOWN) return STATUS_ABORT; + if (reason & FAILURE_IGNORE) return STATUS_IGNORE; return STATUS_CONTINUE; } @@ -78,7 +100,7 @@ status_t utest::v1::greentea_test_setup_handler(const size_t /*number_of_cases*/ void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { verbose_test_teardown_handler(passed, failed, failure); - if (failed || failure != FAILURE_NONE) { + if (failed || (failure && !(failure & FAILURE_IGNORE))) { printf("{{failure}}\n"); } else { printf("{{success}}\n"); @@ -89,5 +111,5 @@ void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t status_t utest::v1::greentea_case_failure_handler(const Case *const source, const failure_t reason) { status_t status = verbose_case_failure_handler(source, reason); - return (status == STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; + return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; } diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 636ec4878a..f3faab68bc 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -52,12 +52,12 @@ static void die() { while(1) ; } -bool Harness::run(const Specification specification) +bool Harness::run(const Specification& specification) { return run(specification, 0); } -bool Harness::run(const Specification specification, std::size_t start_case) +bool Harness::run(const Specification& specification, std::size_t start_case) { // ignore any invalid start index if (start_case >= specification.length) @@ -99,17 +99,17 @@ void Harness::raise_failure(failure_t reason) mbed::util::CriticalSectionLock lock; if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); - if (fail_status != STATUS_IGNORE) case_failed++; + if (!(fail_status & STATUS_IGNORE)) case_failed++; - if (fail_status == STATUS_ABORT && case_timeout_handle) + if ((fail_status & STATUS_ABORT) && case_timeout_handle) { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; } } - if (fail_status == STATUS_ABORT || reason == FAILURE_SETUP) { - if (handlers.case_teardown && reason != FAILURE_TEARDOWN) { + if (fail_status & STATUS_ABORT || reason & FAILURE_SETUP) { + if (handlers.case_teardown && !(reason & FAILURE_TEARDOWN)) { status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, reason); if (teardown_status != STATUS_CONTINUE) { raise_failure(FAILURE_TEARDOWN); @@ -117,7 +117,7 @@ void Harness::raise_failure(failure_t reason) else handlers.case_teardown = NULL; } } - if (fail_status == STATUS_ABORT) { + if (fail_status & STATUS_ABORT) { test_failed++; if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, reason); die(); @@ -126,8 +126,9 @@ void Harness::raise_failure(failure_t reason) void Harness::schedule_next_case() { - if (!(case_control.repeat & REPEAT_ON_TIMEOUT) && - case_failed_before == case_failed) case_passed++; + if (!(case_control.repeat & REPEAT_ON_TIMEOUT) && case_failed_before == case_failed) { + case_passed++; + } if (case_control.repeat & REPEAT_ALL || case_control.repeat == REPEAT_NO_REPEAT) { if (handlers.case_teardown && diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index f4af713e8e..02c19dc448 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -138,31 +138,13 @@ namespace v1 { status_t greentea_case_failure_handler (const Case *const source, const failure_t reason); /// The verbose default handlers that always continue on failure - const handlers_t verbose_continue_handlers = { - verbose_test_setup_handler, - verbose_test_teardown_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - verbose_case_failure_handler - }; + extern const handlers_t verbose_continue_handlers; /// The greentea default handlers that always abort on the first encountered failure - const handlers_t greentea_abort_handlers = { - greentea_test_setup_handler, - greentea_test_teardown_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - greentea_case_failure_handler - }; + extern const handlers_t greentea_abort_handlers; /// The greentea default handlers that always continue on failure - const handlers_t greentea_continue_handlers = { - greentea_test_setup_handler, - greentea_test_teardown_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - verbose_case_failure_handler - }; + extern const handlers_t greentea_continue_handlers; /// The greentea aborting handlers are the default const handlers_t default_handlers = greentea_abort_handlers; diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index ddb65dbdc4..361cad2114 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -46,13 +46,13 @@ namespace v1 { /// Runs a test specification /// @retval `true` if the specification can be run /// @retval `false` if another specification is currently running - static bool run(const Specification specification); + static bool run(const Specification& specification); /// Runs a test specification starting at the specified case index /// @warning if the start index is out of bounds, the call has no effect! /// @retval `true` if the specification can be run /// @retval `false` if another specification is currently running, or the start index was out of bounds - static bool run(const Specification specification, size_t start_case); + static bool run(const Specification& specification, size_t start_case); /// @returns `true` if a test specification is being executed, `false` otherwise static bool is_busy(); diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 3b44f6f595..9016d6b4f4 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -31,25 +31,25 @@ namespace v1 { REPEAT_NO_REPEAT = 0, ///< continue with the next test case REPEAT_CASE_ONLY = 1, ///< repeat the current test case without the setup and teardown handlers REPEAT_ALL = 2, ///< repeat the current test case with the setup and teardown handlers - REPEAT_ON_TIMEOUT = 4 ///< repeat the current on timeout only89 + REPEAT_ON_TIMEOUT = 4 ///< repeat the current on timeout only }; enum status_t { - STATUS_CONTINUE = 0, ///< continues testing - STATUS_IGNORE, ///< ignores failure and continues testing - STATUS_ABORT, ///< stops testing + STATUS_CONTINUE = 0, ///< continues testing + STATUS_IGNORE = 1, ///< ignores failure and continues testing + STATUS_ABORT = 2 ///< stops testing }; enum failure_t { - FAILURE_NONE = 0, ///< No failure occurred - FAILURE, ///< An unknown failure occurred - FAILURE_CASES, ///< A failure occurred in at least one test case - FAILURE_EMPTY_CASE, ///< The test case contains only empty handlers - FAILURE_SETUP, ///< A failure occurred on setup - FAILURE_TEARDOWN, ///< A failure occurred on teardown - FAILURE_TIMEOUT, ///< An expected asynchronous call timed out - FAILURE_ASSERTION, ///< An assertion failed - FAILURE_IGNORE = 0x8000, ///< A failure occurred, but may be ignored + FAILURE_NONE = 0, ///< No failure occurred + FAILURE = 1, ///< An unknown failure occurred + FAILURE_CASES = 2, ///< A failure occurred in at least one test case + FAILURE_EMPTY_CASE = 4, ///< The test case contains only empty handlers + FAILURE_SETUP = 8, ///< A failure occurred on setup + FAILURE_TEARDOWN = 16, ///< A failure occurred on teardown + FAILURE_TIMEOUT = 32, ///< An expected asynchronous call timed out + FAILURE_ASSERTION = 64, ///< An assertion failed + FAILURE_IGNORE = 0x8000 ///< A failure occurred, but may be ignored }; /// Stringifies a failure for understandable error messages. From 633588dc357b96e6552cd118113f2e15c547f970 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 11:44:23 +0000 Subject: [PATCH 40/88] Handlers: Add test failure handler to allow selftest. --- .../source/default_handlers.cpp" | 19 ++++++ "frameworks\\utest/source/harness.cpp" | 10 ++-- "frameworks\\utest/utest/default_handlers.h" | 14 ++++- "frameworks\\utest/utest/specification.h" | 58 ++++++++++++++++--- "frameworks\\utest/utest/types.h" | 9 +++ 5 files changed, 96 insertions(+), 14 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index d9c9847f1a..4a41610614 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -24,6 +24,7 @@ using namespace utest::v1; const handlers_t utest::v1::verbose_continue_handlers = { verbose_test_setup_handler, verbose_test_teardown_handler, + ignore_handler, verbose_case_setup_handler, verbose_case_teardown_handler, verbose_case_failure_handler @@ -31,6 +32,7 @@ const handlers_t utest::v1::verbose_continue_handlers = { const handlers_t utest::v1::greentea_abort_handlers = { greentea_test_setup_handler, greentea_test_teardown_handler, + ignore_handler, verbose_case_setup_handler, verbose_case_teardown_handler, greentea_case_failure_handler @@ -38,6 +40,23 @@ const handlers_t utest::v1::greentea_abort_handlers = { const handlers_t utest::v1::greentea_continue_handlers = { greentea_test_setup_handler, greentea_test_teardown_handler, + ignore_handler, + verbose_case_setup_handler, + verbose_case_teardown_handler, + verbose_case_failure_handler +}; + +static void selftest_failure_handler(const failure_t reason) { + if (reason == FAILURE_ASSERTION) { + printf(">>> failure with reason '%s (in selftest)'\n{{failure}}\n{{end}}\n", stringify(reason)); + while(1) ; + } +} + +const handlers_t utest::v1::selftest_handlers = { + greentea_test_setup_handler, + greentea_test_teardown_handler, + selftest_failure_handler, verbose_case_setup_handler, verbose_case_teardown_handler, verbose_case_failure_handler diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index f3faab68bc..b574853cd9 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -22,7 +22,6 @@ using namespace utest::v1; - namespace { const Case *test_cases = NULL; @@ -67,11 +66,12 @@ bool Harness::run(const Specification& specification, std::size_t start_case) if (is_busy()) return false; - test_cases = specification.cases; + test_cases = specification.cases; test_length = specification.length; - defaults = specification.defaults; - handlers.test_setup = defaults.get_handler(specification.setup_handler); + defaults = specification.defaults; + handlers.test_setup = defaults.get_handler(specification.setup_handler); handlers.test_teardown = defaults.get_handler(specification.teardown_handler); + handlers.test_failure = defaults.get_handler(specification.failure_handler); test_index_of_case = 0; test_passed = 0; @@ -83,6 +83,7 @@ bool Harness::run(const Specification& specification, std::size_t start_case) case_current = &test_cases[start_case]; if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { + if (handlers.test_failure) handlers.test_failure(FAILURE_SETUP); if (handlers.test_teardown) handlers.test_teardown(0, 0, FAILURE_SETUP); test_cases = NULL; return true; @@ -98,6 +99,7 @@ void Harness::raise_failure(failure_t reason) { mbed::util::CriticalSectionLock lock; + if (handlers.test_failure) handlers.test_failure(reason); if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); if (!(fail_status & STATUS_IGNORE)) case_failed++; diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 02c19dc448..0e1e6d6a45 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -37,10 +37,11 @@ namespace v1 { { operator test_setup_handler_t() const { return test_setup_handler_t(1); } operator test_teardown_handler_t() const { return test_teardown_handler_t(1); } + operator test_failure_handler_t() const { return test_failure_handler_t(1); } operator case_setup_handler_t() const { return case_setup_handler_t(1); } operator case_teardown_handler_t() const { return case_teardown_handler_t(1); } - operator case_failure_handler_t() const { return case_failure_handler_t(1); } + operator case_failure_handler_t() const { return case_failure_handler_t(1); } } default_handler; /** Ignore handler hint. @@ -56,10 +57,11 @@ namespace v1 { operator test_setup_handler_t() const { return test_setup_handler_t(NULL); } operator test_teardown_handler_t() const { return test_teardown_handler_t(NULL); } + operator test_failure_handler_t() const { return test_failure_handler_t(NULL); } operator case_setup_handler_t() const { return case_setup_handler_t(NULL); } operator case_teardown_handler_t() const { return case_teardown_handler_t(NULL); } - operator case_failure_handler_t() const { return case_failure_handler_t(NULL); } + operator case_failure_handler_t() const { return case_failure_handler_t(NULL); } } ignore_handler; /** A table of handlers. @@ -88,6 +90,7 @@ namespace v1 { { test_setup_handler_t test_setup; test_teardown_handler_t test_teardown; + test_failure_handler_t test_failure; case_setup_handler_t case_setup; case_teardown_handler_t case_teardown; @@ -101,6 +104,10 @@ namespace v1 { if (handler == default_handler) return test_teardown; return handler; } + inline test_failure_handler_t get_handler(test_failure_handler_t handler) const { + if (handler == default_handler) return test_failure; + return handler; + } inline case_setup_handler_t get_handler(case_setup_handler_t handler) const { if (handler == default_handler) return case_setup; @@ -146,6 +153,9 @@ namespace v1 { /// The greentea default handlers that always continue on failure extern const handlers_t greentea_continue_handlers; + /// The selftest default handlers that always abort on _any_ assertion failure, otherwise continue + extern const handlers_t selftest_handlers; + /// The greentea aborting handlers are the default const handlers_t default_handlers = greentea_abort_handlers; diff --git "a/frameworks\\utest/utest/specification.h" "b/frameworks\\utest/utest/specification.h" index 4ba520d9b9..3e0747d2d7 100644 --- "a/frameworks\\utest/utest/specification.h" +++ "b/frameworks\\utest/utest/specification.h" @@ -48,16 +48,36 @@ namespace v1 { public: template< size_t N > Specification(const Case (&cases)[N], - const test_teardown_handler_t teardown_handler = default_handler, const handlers_t defaults = default_handlers) : - setup_handler(default_handler), teardown_handler(teardown_handler), + setup_handler(default_handler), teardown_handler(default_handler), failure_handler(default_handler), cases(cases), length(N), defaults(defaults) {} template< size_t N > - Specification(const Case (&cases)[N], const handlers_t defaults) : - setup_handler(default_handler), teardown_handler(default_handler), + Specification(const Case (&cases)[N], + const test_failure_handler_t failure_handler, + const handlers_t defaults = default_handlers) : + setup_handler(default_handler), teardown_handler(default_handler), failure_handler(failure_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const Case (&cases)[N], + const test_teardown_handler_t teardown_handler, + const handlers_t defaults = default_handlers) : + setup_handler(default_handler), teardown_handler(teardown_handler), failure_handler(default_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const Case (&cases)[N], + const test_teardown_handler_t teardown_handler, + const test_failure_handler_t failure_handler, + const handlers_t defaults = default_handlers) : + setup_handler(default_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), cases(cases), length(N), defaults(defaults) {} @@ -65,9 +85,8 @@ namespace v1 { template< size_t N > Specification(const test_setup_handler_t setup_handler, const Case (&cases)[N], - const test_teardown_handler_t teardown_handler = default_handler, const handlers_t defaults = default_handlers) : - setup_handler(setup_handler), teardown_handler(teardown_handler), + setup_handler(setup_handler), teardown_handler(default_handler), failure_handler(default_handler), cases(cases), length(N), defaults(defaults) {} @@ -75,8 +94,30 @@ namespace v1 { template< size_t N > Specification(const test_setup_handler_t setup_handler, const Case (&cases)[N], - const handlers_t defaults) : - setup_handler(setup_handler), teardown_handler(default_handler), + const test_failure_handler_t failure_handler, + const handlers_t defaults = default_handlers) : + setup_handler(setup_handler), teardown_handler(default_handler), failure_handler(failure_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const test_setup_handler_t setup_handler, + const Case (&cases)[N], + const test_teardown_handler_t teardown_handler, + const handlers_t defaults = default_handlers) : + setup_handler(setup_handler), teardown_handler(teardown_handler), failure_handler(default_handler), + cases(cases), length(N), + defaults(defaults) + {} + + template< size_t N > + Specification(const test_setup_handler_t setup_handler, + const Case (&cases)[N], + const test_teardown_handler_t teardown_handler, + const test_failure_handler_t failure_handler, + const handlers_t defaults = default_handlers) : + setup_handler(setup_handler), teardown_handler(teardown_handler), failure_handler(failure_handler), cases(cases), length(N), defaults(defaults) {} @@ -84,6 +125,7 @@ namespace v1 { private: const test_setup_handler_t setup_handler; const test_teardown_handler_t teardown_handler; + const test_failure_handler_t failure_handler; const Case *const cases; const size_t length; const handlers_t defaults; diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 9016d6b4f4..62064d2157 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -163,6 +163,15 @@ namespace v1 { */ typedef void (*test_teardown_handler_t)(const size_t passed, const size_t failed, const failure_t failure); + /** Test failure handler. + * + * This handler is called anytime a failure occurs during the execution of a test speficication. + * The handler only allows logging of failures and cannot influence test execution. + * + * @param failure the reason why this handler was called + */ + typedef void (*test_failure_handler_t)(const failure_t reason); + /** Test case setup handler. * * This handler is called before execution of each test case and From bc25003d41697c1ec750f35e3bc22d756ce1514b Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 11:45:36 +0000 Subject: [PATCH 41/88] Unity: Add failure ignoring callback. --- "frameworks\\utest/source/unity_handler.cpp" | 6 ++++++ "frameworks\\utest/utest/unity_handler.h" | 3 +++ 2 files changed, 9 insertions(+) diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index 5baaa6cb8f..b40978c75d 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -23,3 +23,9 @@ void utest_unity_assert_failure() { utest::v1::Harness::raise_failure(utest::v1::FAILURE_ASSERTION); } + +extern "C" +void utest_unity_ignore_failure() +{ + utest::v1::Harness::raise_failure(utest::v1::failure_t(utest::v1::FAILURE_ASSERTION | utest::v1::FAILURE_IGNORE)); +} diff --git "a/frameworks\\utest/utest/unity_handler.h" "b/frameworks\\utest/utest/unity_handler.h" index 8ce3d06a3f..5982ff88a9 100644 --- "a/frameworks\\utest/utest/unity_handler.h" +++ "b/frameworks\\utest/utest/unity_handler.h" @@ -24,4 +24,7 @@ /// this function is called from the unity module when an assertion failed. void utest_unity_assert_failure(); +/// this function is called from the unity module when an assertion failed, but is ignored. +void utest_unity_ignore_failure(); + #endif // UTEST_UNITY_ASSERT_FAILURE_H From 205233a6db24939bc9176858bbba5804c9af4a9f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 13:52:55 +0000 Subject: [PATCH 42/88] Repeat: Allow repeat on timeout and validation at the same time. --- "frameworks\\utest/source/harness.cpp" | 7 ++++--- "frameworks\\utest/utest/types.h" | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index b574853cd9..50787c74f1 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -128,11 +128,11 @@ void Harness::raise_failure(failure_t reason) void Harness::schedule_next_case() { - if (!(case_control.repeat & REPEAT_ON_TIMEOUT) && case_failed_before == case_failed) { + if ((case_control.repeat & REPEAT_ON_VALIDATE) && case_failed_before == case_failed) { case_passed++; } - if (case_control.repeat & REPEAT_ALL || case_control.repeat == REPEAT_NO_REPEAT) { + if (case_control.repeat & REPEAT_SETUP_TEARDOWN || case_control.repeat == REPEAT_NO_REPEAT) { if (handlers.case_teardown && (handlers.case_teardown(case_current, case_passed, case_failed, case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { @@ -180,7 +180,8 @@ void Harness::validate_callback() { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; - if (case_control.repeat & REPEAT_ON_TIMEOUT) case_control = control_t(); + if (case_control.repeat & REPEAT_ON_VALIDATE) case_control = control_t(REPEAT_ALL); + else if (case_control.repeat & REPEAT_ON_TIMEOUT) case_control = control_t(); minar::Scheduler::postCallback(schedule_next_case); } } diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 62064d2157..b8ef648e3d 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -29,9 +29,16 @@ namespace v1 { enum repeat_t { REPEAT_NO_REPEAT = 0, ///< continue with the next test case - REPEAT_CASE_ONLY = 1, ///< repeat the current test case without the setup and teardown handlers - REPEAT_ALL = 2, ///< repeat the current test case with the setup and teardown handlers - REPEAT_ON_TIMEOUT = 4 ///< repeat the current on timeout only + + REPEAT_ON_TIMEOUT = 1, + REPEAT_ON_VALIDATE = 2, + REPEAT_CASE_ONLY = 4, + REPEAT_SETUP_TEARDOWN = 8, + + REPEAT_ALL_ON_TIMEOUT = REPEAT_SETUP_TEARDOWN | REPEAT_ON_TIMEOUT, ///< repeat the handler with setup and teardown on timeout + REPEAT_HANDLER_ON_TIMEOUT = REPEAT_CASE_ONLY | REPEAT_ON_TIMEOUT, ///< repeat only the handler on timeout + REPEAT_ALL = REPEAT_SETUP_TEARDOWN | REPEAT_ON_VALIDATE, ///< repeat the handler with setup and teardown + REPEAT_HANDLER = REPEAT_CASE_ONLY | REPEAT_ON_VALIDATE ///< repeat only the handler }; enum status_t { @@ -99,7 +106,8 @@ namespace v1 { control_t & operator+(const control_t &rhs) { - if (repeat == 0 || repeat < rhs.repeat) repeat = rhs.repeat; + repeat = repeat_t(repeat | rhs.repeat); + if (repeat & REPEAT_SETUP_TEARDOWN) repeat = repeat_t(repeat & ~REPEAT_HANDLER); if (timeout == uint32_t(-1) || timeout > rhs.timeout) timeout = rhs.timeout; return *this; } @@ -117,15 +125,15 @@ namespace v1 { /// Alias class for asynchronous timeout control in milliseconds and /// repeats the test case handler with calling teardown and setup handlers struct CaseRepeatAllOnTimeout : public control_t { - inline CaseRepeatAllOnTimeout(uint32_t ms) : control_t(repeat_t(REPEAT_ALL | REPEAT_ON_TIMEOUT), ms) {} + inline CaseRepeatAllOnTimeout(uint32_t ms) : control_t(REPEAT_ALL_ON_TIMEOUT, ms) {} }; /// Alias class for asynchronous timeout control in milliseconds and /// repeats only the test case handler without calling teardown and setup handlers struct CaseRepeatHandlerOnTimeout : public control_t { - inline CaseRepeatHandlerOnTimeout(uint32_t ms) : control_t(repeat_t(REPEAT_CASE_ONLY | REPEAT_ON_TIMEOUT), ms) {} + inline CaseRepeatHandlerOnTimeout(uint32_t ms) : control_t(REPEAT_HANDLER_ON_TIMEOUT, ms) {} }; /// repeats only the test case handler without calling teardown and setup handlers - const control_t CaseRepeatHandler = control_t(REPEAT_CASE_ONLY); + const control_t CaseRepeatHandler = control_t(REPEAT_HANDLER); const control_t CaseRepeatHandlerOnly __deprecated = CaseRepeatHandler; // [[deprecated("use CaseRepeatHandler instead")]] /// repeats the test case handler with calling teardown and setup handlers const control_t CaseRepeatAll = control_t(REPEAT_ALL); From 17c89289a16fa1eb73b8fdefe6707a689d91da48 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 14:40:49 +0000 Subject: [PATCH 43/88] Harness: Fix bugs in repeat logic. --- "frameworks\\utest/source/harness.cpp" | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 50787c74f1..6401c648c2 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -33,11 +33,12 @@ namespace size_t test_failed = 0; const Case *case_current = NULL; - control_t case_control = control_t(REPEAT_ALL); + control_t case_control = control_t(REPEAT_SETUP_TEARDOWN); size_t case_repeat_count = 0; minar::callback_handle_t case_timeout_handle = NULL; size_t case_validation_count = 0; + bool case_timeout_occurred = false; size_t case_passed = 0; size_t case_failed = 0; @@ -128,11 +129,11 @@ void Harness::raise_failure(failure_t reason) void Harness::schedule_next_case() { - if ((case_control.repeat & REPEAT_ON_VALIDATE) && case_failed_before == case_failed) { + if (!case_timeout_occurred && case_failed_before == case_failed) { case_passed++; } - if (case_control.repeat & REPEAT_SETUP_TEARDOWN || case_control.repeat == REPEAT_NO_REPEAT) { + if (case_control.repeat & REPEAT_SETUP_TEARDOWN || !(case_control.repeat & (REPEAT_ON_TIMEOUT | REPEAT_ON_VALIDATE))) { if (handlers.case_teardown && (handlers.case_teardown(case_current, case_passed, case_failed, case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { @@ -140,11 +141,11 @@ void Harness::schedule_next_case() } } - if (case_control.repeat == REPEAT_NO_REPEAT) { + if (!(case_control.repeat & (REPEAT_ON_TIMEOUT | REPEAT_ON_VALIDATE))) { if (case_failed > 0) test_failed++; else test_passed++; - case_control = control_t(REPEAT_ALL); + case_control = control_t(REPEAT_SETUP_TEARDOWN); case_current++; case_passed = 0; case_failed = 0; @@ -156,16 +157,15 @@ void Harness::schedule_next_case() void Harness::handle_timeout() { - bool timeout_occurred = false; { mbed::util::CriticalSectionLock lock; if (case_timeout_handle != NULL) { case_timeout_handle = NULL; - timeout_occurred = true; + case_timeout_occurred = true; } } - if (timeout_occurred) { + if (case_timeout_occurred) { raise_failure(failure_t(FAILURE_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? FAILURE_IGNORE : 0))); minar::Scheduler::postCallback(schedule_next_case); } @@ -180,8 +180,7 @@ void Harness::validate_callback() { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; - if (case_control.repeat & REPEAT_ON_VALIDATE) case_control = control_t(REPEAT_ALL); - else if (case_control.repeat & REPEAT_ON_TIMEOUT) case_control = control_t(); + case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); minar::Scheduler::postCallback(schedule_next_case); } } @@ -209,9 +208,13 @@ void Harness::run_next_case() return; } - case_validation_count = 0; + { + mbed::util::CriticalSectionLock lock; + case_validation_count = 0; + case_timeout_occurred = false; + } - if (case_control.repeat == REPEAT_ALL) { + if (case_control.repeat & REPEAT_SETUP_TEARDOWN) { case_control = control_t(); uint32_t index_of_case = test_index_of_case++; if (handlers.case_setup && (handlers.case_setup(case_current, index_of_case) != STATUS_CONTINUE)) { @@ -234,6 +237,8 @@ void Harness::run_next_case() { mbed::util::CriticalSectionLock lock; + if (case_validation_count) case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); + if (case_control.timeout != uint32_t(-1) && case_validation_count == 0) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_control.timeout)) From 34571488a634c1e33a87748c8105d1fd166fbbd8 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 10 Dec 2015 16:00:39 +0000 Subject: [PATCH 44/88] Harness: Fix case index counting. --- "frameworks\\utest/source/harness.cpp" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 6401c648c2..620215db48 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -151,6 +151,7 @@ void Harness::schedule_next_case() case_failed = 0; case_failed_before = 0; case_repeat_count = 0; + test_index_of_case++; } minar::Scheduler::postCallback(run_next_case); } @@ -216,8 +217,7 @@ void Harness::run_next_case() if (case_control.repeat & REPEAT_SETUP_TEARDOWN) { case_control = control_t(); - uint32_t index_of_case = test_index_of_case++; - if (handlers.case_setup && (handlers.case_setup(case_current, index_of_case) != STATUS_CONTINUE)) { + if (handlers.case_setup && (handlers.case_setup(case_current, test_index_of_case) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); return; From 49952824fbf6a2fed37501e573452696ba9e236f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 11 Dec 2015 14:29:37 +0000 Subject: [PATCH 45/88] Handlers: Add specialized functions for all handlers. Most of them simply forward to the verbose handlers, however, should we decide differently in the future, existing unit tests will not have to be adapted. --- .../source/default_handlers.cpp" | 85 +++++++++++++------ "frameworks\\utest/utest/default_handlers.h" | 12 ++- 2 files changed, 71 insertions(+), 26 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 4a41610614..21d50149aa 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -21,6 +21,9 @@ using namespace utest::v1; +static status_t greentea_unknown_test_setup_handler(const size_t); +static void selftest_failure_handler(const failure_t reason); + const handlers_t utest::v1::verbose_continue_handlers = { verbose_test_setup_handler, verbose_test_teardown_handler, @@ -30,22 +33,38 @@ const handlers_t utest::v1::verbose_continue_handlers = { verbose_case_failure_handler }; const handlers_t utest::v1::greentea_abort_handlers = { - greentea_test_setup_handler, + greentea_unknown_test_setup_handler, greentea_test_teardown_handler, ignore_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - greentea_case_failure_handler + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_abort_handler }; const handlers_t utest::v1::greentea_continue_handlers = { - greentea_test_setup_handler, + greentea_unknown_test_setup_handler, greentea_test_teardown_handler, ignore_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - verbose_case_failure_handler + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_continue_handler }; +const handlers_t utest::v1::selftest_handlers = { + greentea_unknown_test_setup_handler, + greentea_test_teardown_handler, + selftest_failure_handler, + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_continue_handler +}; + +// --- SPECIAL HANDLERS --- +static status_t greentea_unknown_test_setup_handler(const size_t) { + printf(">>> I do not know how to tell greentea that the test started, since\n"); + printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); + + return STATUS_ABORT; +} static void selftest_failure_handler(const failure_t reason) { if (reason == FAILURE_ASSERTION) { printf(">>> failure with reason '%s (in selftest)'\n{{failure}}\n{{end}}\n", stringify(reason)); @@ -53,15 +72,7 @@ static void selftest_failure_handler(const failure_t reason) { } } -const handlers_t utest::v1::selftest_handlers = { - greentea_test_setup_handler, - greentea_test_teardown_handler, - selftest_failure_handler, - verbose_case_setup_handler, - verbose_case_teardown_handler, - verbose_case_failure_handler -}; - +// --- VERBOSE TEST HANDLERS --- status_t utest::v1::verbose_test_setup_handler(const size_t number_of_cases) { printf(">>> Running %u test cases...\n", number_of_cases); @@ -79,6 +90,12 @@ void utest::v1::verbose_test_teardown_handler(const size_t passed, const size_t if (failed) printf(">>> TESTS FAILED!\n"); } +void utest::v1::verbose_test_failure_handler(const failure_t reason) +{ + printf(">>> failure with reason '%s'\n", stringify(reason)); +} + +// --- VERBOSE CASE HANDLERS --- status_t utest::v1::verbose_case_setup_handler(const Case *const source, const size_t index_of_case) { printf("\n>>> Running case #%u: '%s'...\n", index_of_case + 1, source->get_description()); @@ -99,7 +116,7 @@ status_t utest::v1::verbose_case_teardown_handler(const Case *const source, cons status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) { if (!(reason & FAILURE_ASSERTION)) { - printf(">>> failure with reason '%s'\n", stringify(reason)); + verbose_test_failure_handler(reason); } if (reason & FAILURE_TEARDOWN) return STATUS_ABORT; if (reason & FAILURE_IGNORE) return STATUS_IGNORE; @@ -107,13 +124,10 @@ status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, c } - -status_t utest::v1::greentea_test_setup_handler(const size_t /*number_of_cases*/) +// --- GREENTEA HANDLERS --- +status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) { - printf(">>> I do not know how to tell greentea that the test started, since\n"); - printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); - - return STATUS_ABORT; + return verbose_test_setup_handler(number_of_cases); } void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) @@ -127,8 +141,29 @@ void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t printf("{{end}}\n"); } -status_t utest::v1::greentea_case_failure_handler(const Case *const source, const failure_t reason) +void utest::v1::greentea_test_failure_handler(const failure_t) +{ + // does nothing here +} + +// --- GREENTEA CASE HANDLERS --- +status_t utest::v1::greentea_case_setup_handler(const Case *const source, const size_t index_of_case) +{ + return verbose_case_setup_handler(source, index_of_case); +} + +status_t utest::v1::greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +{ + return verbose_case_teardown_handler(source, passed, failed, failure); +} + +status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t reason) { status_t status = verbose_case_failure_handler(source, reason); return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; } + +status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t reason) +{ + return verbose_case_failure_handler(source, reason); +} diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 0e1e6d6a45..970b21da49 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -127,6 +127,8 @@ namespace v1 { status_t verbose_test_setup_handler (const size_t number_of_cases); /// Prints the number of tests that passed and failed with a reason if provided. void verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); + /// Prints the failure. + void verbose_test_failure_handler(const failure_t failure); /// Prints the index and description of the case being run and continues. status_t verbose_case_setup_handler (const Case *const source, const size_t index_of_case); @@ -140,9 +142,17 @@ namespace v1 { status_t greentea_test_setup_handler (const size_t number_of_cases); /// Calls `verbose_test_teardown_handler` and then prints the greentea failure and success and end strings. void greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); + /// Does nothing. Use this for forwards compatibility. + void greentea_test_failure_handler(const failure_t failure); + /// Forwards to `verbose_case_setup_handler`. Use this for forwards compatibility. + status_t greentea_case_setup_handler (const Case *const source, const size_t index_of_case); + /// Forwards to `verbose_case_teardown_handler`. Use this for forwards compatibility. + status_t greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure); /// Calls `verbose_case_failure_handler` but then aborts. - status_t greentea_case_failure_handler (const Case *const source, const failure_t reason); + status_t greentea_case_failure_abort_handler (const Case *const source, const failure_t reason); + /// Forwards to `verbose_case_failure_handler`. Use this for forwards compatibility. + status_t greentea_case_failure_continue_handler (const Case *const source, const failure_t reason); /// The verbose default handlers that always continue on failure extern const handlers_t verbose_continue_handlers; From d2093f1ddcbaf9731811f8531f28488d01d1a63d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 15 Dec 2015 10:17:37 +0000 Subject: [PATCH 46/88] Types: Add type-compatible Timeout factory functions. Add CaseAwait behavior for infinite timeouts. Improve enum naming. --- "frameworks\\utest/source/harness.cpp" | 10 ++- "frameworks\\utest/utest/types.h" | 87 ++++++++++++++++---------- 2 files changed, 62 insertions(+), 35 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 620215db48..7e45314b1d 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -177,7 +177,7 @@ void Harness::validate_callback() mbed::util::CriticalSectionLock lock; case_validation_count++; - if (case_timeout_handle != NULL) + if (case_timeout_handle != NULL || case_control.timeout == TIMEOUT_FOREVER) { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; @@ -239,10 +239,14 @@ void Harness::run_next_case() mbed::util::CriticalSectionLock lock; if (case_validation_count) case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); - if (case_control.timeout != uint32_t(-1) && case_validation_count == 0) { - case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) + // if timeout valid + if (case_control.timeout != TIMEOUT_NONE && case_validation_count == 0) { + // if await validation _with_ timeout + if (case_control.timeout != TIMEOUT_FOREVER) { + case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_control.timeout)) .getHandle(); + } } else { minar::Scheduler::postCallback(schedule_next_case); diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index b8ef648e3d..29af2d3bc3 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -28,7 +28,7 @@ namespace utest { namespace v1 { enum repeat_t { - REPEAT_NO_REPEAT = 0, ///< continue with the next test case + REPEAT_NONE = 0, ///< continue with the next test case REPEAT_ON_TIMEOUT = 1, REPEAT_ON_VALIDATE = 2, @@ -59,6 +59,11 @@ namespace v1 { FAILURE_IGNORE = 0x8000 ///< A failure occurred, but may be ignored }; + enum { + TIMEOUT_FOREVER = uint32_t(-1), ///< Never time out + TIMEOUT_NONE = uint32_t(-2) ///< Do not use a timeout + }; + /// Stringifies a failure for understandable error messages. const char* stringify(failure_t failure); /// Stringifies a status for understandable status messages. @@ -73,19 +78,19 @@ namespace v1 { * @code * control_t test_case(const size_t repeat_count) { * // repeat 5 times for a total of 6 calls - * return (repeat_count < 5) ? CaseRepeat : CaseNext; + * return (repeat_count < 5) ? CaseRepeatHandler : CaseNext; * } * @endcode * * This class overloads the `+` operator to implement something similiar to saturated arbitration: * - The lower timeout value "wins". - * - A more involved repeat "wins" (ie. `ALL` > 'CASE_ONLY' > 'NO_REPEAT'). + * - A more involved repeat "wins" (ie. `ALL` > 'HANDLER' > 'NONE'). * * You may then add timeouts and repeats together: * @code * control_t test_case(const size_t repeat_count) { * // repeat 5 times for a total of 6 calls, each with a 500ms asynchronous timeout - * return CaseTimeout(500) + ((repeat_count < 5) ? CaseRepeat : CaseNoRepeat); + * return CaseTimeout(500) + ((repeat_count < 5) ? CaseRepeatAll : CaseNext); * } * @endcode * @@ -93,23 +98,41 @@ namespace v1 { */ struct control_t { - control_t() : repeat(REPEAT_NO_REPEAT), timeout(-1) {} + control_t() : repeat(REPEAT_NONE), timeout(TIMEOUT_NONE) {} control_t(repeat_t repeat, uint32_t timeout_ms) : repeat(repeat), timeout(timeout_ms) {} control_t(repeat_t repeat) : - repeat(repeat), timeout(-1) {} + repeat(repeat), timeout(TIMEOUT_NONE) {} control_t(uint32_t timeout_ms) : - repeat(REPEAT_NO_REPEAT), timeout(timeout_ms) {} + repeat(REPEAT_NONE), timeout(timeout_ms) {} - control_t & - operator+(const control_t &rhs) { - repeat = repeat_t(repeat | rhs.repeat); - if (repeat & REPEAT_SETUP_TEARDOWN) repeat = repeat_t(repeat & ~REPEAT_HANDLER); - if (timeout == uint32_t(-1) || timeout > rhs.timeout) timeout = rhs.timeout; - return *this; + control_t + inline operator+(const control_t& rhs) const { + control_t result(repeat_t(this->repeat | rhs.repeat), this->timeout); + + if (result.repeat & REPEAT_SETUP_TEARDOWN) { + result.repeat = repeat_t(result.repeat & ~REPEAT_HANDLER); + } + // This works and does the right thing, + // since (uint32_t(-1) > uint32_t(-2)) => true, or + // TIMEOUT_FOREVER > TIMEOUT_NONE => NONE overwrites FOREVER + // which is correct as it is more restrictive + if (result.timeout > rhs.timeout) { + result.timeout = rhs.timeout; + } + return result; + } + + repeat_t + inline get_repeat() const { + return repeat; + } + uint32_t + inline get_timeout() const { + return timeout; } private: @@ -118,28 +141,28 @@ namespace v1 { friend class Harness; }; - /// Alias class for asynchronous timeout control in milliseconds - struct CaseTimeout : public control_t { - inline CaseTimeout(uint32_t ms) : control_t(ms) {} - }; - /// Alias class for asynchronous timeout control in milliseconds and - /// repeats the test case handler with calling teardown and setup handlers - struct CaseRepeatAllOnTimeout : public control_t { - inline CaseRepeatAllOnTimeout(uint32_t ms) : control_t(REPEAT_ALL_ON_TIMEOUT, ms) {} - }; - /// Alias class for asynchronous timeout control in milliseconds and + /// Awaits until the callback is validated and never times out. Use with caution! + const control_t CaseAwait(TIMEOUT_FOREVER); /// repeats only the test case handler without calling teardown and setup handlers - struct CaseRepeatHandlerOnTimeout : public control_t { - inline CaseRepeatHandlerOnTimeout(uint32_t ms) : control_t(REPEAT_HANDLER_ON_TIMEOUT, ms) {} - }; - /// repeats only the test case handler without calling teardown and setup handlers - const control_t CaseRepeatHandler = control_t(REPEAT_HANDLER); - const control_t CaseRepeatHandlerOnly __deprecated = CaseRepeatHandler; // [[deprecated("use CaseRepeatHandler instead")]] + const control_t CaseRepeatHandler(REPEAT_HANDLER); /// repeats the test case handler with calling teardown and setup handlers - const control_t CaseRepeatAll = control_t(REPEAT_ALL); - const control_t CaseRepeat __deprecated = CaseRepeatAll; // [[deprecated("use CaseRepeatAll instead")]] + const control_t CaseRepeatAll(REPEAT_ALL); /// does not repeat this test case, but moves on to the next one - const control_t CaseNext = control_t(REPEAT_NO_REPEAT); + const control_t CaseNext(REPEAT_NONE); + + /// Alias class for asynchronous timeout control in milliseconds + inline control_t CaseTimeout(uint32_t ms) { return control_t(ms); } + /// Alias class for asynchronous timeout control in milliseconds and + /// repeats the test case handler with calling teardown and setup handlers + inline control_t CaseRepeatAllOnTimeout(uint32_t ms) { return control_t(REPEAT_ALL_ON_TIMEOUT, ms); } + /// Alias class for asynchronous timeout control in milliseconds and + /// repeats only the test case handler without calling teardown and setup handlers + inline control_t CaseRepeatHandlerOnTimeout(uint32_t ms) { return control_t(REPEAT_HANDLER_ON_TIMEOUT, ms); } + + __deprecated_message("Use CaseRepeatAll instead.") + const control_t CaseRepeat = CaseRepeatAll; + __deprecated_message("Use CaseRepeatHandler instead.") + const control_t CaseRepeatHandlerOnly = CaseRepeatHandler; class Case; // forward declaration From ea2befaeeeea71709979ee4652a6185e5ec5206b Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 16 Dec 2015 13:57:22 +0000 Subject: [PATCH 47/88] Test: Fix control_t behavior and assert with test. --- "frameworks\\utest/source/harness.cpp" | 4 +- "frameworks\\utest/utest/types.h" | 59 +++++++++++++++----------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 7e45314b1d..daf75c3cf7 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -240,9 +240,9 @@ void Harness::run_next_case() if (case_validation_count) case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); // if timeout valid - if (case_control.timeout != TIMEOUT_NONE && case_validation_count == 0) { + if (case_control.timeout < TIMEOUT_UNDECLR && case_validation_count == 0) { // if await validation _with_ timeout - if (case_control.timeout != TIMEOUT_FOREVER) { + if (case_control.timeout < TIMEOUT_FOREVER) { case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) .delay(minar::milliseconds(case_control.timeout)) .getHandle(); diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 29af2d3bc3..dcd5e70abe 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -28,12 +28,15 @@ namespace utest { namespace v1 { enum repeat_t { - REPEAT_NONE = 0, ///< continue with the next test case + REPEAT_UNDECLR = 0, + REPEAT_NONE = 1, ///< continue with the next test case - REPEAT_ON_TIMEOUT = 1, - REPEAT_ON_VALIDATE = 2, - REPEAT_CASE_ONLY = 4, - REPEAT_SETUP_TEARDOWN = 8, + REPEAT_ON_TIMEOUT = 2, + REPEAT_ON_VALIDATE = 4, + REPEAT_CASE_ONLY = 8, + REPEAT_SETUP_TEARDOWN = 16, + + REPEAT_MASK = REPEAT_ON_TIMEOUT | REPEAT_ON_VALIDATE | REPEAT_CASE_ONLY | REPEAT_SETUP_TEARDOWN, REPEAT_ALL_ON_TIMEOUT = REPEAT_SETUP_TEARDOWN | REPEAT_ON_TIMEOUT, ///< repeat the handler with setup and teardown on timeout REPEAT_HANDLER_ON_TIMEOUT = REPEAT_CASE_ONLY | REPEAT_ON_TIMEOUT, ///< repeat only the handler on timeout @@ -60,8 +63,9 @@ namespace v1 { }; enum { - TIMEOUT_FOREVER = uint32_t(-1), ///< Never time out - TIMEOUT_NONE = uint32_t(-2) ///< Do not use a timeout + TIMEOUT_NONE = uint32_t(-1), ///< Do not use a timeout + TIMEOUT_UNDECLR = uint32_t(-2), ///< Timeout not explicitly specified, defaults to NONE + TIMEOUT_FOREVER = uint32_t(-3) ///< Never time out }; /// Stringifies a failure for understandable error messages. @@ -98,31 +102,34 @@ namespace v1 { */ struct control_t { - control_t() : repeat(REPEAT_NONE), timeout(TIMEOUT_NONE) {} + control_t() : repeat(REPEAT_UNDECLR), timeout(TIMEOUT_UNDECLR) {} control_t(repeat_t repeat, uint32_t timeout_ms) : repeat(repeat), timeout(timeout_ms) {} control_t(repeat_t repeat) : - repeat(repeat), timeout(TIMEOUT_NONE) {} + repeat(repeat), timeout(TIMEOUT_UNDECLR) {} control_t(uint32_t timeout_ms) : - repeat(REPEAT_NONE), timeout(timeout_ms) {} + repeat(REPEAT_UNDECLR), timeout(timeout_ms) {} control_t inline operator+(const control_t& rhs) const { - control_t result(repeat_t(this->repeat | rhs.repeat), this->timeout); + control_t result( + repeat_t(this->repeat | rhs.repeat), + (rhs.timeout == TIMEOUT_NONE) ? rhs.timeout : this->timeout); - if (result.repeat & REPEAT_SETUP_TEARDOWN) { - result.repeat = repeat_t(result.repeat & ~REPEAT_HANDLER); + if (result.repeat & REPEAT_NONE) { + result.repeat = REPEAT_NONE; } - // This works and does the right thing, - // since (uint32_t(-1) > uint32_t(-2)) => true, or - // TIMEOUT_FOREVER > TIMEOUT_NONE => NONE overwrites FOREVER - // which is correct as it is more restrictive - if (result.timeout > rhs.timeout) { + else if (result.repeat & REPEAT_SETUP_TEARDOWN) { + result.repeat = repeat_t(result.repeat & ~REPEAT_CASE_ONLY); + } + + if (result.timeout != TIMEOUT_NONE && result.timeout > rhs.timeout) { result.timeout = rhs.timeout; } + return result; } @@ -141,17 +148,19 @@ namespace v1 { friend class Harness; }; - /// Awaits until the callback is validated and never times out. Use with caution! - const control_t CaseAwait(TIMEOUT_FOREVER); - /// repeats only the test case handler without calling teardown and setup handlers - const control_t CaseRepeatHandler(REPEAT_HANDLER); + /// does not repeat this test case, but moves on to the next one + const control_t CaseNext(REPEAT_NONE, TIMEOUT_NONE); + /// repeats the test case handler with calling teardown and setup handlers const control_t CaseRepeatAll(REPEAT_ALL); - /// does not repeat this test case, but moves on to the next one - const control_t CaseNext(REPEAT_NONE); + /// repeats only the test case handler without calling teardown and setup handlers + const control_t CaseRepeatHandler(REPEAT_HANDLER); + /// Awaits until the callback is validated and never times out. Use with caution! + const control_t CaseAwait(TIMEOUT_FOREVER); /// Alias class for asynchronous timeout control in milliseconds - inline control_t CaseTimeout(uint32_t ms) { return control_t(ms); } + inline control_t CaseTimeout(uint32_t ms) { return ms; } + /// Alias class for asynchronous timeout control in milliseconds and /// repeats the test case handler with calling teardown and setup handlers inline control_t CaseRepeatAllOnTimeout(uint32_t ms) { return control_t(REPEAT_ALL_ON_TIMEOUT, ms); } From aca2e920e36bbad04eb4d3c43c981b6a12330ead Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 17 Dec 2015 14:31:58 +0000 Subject: [PATCH 48/88] Types: Add `CaseNoRepeat` and `CaseNoTimeout` aliases. Add combination unit tests for aliases and fix bugs. This allows inline use of these properties. Example: `CaseTimeout(ms) + (repeat_count < 100 ? CaseRepeatAll : CaseNoRepeat);` --- "frameworks\\utest/utest/types.h" | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index dcd5e70abe..26aedc1da2 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -119,15 +119,20 @@ namespace v1 { repeat_t(this->repeat | rhs.repeat), (rhs.timeout == TIMEOUT_NONE) ? rhs.timeout : this->timeout); + if (result.timeout != TIMEOUT_NONE && result.timeout > rhs.timeout) { + result.timeout = rhs.timeout; + } + if (result.repeat & REPEAT_NONE) { result.repeat = REPEAT_NONE; } - else if (result.repeat & REPEAT_SETUP_TEARDOWN) { - result.repeat = repeat_t(result.repeat & ~REPEAT_CASE_ONLY); - } - - if (result.timeout != TIMEOUT_NONE && result.timeout > rhs.timeout) { - result.timeout = rhs.timeout; + else { + if (result.repeat & REPEAT_SETUP_TEARDOWN) { + result.repeat = repeat_t(result.repeat & ~REPEAT_CASE_ONLY); + } + if (result.timeout == TIMEOUT_NONE && result.repeat & REPEAT_ON_TIMEOUT) { + result.repeat = repeat_t(result.repeat & ~REPEAT_ON_TIMEOUT); + } } return result; @@ -148,14 +153,18 @@ namespace v1 { friend class Harness; }; - /// does not repeat this test case, but moves on to the next one + /// does not repeat this test case and immediately moves on to the next one without timeout const control_t CaseNext(REPEAT_NONE, TIMEOUT_NONE); + /// does not repeat this test case, moves on to the next one + const control_t CaseNoRepeat(REPEAT_NONE); /// repeats the test case handler with calling teardown and setup handlers const control_t CaseRepeatAll(REPEAT_ALL); /// repeats only the test case handler without calling teardown and setup handlers const control_t CaseRepeatHandler(REPEAT_HANDLER); + /// No timeout, immediately moves on to the next case, but allows repeats + const control_t CaseNoTimeout(TIMEOUT_NONE); /// Awaits until the callback is validated and never times out. Use with caution! const control_t CaseAwait(TIMEOUT_FOREVER); /// Alias class for asynchronous timeout control in milliseconds From 15f3ccad1b756253b99e33290b4ecb2aee4fb2eb Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Dec 2015 12:00:14 +0000 Subject: [PATCH 49/88] Add constants to `{default|ignore}_handler`. This is better than explicitly casting to the handler you want. --- "frameworks\\utest/utest/default_handlers.h" | 56 ++++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 970b21da49..3c9fa516ca 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -31,37 +31,59 @@ namespace v1 { /** Default handler hint. * * Use this handler to indicate the you want the default handler to be called. - * This type automatically casts itself into the appropriate handler type. + * This type automatically casts itself into the appropriate handler type, when possible. + * Use the constants to default a handler unambigously. */ const struct { - operator test_setup_handler_t() const { return test_setup_handler_t(1); } - operator test_teardown_handler_t() const { return test_teardown_handler_t(1); } - operator test_failure_handler_t() const { return test_failure_handler_t(1); } + const test_setup_handler_t test_setup = test_setup_handler_t(1); + const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); + const test_failure_handler_t test_failure = test_failure_handler_t(1); - operator case_setup_handler_t() const { return case_setup_handler_t(1); } - operator case_teardown_handler_t() const { return case_teardown_handler_t(1); } - operator case_failure_handler_t() const { return case_failure_handler_t(1); } + const case_setup_handler_t case_setup = case_setup_handler_t(1); + const case_teardown_handler_t case_teardown = case_teardown_handler_t(1); + const case_failure_handler_t case_failure = case_failure_handler_t(1); + + operator test_setup_handler_t() const { return test_setup; } + operator test_teardown_handler_t() const { return test_teardown; } + operator test_failure_handler_t() const { return test_failure; } + + operator case_setup_handler_t() const { return case_setup; } + operator case_teardown_handler_t() const { return case_teardown; } + operator case_failure_handler_t() const { return case_failure; } } default_handler; /** Ignore handler hint. * * Use this handler to indicate the you want to ignore this handler and it will not be called. - * This type automatically casts itself into the appropriate handler type. + * This type automatically casts itself into the appropriate handler type, when possible. + * Use the constants to ignore a handler unambigously. */ const struct { - operator case_handler_t() const { return case_handler_t(NULL); } - operator case_control_handler_t() const { return case_control_handler_t(NULL); } - operator case_repeat_count_handler_t() const { return case_repeat_count_handler_t(NULL); } + const case_handler_t handler = case_handler_t(NULL); + const case_control_handler_t control = case_control_handler_t(NULL); + const case_repeat_count_handler_t repeat_count = case_repeat_count_handler_t(NULL); - operator test_setup_handler_t() const { return test_setup_handler_t(NULL); } - operator test_teardown_handler_t() const { return test_teardown_handler_t(NULL); } - operator test_failure_handler_t() const { return test_failure_handler_t(NULL); } + const test_setup_handler_t test_setup = test_setup_handler_t(1); + const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); + const test_failure_handler_t test_failure = test_failure_handler_t(1); - operator case_setup_handler_t() const { return case_setup_handler_t(NULL); } - operator case_teardown_handler_t() const { return case_teardown_handler_t(NULL); } - operator case_failure_handler_t() const { return case_failure_handler_t(NULL); } + const case_setup_handler_t case_setup = case_setup_handler_t(1); + const case_teardown_handler_t case_teardown = case_teardown_handler_t(1); + const case_failure_handler_t case_failure = case_failure_handler_t(1); + + operator case_handler_t() const { return handler; } + operator case_control_handler_t() const { return control; } + operator case_repeat_count_handler_t() const { return repeat_count; } + + operator test_setup_handler_t() const { return test_setup; } + operator test_teardown_handler_t() const { return test_teardown; } + operator test_failure_handler_t() const { return test_failure; } + + operator case_setup_handler_t() const { return case_setup; } + operator case_teardown_handler_t() const { return case_teardown; } + operator case_failure_handler_t() const { return case_failure; } } ignore_handler; /** A table of handlers. From d5c8b80e737d26f6e2ebb68a9080a37dd70b61b1 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Dec 2015 15:35:28 +0000 Subject: [PATCH 50/88] Replace `repeat_count` with `call_count`. This aims to reduce confusion over repeat vs. call counting, and the resulting off-by-one error due to different user expectations. --- "frameworks\\utest/source/case.cpp" | 6 +++--- "frameworks\\utest/source/harness.cpp" | 4 ++-- "frameworks\\utest/utest/case.h" | 10 +++++----- "frameworks\\utest/utest/default_handlers.h" | 4 ++-- "frameworks\\utest/utest/types.h" | 13 +++++++------ 5 files changed, 19 insertions(+), 18 deletions(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index b5f5a93a3d..eb377679d3 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -103,7 +103,7 @@ Case::Case(const char *description, // control flow handler Case::Case(const char *description, const case_setup_handler_t setup_handler, - const case_repeat_count_handler_t case_repeat_count_handler, + const case_call_count_handler_t case_repeat_count_handler, const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), @@ -116,7 +116,7 @@ Case::Case(const char *description, {} Case::Case(const char *description, - const case_repeat_count_handler_t case_repeat_count_handler, + const case_call_count_handler_t case_repeat_count_handler, const case_failure_handler_t failure_handler) : description(description), handler(ignore_handler), @@ -128,7 +128,7 @@ Case::Case(const char *description, {} Case::Case(const char *description, - const case_repeat_count_handler_t case_repeat_count_handler, + const case_call_count_handler_t case_repeat_count_handler, const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler) : description(description), diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index daf75c3cf7..2e259d3a42 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -34,7 +34,7 @@ namespace const Case *case_current = NULL; control_t case_control = control_t(REPEAT_SETUP_TEARDOWN); - size_t case_repeat_count = 0; + size_t case_repeat_count = 1; minar::callback_handle_t case_timeout_handle = NULL; size_t case_validation_count = 0; @@ -150,7 +150,7 @@ void Harness::schedule_next_case() case_passed = 0; case_failed = 0; case_failed_before = 0; - case_repeat_count = 0; + case_repeat_count = 1; test_index_of_case++; } minar::Scheduler::postCallback(run_next_case); diff --git "a/frameworks\\utest/utest/case.h" "b/frameworks\\utest/utest/case.h" index 35b6639d12..bf9569ddeb 100644 --- "a/frameworks\\utest/utest/case.h" +++ "b/frameworks\\utest/utest/case.h" @@ -85,19 +85,19 @@ namespace v1 { const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler = default_handler); - // overloads for case_repeat_count_handler_t + // overloads for case_call_count_handler_t Case(const char *description, const case_setup_handler_t setup_handler, - const case_repeat_count_handler_t case_handler, + const case_call_count_handler_t case_handler, const case_teardown_handler_t teardown_handler = default_handler, const case_failure_handler_t failure_handler = default_handler); Case(const char *description, - const case_repeat_count_handler_t case_handler, + const case_call_count_handler_t case_handler, const case_failure_handler_t failure_handler = default_handler); Case(const char *description, - const case_repeat_count_handler_t case_handler, + const case_call_count_handler_t case_handler, const case_teardown_handler_t teardown_handler, const case_failure_handler_t failure_handler = default_handler); @@ -113,7 +113,7 @@ namespace v1 { const case_handler_t handler; const case_control_handler_t control_handler; - const case_repeat_count_handler_t repeat_count_handler; + const case_call_count_handler_t repeat_count_handler; const case_setup_handler_t setup_handler; const case_teardown_handler_t teardown_handler; diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 3c9fa516ca..bc493b3312 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -63,7 +63,7 @@ namespace v1 { { const case_handler_t handler = case_handler_t(NULL); const case_control_handler_t control = case_control_handler_t(NULL); - const case_repeat_count_handler_t repeat_count = case_repeat_count_handler_t(NULL); + const case_call_count_handler_t call_count = case_call_count_handler_t(NULL); const test_setup_handler_t test_setup = test_setup_handler_t(1); const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); @@ -75,7 +75,7 @@ namespace v1 { operator case_handler_t() const { return handler; } operator case_control_handler_t() const { return control; } - operator case_repeat_count_handler_t() const { return repeat_count; } + operator case_call_count_handler_t() const { return call_count; } operator test_setup_handler_t() const { return test_setup; } operator test_teardown_handler_t() const { return test_teardown; } diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 26aedc1da2..a63d9c863a 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -80,21 +80,22 @@ namespace v1 { * Instead of using this class directly it is recommended to use the aliases for clearer * semantics: * @code - * control_t test_case(const size_t repeat_count) { + * control_t test_case(const size_t call_count) { * // repeat 5 times for a total of 6 calls - * return (repeat_count < 5) ? CaseRepeatHandler : CaseNext; + * return (call_count < 6) ? CaseRepeatHandler : CaseNext; * } * @endcode * * This class overloads the `+` operator to implement something similiar to saturated arbitration: * - The lower timeout value "wins". * - A more involved repeat "wins" (ie. `ALL` > 'HANDLER' > 'NONE'). + * - Next Case always wins. * * You may then add timeouts and repeats together: * @code - * control_t test_case(const size_t repeat_count) { + * control_t test_case(const size_t call_count) { * // repeat 5 times for a total of 6 calls, each with a 500ms asynchronous timeout - * return CaseTimeout(500) + ((repeat_count < 5) ? CaseRepeatAll : CaseNext); + * return CaseTimeout(500) + ((call_count < 6) ? CaseRepeatAll : CaseNoRepeat); * } * @endcode * @@ -259,12 +260,12 @@ namespace v1 { * This handler is called only if the case setup succeeded and then may be repeated or * awaiting a asynchronous callback, depending on the return modifiers. * - * @param repeat_count starting at `0`, contains the number of times this handler has been called + * @param call_count starting at `1`, contains the number of times this handler has been called * * @returns * A combination of control modifiers. */ - typedef control_t (*case_repeat_count_handler_t)(const size_t repeat_count); + typedef control_t (*case_call_count_handler_t)(const size_t call_count); /** Test case teardown handler. * From 3abe3b04cf0ff54be9addbf3224198fe7ed3feee Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Dec 2015 15:59:27 +0000 Subject: [PATCH 51/88] Fix default handler initialization value. --- "frameworks\\utest/utest/default_handlers.h" | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index bc493b3312..69c819fef8 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -36,13 +36,13 @@ namespace v1 { */ const struct { - const test_setup_handler_t test_setup = test_setup_handler_t(1); + const test_setup_handler_t test_setup = test_setup_handler_t(1); const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); - const test_failure_handler_t test_failure = test_failure_handler_t(1); + const test_failure_handler_t test_failure = test_failure_handler_t(1); - const case_setup_handler_t case_setup = case_setup_handler_t(1); + const case_setup_handler_t case_setup = case_setup_handler_t(1); const case_teardown_handler_t case_teardown = case_teardown_handler_t(1); - const case_failure_handler_t case_failure = case_failure_handler_t(1); + const case_failure_handler_t case_failure = case_failure_handler_t(1); operator test_setup_handler_t() const { return test_setup; } operator test_teardown_handler_t() const { return test_teardown; } @@ -61,20 +61,20 @@ namespace v1 { */ const struct { - const case_handler_t handler = case_handler_t(NULL); - const case_control_handler_t control = case_control_handler_t(NULL); + const case_handler_t handler = case_handler_t(NULL); + const case_control_handler_t control = case_control_handler_t(NULL); const case_call_count_handler_t call_count = case_call_count_handler_t(NULL); - const test_setup_handler_t test_setup = test_setup_handler_t(1); - const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); - const test_failure_handler_t test_failure = test_failure_handler_t(1); + const test_setup_handler_t test_setup = test_setup_handler_t(NULL); + const test_teardown_handler_t test_teardown = test_teardown_handler_t(NULL); + const test_failure_handler_t test_failure = test_failure_handler_t(NULL); - const case_setup_handler_t case_setup = case_setup_handler_t(1); - const case_teardown_handler_t case_teardown = case_teardown_handler_t(1); - const case_failure_handler_t case_failure = case_failure_handler_t(1); + const case_setup_handler_t case_setup = case_setup_handler_t(NULL); + const case_teardown_handler_t case_teardown = case_teardown_handler_t(NULL); + const case_failure_handler_t case_failure = case_failure_handler_t(NULL); - operator case_handler_t() const { return handler; } - operator case_control_handler_t() const { return control; } + operator case_handler_t() const { return handler; } + operator case_control_handler_t() const { return control; } operator case_call_count_handler_t() const { return call_count; } operator test_setup_handler_t() const { return test_setup; } From 7f9f0d81ab176b7a27375e4ce9a7c80e4ae42d37 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Dec 2015 16:11:41 +0000 Subject: [PATCH 52/88] Allow case attribute modification in callback validation. --- "frameworks\\utest/source/harness.cpp" | 7 ++++--- "frameworks\\utest/utest/harness.h" | 13 +++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 2e259d3a42..f24c9c8811 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -94,7 +94,7 @@ bool Harness::run(const Specification& specification, std::size_t start_case) return true; } -void Harness::raise_failure(failure_t reason) +void Harness::raise_failure(const failure_t reason) { status_t fail_status = STATUS_ABORT; { @@ -172,7 +172,7 @@ void Harness::handle_timeout() } } -void Harness::validate_callback() +void Harness::validate_callback(const control_t control) { mbed::util::CriticalSectionLock lock; case_validation_count++; @@ -181,7 +181,8 @@ void Harness::validate_callback() { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; - case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); + control_t merged_control = case_control + control; + case_control.repeat = repeat_t(merged_control.repeat & ~REPEAT_ON_TIMEOUT); minar::Scheduler::postCallback(schedule_next_case); } } diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index 361cad2114..fa2ad9e102 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -62,12 +62,21 @@ namespace v1 { * You can only validate a callback once, calling this function when no callback is expected * has no side effects. * After callback validation, the next test case is scheduled. + * + * You may specify additional test case attributes with this callback. + * So for example, you may delay the decision to repeat an asynchronous test case until the callback + * needs to be validated. + * + * However, be aware, that only the repeat attributes can be modified and the usual arbitration rules apply. + * The modified case attributes are only valid until the case handler returns updated attributes. + * + * @param control the test case attribute to be added to the existing attributes. */ - static void validate_callback(); + static void validate_callback(const control_t control = control_t()); /// Raising a failure causes the failure to be counted and the failure handler to be called. /// Further action then depends on its return state. - static void raise_failure(failure_t reason); + static void raise_failure(const failure_t reason); protected: static void run_next_case(); From 5a052a523a98a07025befb17269ab37644c48c94 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 22 Dec 2015 18:08:20 +0000 Subject: [PATCH 53/88] Fixed premature validation attribute modification. --- "frameworks\\utest/source/harness.cpp" | 11 +++++++---- "frameworks\\utest/utest/types.h" | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index f24c9c8811..521e809e16 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -183,6 +183,7 @@ void Harness::validate_callback(const control_t control) case_timeout_handle = NULL; control_t merged_control = case_control + control; case_control.repeat = repeat_t(merged_control.repeat & ~REPEAT_ON_TIMEOUT); + case_control.timeout = TIMEOUT_NONE; minar::Scheduler::postCallback(schedule_next_case); } } @@ -210,14 +211,16 @@ void Harness::run_next_case() return; } + repeat_t setup_repeat; { mbed::util::CriticalSectionLock lock; case_validation_count = 0; case_timeout_occurred = false; + setup_repeat = case_control.repeat; + case_control = control_t(); } - if (case_control.repeat & REPEAT_SETUP_TEARDOWN) { - case_control = control_t(); + if (setup_repeat & REPEAT_SETUP_TEARDOWN) { if (handlers.case_setup && (handlers.case_setup(case_current, test_index_of_case) != STATUS_CONTINUE)) { raise_failure(FAILURE_SETUP); schedule_next_case(); @@ -230,9 +233,9 @@ void Harness::run_next_case() if (case_current->handler) { case_current->handler(); } else if (case_current->control_handler) { - case_control = case_current->control_handler(); + case_control = case_control + case_current->control_handler(); } else if (case_current->repeat_count_handler) { - case_control = case_current->repeat_count_handler(case_repeat_count); + case_control = case_control + case_current->repeat_count_handler(case_repeat_count); } case_repeat_count++; diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index a63d9c863a..d2be7688a0 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -293,6 +293,7 @@ namespace v1 { * @returns * You can return `STATUS_ABORT` to indicate that this failure is non-recoverable, which will call the case * teardown handler with reason. If a failure occurs during teardown, the teardown will not be called again. + * You may return `STATUS_IGNORE` which will cause the harness to ignore and not count the failure. */ typedef status_t (*case_failure_handler_t)(const Case *const source, const failure_t reason); From e68d00ded54d18b0ee4dd5a18d6811122b4154a7 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 7 Jan 2016 09:44:58 +0000 Subject: [PATCH 54/88] Add location to failure information. Rename `failure_t` to `failure_reason_t`. Add `location_t` with stringify function. Add new `failure_t` struct with location information. Adapt harness logic to keep track of location. Add a test failure handler that reports assertion failures on test setup and test teardown. --- .../source/default_handlers.cpp" | 57 ++++++++------ "frameworks\\utest/source/harness.cpp" | 44 +++++++---- "frameworks\\utest/source/types.cpp" | 74 ++++++++++++++----- "frameworks\\utest/source/unity_handler.cpp" | 4 +- "frameworks\\utest/utest/harness.h" | 2 +- "frameworks\\utest/utest/types.h" | 63 ++++++++++++---- 6 files changed, 170 insertions(+), 74 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 21d50149aa..72fbcd80f9 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -22,12 +22,13 @@ using namespace utest::v1; static status_t greentea_unknown_test_setup_handler(const size_t); -static void selftest_failure_handler(const failure_t reason); +static void selftest_failure_handler(const failure_t failure); +static void test_failure_handler(const failure_t failure); const handlers_t utest::v1::verbose_continue_handlers = { verbose_test_setup_handler, verbose_test_teardown_handler, - ignore_handler, + test_failure_handler, verbose_case_setup_handler, verbose_case_teardown_handler, verbose_case_failure_handler @@ -35,7 +36,7 @@ const handlers_t utest::v1::verbose_continue_handlers = { const handlers_t utest::v1::greentea_abort_handlers = { greentea_unknown_test_setup_handler, greentea_test_teardown_handler, - ignore_handler, + test_failure_handler, greentea_case_setup_handler, greentea_case_teardown_handler, greentea_case_failure_abort_handler @@ -43,7 +44,7 @@ const handlers_t utest::v1::greentea_abort_handlers = { const handlers_t utest::v1::greentea_continue_handlers = { greentea_unknown_test_setup_handler, greentea_test_teardown_handler, - ignore_handler, + test_failure_handler, greentea_case_setup_handler, greentea_case_teardown_handler, greentea_case_failure_continue_handler @@ -65,9 +66,19 @@ static status_t greentea_unknown_test_setup_handler(const size_t) { return STATUS_ABORT; } -static void selftest_failure_handler(const failure_t reason) { - if (reason == FAILURE_ASSERTION) { - printf(">>> failure with reason '%s (in selftest)'\n{{failure}}\n{{end}}\n", stringify(reason)); +static void selftest_failure_handler(const failure_t failure) { + if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN || failure.reason == REASON_ASSERTION) { + verbose_test_failure_handler(failure); + } + if (failure.reason == REASON_ASSERTION) { + printf("{{failure}}\n{{end}}\n"); + while(1) ; + } +} +static void test_failure_handler(const failure_t failure) { + if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { + verbose_test_failure_handler(failure); + printf("{{failure}}\n{{end}}\n"); while(1) ; } } @@ -82,17 +93,17 @@ status_t utest::v1::verbose_test_setup_handler(const size_t number_of_cases) void utest::v1::verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { printf("\n>>> Test cases: %u passed, %u failed", passed, failed); - if (failure == FAILURE_NONE) { + if (failure.reason == REASON_NONE) { printf("\n"); } else { - printf(" with reason '%s'\n", stringify(failure)); + printf(" with reason '%s'\n", stringify(failure.reason)); } if (failed) printf(">>> TESTS FAILED!\n"); } -void utest::v1::verbose_test_failure_handler(const failure_t reason) +void utest::v1::verbose_test_failure_handler(const failure_t failure) { - printf(">>> failure with reason '%s'\n", stringify(reason)); + printf(">>> failure with reason '%s' during '%s'\n", stringify(failure.reason), stringify(failure.location)); } // --- VERBOSE CASE HANDLERS --- @@ -105,21 +116,21 @@ status_t utest::v1::verbose_case_setup_handler(const Case *const source, const s status_t utest::v1::verbose_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) { printf(">>> '%s': %u passed, %u failed", source->get_description(), passed, failed); - if (failure == FAILURE_NONE) { + if (failure.reason == REASON_NONE) { printf("\n"); } else { - printf(" with reason '%s'\n", stringify(failure)); + printf(" with reason '%s'\n", stringify(failure.reason)); } return STATUS_CONTINUE; } -status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t reason) +status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, const failure_t failure) { - if (!(reason & FAILURE_ASSERTION)) { - verbose_test_failure_handler(reason); + if (!(failure.reason & REASON_ASSERTION)) { + verbose_test_failure_handler(failure); } - if (reason & FAILURE_TEARDOWN) return STATUS_ABORT; - if (reason & FAILURE_IGNORE) return STATUS_IGNORE; + if (failure.reason & (REASON_TEST_TEARDOWN | REASON_CASE_TEARDOWN)) return STATUS_ABORT; + if (failure.reason & REASON_IGNORE) return STATUS_IGNORE; return STATUS_CONTINUE; } @@ -133,7 +144,7 @@ status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { verbose_test_teardown_handler(passed, failed, failure); - if (failed || (failure && !(failure & FAILURE_IGNORE))) { + if (failed || (failure.reason && !(failure.reason & REASON_IGNORE))) { printf("{{failure}}\n"); } else { printf("{{success}}\n"); @@ -157,13 +168,13 @@ status_t utest::v1::greentea_case_teardown_handler(const Case *const source, con return verbose_case_teardown_handler(source, passed, failed, failure); } -status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t reason) +status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t failure) { - status_t status = verbose_case_failure_handler(source, reason); + status_t status = verbose_case_failure_handler(source, failure); return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; } -status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t reason) +status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t failure) { - return verbose_case_failure_handler(source, reason); + return verbose_case_failure_handler(source, failure); } diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 521e809e16..a41a980af0 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -46,6 +46,8 @@ namespace handlers_t defaults = default_handlers; handlers_t handlers = defaults; + + location_t location = LOCATION_UNKNOWN; } static void die() { @@ -82,10 +84,11 @@ bool Harness::run(const Specification& specification, std::size_t start_case) case_failed = 0; case_failed_before = 0; case_current = &test_cases[start_case]; + location = LOCATION_TEST_SETUP; if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { - if (handlers.test_failure) handlers.test_failure(FAILURE_SETUP); - if (handlers.test_teardown) handlers.test_teardown(0, 0, FAILURE_SETUP); + if (handlers.test_failure) handlers.test_failure(failure_t(REASON_TEST_SETUP, location)); + if (handlers.test_teardown) handlers.test_teardown(0, 0, failure_t(REASON_TEST_SETUP, location)); test_cases = NULL; return true; } @@ -94,14 +97,14 @@ bool Harness::run(const Specification& specification, std::size_t start_case) return true; } -void Harness::raise_failure(const failure_t reason) +void Harness::raise_failure(const failure_reason_t reason) { status_t fail_status = STATUS_ABORT; { mbed::util::CriticalSectionLock lock; - if (handlers.test_failure) handlers.test_failure(reason); - if (handlers.case_failure) fail_status = handlers.case_failure(case_current, reason); + if (handlers.test_failure) handlers.test_failure(failure_t(reason, location)); + if (handlers.case_failure) fail_status = handlers.case_failure(case_current, failure_t(reason, location)); if (!(fail_status & STATUS_IGNORE)) case_failed++; if ((fail_status & STATUS_ABORT) && case_timeout_handle) @@ -111,18 +114,22 @@ void Harness::raise_failure(const failure_t reason) } } - if (fail_status & STATUS_ABORT || reason & FAILURE_SETUP) { - if (handlers.case_teardown && !(reason & FAILURE_TEARDOWN)) { - status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, reason); + if (fail_status & STATUS_ABORT || reason & REASON_CASE_SETUP) { + if (handlers.case_teardown && location != LOCATION_CASE_TEARDOWN) { + location_t fail_loc(location); + location = LOCATION_CASE_TEARDOWN; + status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, failure_t(reason, fail_loc)); if (teardown_status != STATUS_CONTINUE) { - raise_failure(FAILURE_TEARDOWN); + raise_failure(REASON_CASE_TEARDOWN); } else handlers.case_teardown = NULL; } } if (fail_status & STATUS_ABORT) { test_failed++; - if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, reason); + failure_t fail(reason, location); + location = LOCATION_TEST_TEARDOWN; + if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, fail); die(); } } @@ -134,10 +141,11 @@ void Harness::schedule_next_case() } if (case_control.repeat & REPEAT_SETUP_TEARDOWN || !(case_control.repeat & (REPEAT_ON_TIMEOUT | REPEAT_ON_VALIDATE))) { + location = LOCATION_CASE_TEARDOWN; if (handlers.case_teardown && (handlers.case_teardown(case_current, case_passed, case_failed, - case_failed ? FAILURE_CASES : FAILURE_NONE) != STATUS_CONTINUE)) { - raise_failure(FAILURE_TEARDOWN); + case_failed ? failure_t(REASON_CASES, LOCATION_UNKNOWN) : failure_t(REASON_NONE)) != STATUS_CONTINUE)) { + raise_failure(REASON_CASE_TEARDOWN); } } @@ -167,7 +175,7 @@ void Harness::handle_timeout() } } if (case_timeout_occurred) { - raise_failure(failure_t(FAILURE_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? FAILURE_IGNORE : 0))); + raise_failure(failure_reason_t(REASON_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? REASON_IGNORE : 0))); minar::Scheduler::postCallback(schedule_next_case); } } @@ -206,7 +214,8 @@ void Harness::run_next_case() handlers.case_failure = defaults.get_handler(case_current->failure_handler); if (case_current->is_empty()) { - raise_failure(FAILURE_EMPTY_CASE); + location = LOCATION_UNKNOWN; + raise_failure(REASON_EMPTY_CASE); schedule_next_case(); return; } @@ -221,14 +230,16 @@ void Harness::run_next_case() } if (setup_repeat & REPEAT_SETUP_TEARDOWN) { + location = LOCATION_CASE_SETUP; if (handlers.case_setup && (handlers.case_setup(case_current, test_index_of_case) != STATUS_CONTINUE)) { - raise_failure(FAILURE_SETUP); + raise_failure(REASON_CASE_SETUP); schedule_next_case(); return; } } case_failed_before = case_failed; + location = LOCATION_CASE_HANDLER; if (case_current->handler) { case_current->handler(); @@ -258,7 +269,8 @@ void Harness::run_next_case() } } else if (handlers.test_teardown) { - handlers.test_teardown(test_passed, test_failed, test_failed ? FAILURE_CASES : FAILURE_NONE); + location = LOCATION_TEST_TEARDOWN; + handlers.test_teardown(test_passed, test_failed, test_failed ? failure_t(REASON_CASES, LOCATION_UNKNOWN) : failure_t(REASON_NONE)); test_cases = NULL; } } diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index 8ef482b5e6..3f8f692c58 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -18,40 +18,80 @@ #include "utest/types.h" -const char* utest::v1::stringify(utest::v1::failure_t failure) +const char* utest::v1::stringify(utest::v1::failure_reason_t reason) { const char *string; - switch(failure & ~FAILURE_IGNORE) + switch(reason & ~REASON_IGNORE) { - case FAILURE_NONE: + case REASON_NONE: string = "Ignored: No Failure"; break; - case FAILURE: - string = "Ignored: Unspecified Failure"; - break; - case FAILURE_CASES: + case REASON_CASES: string = "Ignored: Test Cases Failed"; break; - case FAILURE_EMPTY_CASE: + case REASON_EMPTY_CASE: string = "Ignored: Test Case is Empty"; break; - case FAILURE_SETUP: - string = "Ignored: Setup Failed"; - break; - case FAILURE_TEARDOWN: - string = "Ignored: Teardown Failed"; - break; - case FAILURE_TIMEOUT: + case REASON_TIMEOUT: string = "Ignored: Timed Out"; break; - case FAILURE_ASSERTION: + case REASON_ASSERTION: string = "Ignored: Assertion Failed"; break; + case REASON_TEST_SETUP: + string = "Ignored: Test Setup Failed"; + break; + case REASON_TEST_TEARDOWN: + string = "Ignored: Test Teardown Failed"; + break; + case REASON_CASE_SETUP: + string = "Ignored: Case Setup Failed"; + break; + case REASON_CASE_HANDLER: + string = "Ignored: Case Handler Failed"; + break; + case REASON_CASE_TEARDOWN: + string = "Ignored: Case Teardown Failed"; + break; default: + case REASON_UNKNOWN: string = "Ignored: Unknown Failure"; break; } - if (!(failure & FAILURE_IGNORE)) string += 9; + if (!(reason & REASON_IGNORE)) string += 9; + return string; +} + +const char* utest::v1::stringify(utest::v1::failure_t failure) +{ + return stringify(failure.reason); +} + +const char* utest::v1::stringify(utest::v1::location_t location) +{ + const char *string; + switch(location) + { + case LOCATION_TEST_SETUP: + string = "Test Setup Handler"; + break; + case LOCATION_TEST_TEARDOWN: + string = "Test Teardown Handler"; + break; + case LOCATION_CASE_SETUP: + string = "Case Setup Handler"; + break; + case LOCATION_CASE_HANDLER: + string = "Case Handler"; + break; + case LOCATION_CASE_TEARDOWN: + string = "Case Teardown Handler"; + break; + default: + case LOCATION_UNKNOWN: + string = "Unknown Location"; + break; + } return string; } diff --git "a/frameworks\\utest/source/unity_handler.cpp" "b/frameworks\\utest/source/unity_handler.cpp" index b40978c75d..bc595233aa 100644 --- "a/frameworks\\utest/source/unity_handler.cpp" +++ "b/frameworks\\utest/source/unity_handler.cpp" @@ -21,11 +21,11 @@ extern "C" void utest_unity_assert_failure() { - utest::v1::Harness::raise_failure(utest::v1::FAILURE_ASSERTION); + utest::v1::Harness::raise_failure(utest::v1::REASON_ASSERTION); } extern "C" void utest_unity_ignore_failure() { - utest::v1::Harness::raise_failure(utest::v1::failure_t(utest::v1::FAILURE_ASSERTION | utest::v1::FAILURE_IGNORE)); + utest::v1::Harness::raise_failure(utest::v1::failure_reason_t(utest::v1::REASON_ASSERTION | utest::v1::REASON_IGNORE)); } diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index fa2ad9e102..726f146497 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -76,7 +76,7 @@ namespace v1 { /// Raising a failure causes the failure to be counted and the failure handler to be called. /// Further action then depends on its return state. - static void raise_failure(const failure_t reason); + static void raise_failure(const failure_reason_t reason); protected: static void run_next_case(); diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index d2be7688a0..c936666bec 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -50,16 +50,45 @@ namespace v1 { STATUS_ABORT = 2 ///< stops testing }; - enum failure_t { - FAILURE_NONE = 0, ///< No failure occurred - FAILURE = 1, ///< An unknown failure occurred - FAILURE_CASES = 2, ///< A failure occurred in at least one test case - FAILURE_EMPTY_CASE = 4, ///< The test case contains only empty handlers - FAILURE_SETUP = 8, ///< A failure occurred on setup - FAILURE_TEARDOWN = 16, ///< A failure occurred on teardown - FAILURE_TIMEOUT = 32, ///< An expected asynchronous call timed out - FAILURE_ASSERTION = 64, ///< An assertion failed - FAILURE_IGNORE = 0x8000 ///< A failure occurred, but may be ignored + enum failure_reason_t { + REASON_NONE = 0, ///< No failure occurred + + REASON_UNKNOWN = (1 << 0), ///< An unknown failure occurred + REASON_CASES = (1 << 1), ///< A failure occurred in at least one test case + REASON_EMPTY_CASE = (1 << 2), ///< The test case contains only empty handlers + REASON_TIMEOUT = (1 << 3), ///< An expected asynchronous call timed out + REASON_ASSERTION = (1 << 4), ///< An assertion failed + + REASON_TEST_SETUP = (1 << 5), ///< Test setup failed + REASON_TEST_TEARDOWN = (1 << 6), ///< Test teardown failed + REASON_CASE_SETUP = (1 << 7), ///< Case setup failed + REASON_CASE_HANDLER = (1 << 8), ///< Case handler failed + REASON_CASE_TEARDOWN = (1 << 9), ///< Case teardown failed + + REASON_IGNORE = 0x8000 ///< The failure may be ignored + }; + + enum location_t { + LOCATION_NONE = 0, ///< No location information + LOCATION_TEST_SETUP, ///< A failure occurred in the test setup + LOCATION_TEST_TEARDOWN, ///< A failure occurred in the test teardown + LOCATION_CASE_SETUP, ///< A failure occurred in the case setup + LOCATION_CASE_HANDLER, ///< A failure occurred in the case handler + LOCATION_CASE_TEARDOWN, ///< A failure occurred in the case teardown + LOCATION_UNKNOWN ///< A failure occurred in an unknown location + }; + + struct failure_t { + failure_t(failure_reason_t reason) : reason(reason) {} + failure_t(location_t location) : location(location) {} + failure_t(failure_reason_t reason, location_t location) : reason(reason), location(location) {} + + failure_t ignored() const { + return failure_t(failure_reason_t(reason | REASON_IGNORE), location); + } + + failure_reason_t reason = REASON_NONE; + location_t location = LOCATION_NONE; }; enum { @@ -68,9 +97,13 @@ namespace v1 { TIMEOUT_FOREVER = uint32_t(-3) ///< Never time out }; + /// Stringifies a failure reason for understandable error messages. + const char* stringify(failure_reason_t reason); /// Stringifies a failure for understandable error messages. const char* stringify(failure_t failure); - /// Stringifies a status for understandable status messages. + /// Stringifies a location. + const char* stringify(location_t location); + /// Stringifies a status. const char* stringify(status_t status); /** Control class for specifying test case attributes @@ -194,7 +227,7 @@ namespace v1 { * * @returns * You can return `STATUS_ABORT` if you initialization failed and the test teardown handler will - * then be called with the `FAILURE_SETUP`. + * then be called with the `REASON_SETUP`. */ typedef status_t (*test_setup_handler_t)(const size_t number_of_cases); @@ -203,7 +236,7 @@ namespace v1 { * This handler is called after execution of all test case or if test execution is aborted. * You can use this handler to de-initialize your test environment and output test statistics. * The failure argument contains the immediate reason why this handler is called. - * If the test completed normally without failures, this will contain `FAILURE_NONE`. + * If the test completed normally without failures, this will contain `REASON_NONE`. * * After execution of this handler, the test harness will stop execution. * @@ -232,7 +265,7 @@ namespace v1 { * * @returns * You can return `STATUS_ABORT` to indicate that your setup failed, which will call the case - * failure handler with `FAILURE_SETUP` and then the case teardown handler with `FAILURE_SETUP`. + * failure handler with `REASON_SETUP` and then the case teardown handler with `REASON_SETUP`. * This gives the teardown handler a chance to clean up a failed setup. */ typedef status_t (*case_setup_handler_t)(const Case *const source, const size_t index_of_case); @@ -279,7 +312,7 @@ namespace v1 { * * @returns * You can return `STATUS_ABORT` to indicate that your teardown failed, which will call the case - * failure handler with `FAILURE_TEARDOWN`. + * failure handler with `REASON_TEARDOWN`. */ typedef status_t (*case_teardown_handler_t)(const Case *const source, const size_t passed, const size_t failed, const failure_t reason); From 3aaa6c903b4ba3bbb0b5ceed4de52188beaff7e8 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 7 Jan 2016 10:51:09 +0000 Subject: [PATCH 55/88] Update documentation and changelog. --- "frameworks\\utest/utest/types.h" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index c936666bec..6eb05c3816 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -78,11 +78,13 @@ namespace v1 { LOCATION_UNKNOWN ///< A failure occurred in an unknown location }; + /// Contains the reason and location of the failure. struct failure_t { failure_t(failure_reason_t reason) : reason(reason) {} failure_t(location_t location) : location(location) {} failure_t(failure_reason_t reason, location_t location) : reason(reason), location(location) {} + /// @returns a copy of the failure with the reason ignored. failure_t ignored() const { return failure_t(failure_reason_t(reason | REASON_IGNORE), location); } From 110b13e8b5af4e386068fe9d574049bd5fe81784 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 7 Jan 2016 11:08:37 +0000 Subject: [PATCH 56/88] Properly deprecate `FAILURE_` enumerations. --- "frameworks\\utest/utest/types.h" | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 6eb05c3816..4fd68e5152 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -93,6 +93,7 @@ namespace v1 { location_t location = LOCATION_NONE; }; + enum { TIMEOUT_NONE = uint32_t(-1), ///< Do not use a timeout TIMEOUT_UNDECLR = uint32_t(-2), ///< Timeout not explicitly specified, defaults to NONE @@ -213,11 +214,6 @@ namespace v1 { /// repeats only the test case handler without calling teardown and setup handlers inline control_t CaseRepeatHandlerOnTimeout(uint32_t ms) { return control_t(REPEAT_HANDLER_ON_TIMEOUT, ms); } - __deprecated_message("Use CaseRepeatAll instead.") - const control_t CaseRepeat = CaseRepeatAll; - __deprecated_message("Use CaseRepeatHandler instead.") - const control_t CaseRepeatHandlerOnly = CaseRepeatHandler; - class Case; // forward declaration /** Test setup handler. @@ -332,6 +328,22 @@ namespace v1 { */ typedef status_t (*case_failure_handler_t)(const Case *const source, const failure_t reason); + + // deprecations + __deprecated_message("Use CaseRepeatAll instead.") const control_t CaseRepeat = CaseRepeatAll; + __deprecated_message("Use CaseRepeatHandler instead.") const control_t CaseRepeatHandlerOnly = CaseRepeatHandler; + + __deprecated_message("Use REASON_NONE instead.") const failure_reason_t FAILURE_NONE = REASON_NONE; + __deprecated_message("Use REASON_UNKNOWN instead.") const failure_reason_t FAILURE_UNKNOWN = REASON_UNKNOWN; + __deprecated_message("Use REASON_CASES instead.") const failure_reason_t FAILURE_CASES = REASON_CASES; + __deprecated_message("Use REASON_EMPTY_CASE instead.") const failure_reason_t FAILURE_EMPTY_CASE = REASON_EMPTY_CASE; + __deprecated_message("Use REASON_TIMEOUT instead.") const failure_reason_t FAILURE_TIMEOUT = REASON_TIMEOUT; + __deprecated_message("Use REASON_ASSERTION instead.") const failure_reason_t FAILURE_ASSERTION = REASON_ASSERTION; + __deprecated_message("Use REASON_CASE_SETUP instead.") const failure_reason_t FAILURE_SETUP = REASON_CASE_SETUP; + __deprecated_message("Use REASON_CASE_TEARDOWN instead.") const failure_reason_t FAILURE_TEARDOWN = REASON_CASE_TEARDOWN; + __deprecated_message("Use REASON_IGNORE instead.") const failure_reason_t FAILURE_IGNORE = REASON_IGNORE; + + } // namespace v1 } // namespace utest From 4db0ec48c3e137c60b715246bb0880c52204ce6a Mon Sep 17 00:00:00 2001 From: Martin Kojtal Date: Mon, 25 Jan 2016 14:24:10 +0000 Subject: [PATCH 57/88] Case - add control handler check to is_empty() --- "frameworks\\utest/source/case.cpp" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/case.cpp" "b/frameworks\\utest/source/case.cpp" index eb377679d3..57395abd4a 100644 --- "a/frameworks\\utest/source/case.cpp" +++ "b/frameworks\\utest/source/case.cpp" @@ -147,5 +147,5 @@ Case::get_description() const { bool Case::is_empty() const { - return !(handler || repeat_count_handler || setup_handler || teardown_handler); + return !(handler || control_handler || repeat_count_handler || setup_handler || teardown_handler); } From 01040bb9bf6dc5fc83d84a14daed034bd0a67974 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 29 Feb 2016 15:21:17 +0100 Subject: [PATCH 58/88] Do not report failure with uninitialized harness. Calling `raise_failure` before harness is initialized can print unintentional failure strings. This disallows using Unity macros outside of the utest harness. --- "frameworks\\utest/source/harness.cpp" | 4 ++++ 1 file changed, 4 insertions(+) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index a41a980af0..fe5daa23e7 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -99,6 +99,10 @@ bool Harness::run(const Specification& specification, std::size_t start_case) void Harness::raise_failure(const failure_reason_t reason) { + // ignore a failure, if the Harness has not been initialized. + // this allows using unity assertion macros without setting up utest. + if (test_cases == NULL) return; + status_t fail_status = STATUS_ABORT; { mbed::util::CriticalSectionLock lock; From 2fc2c1fbccb6f19324c84c97eeeb2c955ec01dab Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 10 Feb 2016 13:50:33 +0000 Subject: [PATCH 59/88] Modify module configuration --- .../source/greentea_handlers.cpp" | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 "frameworks\\utest/source/greentea_handlers.cpp" diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" new file mode 100644 index 0000000000..194e257ea3 --- /dev/null +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -0,0 +1,79 @@ +/**************************************************************************** + * Copyright (c) 2015, 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 "utest/default_handlers.h" +#include "utest/case.h" +#include "mbed-drivers/test_env.h" + +using namespace utest::v1; + +/** + +extern const char* TEST_ENV_TESTCASE_COUNT; +extern const char* TEST_ENV_TESTCASE_START; +extern const char* TEST_ENV_TESTCASE_FINISH; + +void greentea_send_kv(const char *, const char *); +void greentea_send_kv(const char *, const int); +int greentea_parse_kv(char *, char *, const int, const int); + + + */ + +// --- GREENTEA HANDLERS --- +status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) +{ + greentea_send_kv(TEST_ENV_TESTCASE_COUNT, number_of_cases); + return verbose_test_setup_handler(number_of_cases); +} + +void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) +{ + verbose_test_teardown_handler(passed, failed, failure); + int result = !(failed || (failure.reason && !(failure.reason & REASON_IGNORE))); + GREENTEA_TESTSUITE_RESULT(result); +} + +void utest::v1::greentea_test_failure_handler(const failure_t) +{ + // does nothing here +} + +// --- GREENTEA CASE HANDLERS --- +status_t utest::v1::greentea_case_setup_handler(const Case *const source, const size_t index_of_case) +{ + greentea_send_kv(TEST_ENV_TESTCASE_START, source->get_description()); + return verbose_case_setup_handler(source, index_of_case); +} + +status_t utest::v1::greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +{ + greentea_send_kv(TEST_ENV_TESTCASE_FINISH, source->get_description(), passed, failed); + return verbose_case_teardown_handler(source, passed, failed, failure); +} + +status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t failure) +{ + status_t status = verbose_case_failure_handler(source, failure); + return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; +} + +status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t failure) +{ + return verbose_case_failure_handler(source, failure); +} From 982a06cf33fa254d17b03b2f626b16c8a193ea20 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 10 Feb 2016 13:51:18 +0000 Subject: [PATCH 60/88] Port tests to Async API feature --- .../source/default_handlers.cpp" | 45 ------------------- 1 file changed, 45 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 72fbcd80f9..62d9540e2e 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -133,48 +133,3 @@ status_t utest::v1::verbose_case_failure_handler(const Case *const /*source*/, c if (failure.reason & REASON_IGNORE) return STATUS_IGNORE; return STATUS_CONTINUE; } - - -// --- GREENTEA HANDLERS --- -status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) -{ - return verbose_test_setup_handler(number_of_cases); -} - -void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) -{ - verbose_test_teardown_handler(passed, failed, failure); - if (failed || (failure.reason && !(failure.reason & REASON_IGNORE))) { - printf("{{failure}}\n"); - } else { - printf("{{success}}\n"); - } - printf("{{end}}\n"); -} - -void utest::v1::greentea_test_failure_handler(const failure_t) -{ - // does nothing here -} - -// --- GREENTEA CASE HANDLERS --- -status_t utest::v1::greentea_case_setup_handler(const Case *const source, const size_t index_of_case) -{ - return verbose_case_setup_handler(source, index_of_case); -} - -status_t utest::v1::greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) -{ - return verbose_case_teardown_handler(source, passed, failed, failure); -} - -status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t failure) -{ - status_t status = verbose_case_failure_handler(source, failure); - return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; -} - -status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t failure) -{ - return verbose_case_failure_handler(source, failure); -} From 93efc09f4cddc6554ba762710d22337430d53bbd Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 10 Feb 2016 16:09:30 +0000 Subject: [PATCH 61/88] Replace verbose_case_teardown_handler with greentea counterparts --- .../source/greentea_handlers.cpp" | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 194e257ea3..407322f91e 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -22,18 +22,6 @@ using namespace utest::v1; -/** - -extern const char* TEST_ENV_TESTCASE_COUNT; -extern const char* TEST_ENV_TESTCASE_START; -extern const char* TEST_ENV_TESTCASE_FINISH; - -void greentea_send_kv(const char *, const char *); -void greentea_send_kv(const char *, const int); -int greentea_parse_kv(char *, char *, const int, const int); - - - */ // --- GREENTEA HANDLERS --- status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) @@ -44,14 +32,15 @@ status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { + greentea_send_kv(TEST_ENV_TESTCASE_SUMMARY, passed, failed); verbose_test_teardown_handler(passed, failed, failure); int result = !(failed || (failure.reason && !(failure.reason & REASON_IGNORE))); GREENTEA_TESTSUITE_RESULT(result); } -void utest::v1::greentea_test_failure_handler(const failure_t) +void utest::v1::greentea_test_failure_handler(const failure_t failure) { - // does nothing here + verbose_test_failure_handler(failure); } // --- GREENTEA CASE HANDLERS --- From 59fc24ccb2af07cc7502099c835861ad9ee59b39 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 11 Feb 2016 10:18:52 +0000 Subject: [PATCH 62/88] Refactor failure_handler(s) --- .../source/default_handlers.cpp" | 36 +----------- .../source/greentea_handlers.cpp" | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+), 33 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index 62d9540e2e..ec40101939 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -16,12 +16,11 @@ **************************************************************************** */ - #include "utest/default_handlers.h" - #include "utest/case.h" +#include "utest/default_handlers.h" +#include "utest/case.h" using namespace utest::v1; -static status_t greentea_unknown_test_setup_handler(const size_t); static void selftest_failure_handler(const failure_t failure); static void test_failure_handler(const failure_t failure); @@ -33,39 +32,9 @@ const handlers_t utest::v1::verbose_continue_handlers = { verbose_case_teardown_handler, verbose_case_failure_handler }; -const handlers_t utest::v1::greentea_abort_handlers = { - greentea_unknown_test_setup_handler, - greentea_test_teardown_handler, - test_failure_handler, - greentea_case_setup_handler, - greentea_case_teardown_handler, - greentea_case_failure_abort_handler -}; -const handlers_t utest::v1::greentea_continue_handlers = { - greentea_unknown_test_setup_handler, - greentea_test_teardown_handler, - test_failure_handler, - greentea_case_setup_handler, - greentea_case_teardown_handler, - greentea_case_failure_continue_handler -}; -const handlers_t utest::v1::selftest_handlers = { - greentea_unknown_test_setup_handler, - greentea_test_teardown_handler, - selftest_failure_handler, - greentea_case_setup_handler, - greentea_case_teardown_handler, - greentea_case_failure_continue_handler -}; // --- SPECIAL HANDLERS --- -static status_t greentea_unknown_test_setup_handler(const size_t) { - printf(">>> I do not know how to tell greentea that the test started, since\n"); - printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); - - return STATUS_ABORT; -} static void selftest_failure_handler(const failure_t failure) { if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN || failure.reason == REASON_ASSERTION) { verbose_test_failure_handler(failure); @@ -75,6 +44,7 @@ static void selftest_failure_handler(const failure_t failure) { while(1) ; } } + static void test_failure_handler(const failure_t failure) { if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { verbose_test_failure_handler(failure); diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 407322f91e..3dbd2001c1 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -22,6 +22,64 @@ using namespace utest::v1; +static status_t greentea_unknown_test_setup_handler(const size_t); +static void greentea_selftest_failure_handler(const failure_t); +static void greentea_test_failure_handler(const failure_t); + + +const handlers_t utest::v1::greentea_abort_handlers = { + greentea_unknown_test_setup_handler, + greentea_test_teardown_handler, + greentea_test_failure_handler, + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_abort_handler +}; + +const handlers_t utest::v1::greentea_continue_handlers = { + greentea_unknown_test_setup_handler, + greentea_test_teardown_handler, + greentea_test_failure_handler, + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_continue_handler +}; + +const handlers_t utest::v1::selftest_handlers = { + greentea_unknown_test_setup_handler, + greentea_test_teardown_handler, + greentea_selftest_failure_handler, + greentea_case_setup_handler, + greentea_case_teardown_handler, + greentea_case_failure_continue_handler +}; + + +// --- SPECIAL HANDLERS --- +static status_t greentea_unknown_test_setup_handler(const size_t) { + printf(">>> I do not know how to tell greentea that the test started, since\n"); + printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); + + return STATUS_ABORT; +} + +static void greentea_selftest_failure_handler(const failure_t failure) { + if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN || failure.reason == REASON_ASSERTION) { + verbose_test_failure_handler(failure); + } + if (failure.reason == REASON_ASSERTION) { + GREENTEA_TESTSUITE_RESULT(false); + while(1) ; + } +} + +static void greentea_test_failure_handler(const failure_t failure) { + if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { + verbose_test_failure_handler(failure); + GREENTEA_TESTSUITE_RESULT(false); + while(1) ; + } +} // --- GREENTEA HANDLERS --- status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) From 5369d33ae2b29798d63c4d44b4a4efbb3b0f99cc Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 11 Feb 2016 19:18:46 +0000 Subject: [PATCH 63/88] Expect FAIL test cases. Merge and squash changes from Niklas From @niklas-arm: * Report success to greentea for expected failures. * Use the greentea setup handlers for correct reporting. * Remove GREENTEA_START() from all tests. * Reorder greentea_send_kv to be more readable. --- "frameworks\\utest/source/greentea_handlers.cpp" | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 3dbd2001c1..3424ae75ea 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -90,8 +90,8 @@ status_t utest::v1::greentea_test_setup_handler(const size_t number_of_cases) void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure) { - greentea_send_kv(TEST_ENV_TESTCASE_SUMMARY, passed, failed); verbose_test_teardown_handler(passed, failed, failure); + greentea_send_kv(TEST_ENV_TESTCASE_SUMMARY, passed, failed); int result = !(failed || (failure.reason && !(failure.reason & REASON_IGNORE))); GREENTEA_TESTSUITE_RESULT(result); } @@ -104,8 +104,9 @@ void utest::v1::greentea_test_failure_handler(const failure_t failure) // --- GREENTEA CASE HANDLERS --- status_t utest::v1::greentea_case_setup_handler(const Case *const source, const size_t index_of_case) { + status_t status = verbose_case_setup_handler(source, index_of_case); greentea_send_kv(TEST_ENV_TESTCASE_START, source->get_description()); - return verbose_case_setup_handler(source, index_of_case); + return status; } status_t utest::v1::greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) From b1af815f49e0f24e326882cca22e1f8670c2d1bc Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Fri, 12 Feb 2016 00:52:55 +0000 Subject: [PATCH 64/88] Add support for greentea-client --- "frameworks\\utest/source/greentea_handlers.cpp" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 3424ae75ea..7881fc9f49 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -18,7 +18,7 @@ #include "utest/default_handlers.h" #include "utest/case.h" -#include "mbed-drivers/test_env.h" +#include "greentea-client/test_env.h" using namespace utest::v1; From ad8eaadb8ffc0abe86f95a9ee69cfa1cc8257fca Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 30 Mar 2016 16:25:08 +0100 Subject: [PATCH 65/88] exit(result) after harness finished. --- "frameworks\\utest/source/harness.cpp" | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index fe5daa23e7..48bb12c750 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -16,9 +16,10 @@ **************************************************************************** */ - #include "utest/harness.h" - #include "minar/minar.h" - #include "core-util/CriticalSectionLock.h" +#include "utest/harness.h" +#include "minar/minar.h" +#include "core-util/CriticalSectionLock.h" +#include using namespace utest::v1; @@ -276,5 +277,8 @@ void Harness::run_next_case() location = LOCATION_TEST_TEARDOWN; handlers.test_teardown(test_passed, test_failed, test_failed ? failure_t(REASON_CASES, LOCATION_UNKNOWN) : failure_t(REASON_NONE)); test_cases = NULL; + exit(test_failed); + } else { + exit(test_failed); } } From 31a5cf9c34f271e00ac278ee00ec013a1acd46c8 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 31 Mar 2016 10:35:03 +0100 Subject: [PATCH 66/88] Also `exit(1)` on test failure. --- "frameworks\\utest/source/harness.cpp" | 2 ++ 1 file changed, 2 insertions(+) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 48bb12c750..85fe5a9f82 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -91,6 +91,7 @@ bool Harness::run(const Specification& specification, std::size_t start_case) if (handlers.test_failure) handlers.test_failure(failure_t(REASON_TEST_SETUP, location)); if (handlers.test_teardown) handlers.test_teardown(0, 0, failure_t(REASON_TEST_SETUP, location)); test_cases = NULL; + exit(1); return true; } @@ -135,6 +136,7 @@ void Harness::raise_failure(const failure_reason_t reason) failure_t fail(reason, location); location = LOCATION_TEST_TEARDOWN; if (handlers.test_teardown) handlers.test_teardown(test_passed, test_failed, fail); + exit(test_failed); die(); } } From 2ee605a4ec1a818f77c1147ebeadba8f648f3a7b Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 11 Feb 2016 22:27:55 +0000 Subject: [PATCH 67/88] Update documentation of greentea default handlers. --- "frameworks\\utest/utest/default_handlers.h" | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 69c819fef8..3ef00ce584 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -149,8 +149,8 @@ namespace v1 { status_t verbose_test_setup_handler (const size_t number_of_cases); /// Prints the number of tests that passed and failed with a reason if provided. void verbose_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); - /// Prints the failure. - void verbose_test_failure_handler(const failure_t failure); + /// Prints the failure for `REASON_TEST_SETUP` and `REASON_TEST_TEARDOWN` and then dies. + void verbose_test_failure_handler (const failure_t failure); /// Prints the index and description of the case being run and continues. status_t verbose_case_setup_handler (const Case *const source, const size_t index_of_case); @@ -162,19 +162,19 @@ namespace v1 { /// Prints a helpful error message and aborts. /// This function **NEEDS** to be overridden by the user when using greentea. status_t greentea_test_setup_handler (const size_t number_of_cases); - /// Calls `verbose_test_teardown_handler` and then prints the greentea failure and success and end strings. + /// Reports the test results to greentea. void greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); - /// Does nothing. Use this for forwards compatibility. - void greentea_test_failure_handler(const failure_t failure); + /// Reports the failure for `REASON_TEST_SETUP` and `REASON_TEST_TEARDOWN` to greentea and then dies. + void greentea_test_failure_handler (const failure_t failure); - /// Forwards to `verbose_case_setup_handler`. Use this for forwards compatibility. + /// Registers the test case setup with greentea. status_t greentea_case_setup_handler (const Case *const source, const size_t index_of_case); - /// Forwards to `verbose_case_teardown_handler`. Use this for forwards compatibility. + /// Registers the test case teardown with greentea. status_t greentea_case_teardown_handler(const Case *const source, const size_t passed, const size_t failed, const failure_t failure); - /// Calls `verbose_case_failure_handler` but then aborts. - status_t greentea_case_failure_abort_handler (const Case *const source, const failure_t reason); - /// Forwards to `verbose_case_failure_handler`. Use this for forwards compatibility. - status_t greentea_case_failure_continue_handler (const Case *const source, const failure_t reason); + /// Reports the failure to greentea and then aborts. + status_t greentea_case_failure_abort_handler (const Case *const source, const failure_t reason); + /// Reports the failure to greentea and then continues. + status_t greentea_case_failure_continue_handler(const Case *const source, const failure_t reason); /// The verbose default handlers that always continue on failure extern const handlers_t verbose_continue_handlers; From 014b3fef1f8fda1651c0094c27af07ec070c2cc5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 11 Feb 2016 22:45:30 +0000 Subject: [PATCH 68/88] Use negative numbers for `status_t`. --- "frameworks\\utest/source/greentea_handlers.cpp" | 2 +- "frameworks\\utest/source/harness.cpp" | 8 ++++---- "frameworks\\utest/utest/types.h" | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 7881fc9f49..747642f62b 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -118,7 +118,7 @@ status_t utest::v1::greentea_case_teardown_handler(const Case *const source, con status_t utest::v1::greentea_case_failure_abort_handler(const Case *const source, const failure_t failure) { status_t status = verbose_case_failure_handler(source, failure); - return (status & STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; + return (status == STATUS_IGNORE) ? STATUS_IGNORE : STATUS_ABORT; } status_t utest::v1::greentea_case_failure_continue_handler(const Case *const source, const failure_t failure) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 85fe5a9f82..d621f1bcf7 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -111,16 +111,16 @@ void Harness::raise_failure(const failure_reason_t reason) if (handlers.test_failure) handlers.test_failure(failure_t(reason, location)); if (handlers.case_failure) fail_status = handlers.case_failure(case_current, failure_t(reason, location)); - if (!(fail_status & STATUS_IGNORE)) case_failed++; + if (fail_status != STATUS_IGNORE) case_failed++; - if ((fail_status & STATUS_ABORT) && case_timeout_handle) + if ((fail_status == STATUS_ABORT) && case_timeout_handle) { minar::Scheduler::cancelCallback(case_timeout_handle); case_timeout_handle = NULL; } } - if (fail_status & STATUS_ABORT || reason & REASON_CASE_SETUP) { + if (fail_status == STATUS_ABORT || reason & REASON_CASE_SETUP) { if (handlers.case_teardown && location != LOCATION_CASE_TEARDOWN) { location_t fail_loc(location); location = LOCATION_CASE_TEARDOWN; @@ -131,7 +131,7 @@ void Harness::raise_failure(const failure_reason_t reason) else handlers.case_teardown = NULL; } } - if (fail_status & STATUS_ABORT) { + if (fail_status == STATUS_ABORT) { test_failed++; failure_t fail(reason, location); location = LOCATION_TEST_TEARDOWN; diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 4fd68e5152..127f9a739d 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -45,9 +45,9 @@ namespace v1 { }; enum status_t { - STATUS_CONTINUE = 0, ///< continues testing - STATUS_IGNORE = 1, ///< ignores failure and continues testing - STATUS_ABORT = 2 ///< stops testing + STATUS_CONTINUE = -1, ///< continues testing + STATUS_IGNORE = -2, ///< ignores failure and continues testing + STATUS_ABORT = -3 ///< stops testing }; enum failure_reason_t { From 50917538ebeac9c3e05283511288fd08246b1478 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 11 Feb 2016 22:48:40 +0000 Subject: [PATCH 69/88] Add `REASON_CASE_INDEX` failure reason. --- "frameworks\\utest/source/types.cpp" | 3 +++ "frameworks\\utest/utest/types.h" | 2 ++ 2 files changed, 5 insertions(+) diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index 3f8f692c58..f9bed9849f 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -53,6 +53,9 @@ const char* utest::v1::stringify(utest::v1::failure_reason_t reason) case REASON_CASE_TEARDOWN: string = "Ignored: Case Teardown Failed"; break; + case REASON_CASE_INDEX: + string = "Ignored: Case Index Invalid"; + break; default: case REASON_UNKNOWN: string = "Ignored: Unknown Failure"; diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 127f9a739d..8d49176827 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -65,6 +65,8 @@ namespace v1 { REASON_CASE_HANDLER = (1 << 8), ///< Case handler failed REASON_CASE_TEARDOWN = (1 << 9), ///< Case teardown failed + REASON_CASE_INDEX = (1 << 10), ///< Case index out-of-range + REASON_IGNORE = 0x8000 ///< The failure may be ignored }; From 6b692dd5fa2ed6a4415e3ccc6635246a6b24c9fd Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 11 Feb 2016 22:50:10 +0000 Subject: [PATCH 70/88] Use return value of test setup handler to choose start case. --- "frameworks\\utest/source/harness.cpp" | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index d621f1bcf7..4c733fca61 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -60,12 +60,8 @@ bool Harness::run(const Specification& specification) return run(specification, 0); } -bool Harness::run(const Specification& specification, std::size_t start_case) +bool Harness::run(const Specification& specification, std::size_t) { - // ignore any invalid start index - if (start_case >= specification.length) - return false; - // check if a specification is currently running if (is_busy()) return false; @@ -84,17 +80,28 @@ bool Harness::run(const Specification& specification, std::size_t start_case) case_passed = 0; case_failed = 0; case_failed_before = 0; - case_current = &test_cases[start_case]; - location = LOCATION_TEST_SETUP; - if (handlers.test_setup && (handlers.test_setup(test_length) != STATUS_CONTINUE)) { - if (handlers.test_failure) handlers.test_failure(failure_t(REASON_TEST_SETUP, location)); - if (handlers.test_teardown) handlers.test_teardown(0, 0, failure_t(REASON_TEST_SETUP, location)); + location = LOCATION_TEST_SETUP; + int setup_status = 0; + failure_t failure(REASON_NONE, location); + + if (handlers.test_setup) { + setup_status = handlers.test_setup(test_length); + if (setup_status == STATUS_CONTINUE) setup_status = 0; + else if (setup_status < STATUS_CONTINUE) failure.reason = REASON_TEST_SETUP; + else if (setup_status > signed(test_length)) failure.reason = REASON_CASE_INDEX; + } + + if (failure.reason != REASON_NONE) { + if (handlers.test_failure) handlers.test_failure(failure); + if (handlers.test_teardown) handlers.test_teardown(0, 0, failure); test_cases = NULL; exit(1); return true; } + case_current = &test_cases[setup_status]; + minar::Scheduler::postCallback(run_next_case); return true; } From 2e71820fa958be28d7528162c118e9457dbe5084 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Fri, 18 Mar 2016 17:34:34 +0000 Subject: [PATCH 71/88] Cleanup confusing default handler namings. --- .../source/default_handlers.cpp" | 11 --------- .../source/greentea_handlers.cpp" | 24 +++++++++---------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git "a/frameworks\\utest/source/default_handlers.cpp" "b/frameworks\\utest/source/default_handlers.cpp" index ec40101939..44c0ffae42 100644 --- "a/frameworks\\utest/source/default_handlers.cpp" +++ "b/frameworks\\utest/source/default_handlers.cpp" @@ -21,7 +21,6 @@ using namespace utest::v1; -static void selftest_failure_handler(const failure_t failure); static void test_failure_handler(const failure_t failure); const handlers_t utest::v1::verbose_continue_handlers = { @@ -35,16 +34,6 @@ const handlers_t utest::v1::verbose_continue_handlers = { // --- SPECIAL HANDLERS --- -static void selftest_failure_handler(const failure_t failure) { - if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN || failure.reason == REASON_ASSERTION) { - verbose_test_failure_handler(failure); - } - if (failure.reason == REASON_ASSERTION) { - printf("{{failure}}\n{{end}}\n"); - while(1) ; - } -} - static void test_failure_handler(const failure_t failure) { if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { verbose_test_failure_handler(failure); diff --git "a/frameworks\\utest/source/greentea_handlers.cpp" "b/frameworks\\utest/source/greentea_handlers.cpp" index 747642f62b..e4760287e0 100644 --- "a/frameworks\\utest/source/greentea_handlers.cpp" +++ "b/frameworks\\utest/source/greentea_handlers.cpp" @@ -22,33 +22,33 @@ using namespace utest::v1; -static status_t greentea_unknown_test_setup_handler(const size_t); -static void greentea_selftest_failure_handler(const failure_t); -static void greentea_test_failure_handler(const failure_t); +static status_t unknown_test_setup_handler(const size_t); +static void selftest_failure_handler(const failure_t); +static void test_failure_handler(const failure_t); const handlers_t utest::v1::greentea_abort_handlers = { - greentea_unknown_test_setup_handler, + unknown_test_setup_handler, greentea_test_teardown_handler, - greentea_test_failure_handler, + test_failure_handler, greentea_case_setup_handler, greentea_case_teardown_handler, greentea_case_failure_abort_handler }; const handlers_t utest::v1::greentea_continue_handlers = { - greentea_unknown_test_setup_handler, + unknown_test_setup_handler, greentea_test_teardown_handler, - greentea_test_failure_handler, + test_failure_handler, greentea_case_setup_handler, greentea_case_teardown_handler, greentea_case_failure_continue_handler }; const handlers_t utest::v1::selftest_handlers = { - greentea_unknown_test_setup_handler, + unknown_test_setup_handler, greentea_test_teardown_handler, - greentea_selftest_failure_handler, + selftest_failure_handler, greentea_case_setup_handler, greentea_case_teardown_handler, greentea_case_failure_continue_handler @@ -56,14 +56,14 @@ const handlers_t utest::v1::selftest_handlers = { // --- SPECIAL HANDLERS --- -static status_t greentea_unknown_test_setup_handler(const size_t) { +static status_t unknown_test_setup_handler(const size_t) { printf(">>> I do not know how to tell greentea that the test started, since\n"); printf(">>> you forgot to override the `test_setup_handler` in your specification.\n"); return STATUS_ABORT; } -static void greentea_selftest_failure_handler(const failure_t failure) { +static void selftest_failure_handler(const failure_t failure) { if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN || failure.reason == REASON_ASSERTION) { verbose_test_failure_handler(failure); } @@ -73,7 +73,7 @@ static void greentea_selftest_failure_handler(const failure_t failure) { } } -static void greentea_test_failure_handler(const failure_t failure) { +static void test_failure_handler(const failure_t failure) { if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { verbose_test_failure_handler(failure); GREENTEA_TESTSUITE_RESULT(false); From 589dd7b509bdc361d55954529e61c525cfc01e49 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 13:51:37 +0000 Subject: [PATCH 72/88] Add scheduler interface with documentation. --- "frameworks\\utest/utest/scheduler.h" | 82 +++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 "frameworks\\utest/utest/scheduler.h" diff --git "a/frameworks\\utest/utest/scheduler.h" "b/frameworks\\utest/utest/scheduler.h" new file mode 100644 index 0000000000..243851cb19 --- /dev/null +++ "b/frameworks\\utest/utest/scheduler.h" @@ -0,0 +1,82 @@ +/**************************************************************************** + * Copyright (c) 2015, 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. + **************************************************************************** + */ + +#ifndef UTEST_SCHEDULER_H +#define UTEST_SCHEDULER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The utest harness manages its own state and therefore does not require the scheduler to + * bind any arguments to the scheduled callback. + */ +typedef void (*utest_v1_harness_callback_t)(void); + +/** + * utest calls this function when it needs to schedule a callback with a delay in milliseconds. + * `delay_ms` will only be non-zero if an asynchronous test case exists in the test specification. + * @note If your scheduler cannot provide asynchronous callbacks (which probably require a hardware timer), + * then this scheduler may return `NULL` as a handle and `utest` will fail the asynchronous request and move on. + * Note that test cases which do not require asynchronous callback support will still work fine then. + * + * @warning You MUST NOT execute the callback inside this function, even for a delay of 0ms. + * Buffer the callback and call it in your main loop. + * @warning You MUST NOT execute the callback in an interrupt context! + * Buffer the callback and call it in your main loop. + * @note utest only schedules one callback at any given time. + * This should make the implementation of this scheduler a lot simpler for you. + * + * @param callback the pointer to the callback function + * @param delay_ms the delay in milliseconds after which the callback should be executed + * @return A handle to identify the scheduled callback, or `NULL` for failure. + */ +typedef void *(*utest_v1_scheduler_post_callback_t)(const utest_v1_harness_callback_t callback, const uint32_t delay_ms); + +/** + * utest needs to cancel callbacks with a non-zero delay some time later. + * Even though `utest` only schedules one callback at any given time, it can cancel a callback more than once. + * You should therefore make use of the handle to make sure you do not cancel the wrong callback. + * + * @note If your scheduler cannot provide asynchronous callbacks, do nothing in this function and return non-zero. + * + * @param handle the handle returned from the `post` call to identify which callback to be cancelled. + * @retval `0` if success + * @retval non-zero if failure + */ +typedef int32_t (*utest_v1_scheduler_cancel_callback_t)(void *handle); + +/** + * The scheduler interface consists out of the `post` and `cancel` functions, + * which you must implement to use `utest`. + */ +typedef struct { + utest_v1_scheduler_post_callback_t post; + utest_v1_scheduler_cancel_callback_t cancel; +} utest_v1_scheduler_t; + +#ifdef __cplusplus +} +#endif + +#endif // UTEST_SCHEDULER_H From 95462c1d7cb97e5acbd46e806501c38cffbd9e15 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 13:58:01 +0000 Subject: [PATCH 73/88] Use scheduler interface in harness. The default implementation uses MINAR as the underlying scheduler, however, by declaring `config.utest.use_custom_scheduler = true` MINAR is not included by default. --- "frameworks\\utest/source/harness.cpp" | 66 ++++++++++++++++++++------ "frameworks\\utest/utest/harness.h" | 19 ++++++-- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 4c733fca61..d66815b184 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -17,9 +17,29 @@ */ #include "utest/harness.h" -#include "minar/minar.h" -#include "core-util/CriticalSectionLock.h" #include +#include "core-util/CriticalSectionLock.h" + + +#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER +#include "minar/minar.h" + +static void *utest_minar_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) +{ + void *handle = minar::Scheduler::postCallback(callback).delay(minar::milliseconds(delay_ms)).getHandle(); + return handle; +} +static int32_t utest_minar_cancel(void *handle) +{ + int32_t ret = minar::Scheduler::cancelCallback(handle); + return ret; +} +static const utest_v1_scheduler_t utest_minar_scheduler = +{ + utest_minar_post, + utest_minar_cancel +}; +#endif using namespace utest::v1; @@ -37,7 +57,7 @@ namespace control_t case_control = control_t(REPEAT_SETUP_TEARDOWN); size_t case_repeat_count = 1; - minar::callback_handle_t case_timeout_handle = NULL; + void *case_timeout_handle = NULL; size_t case_validation_count = 0; bool case_timeout_occurred = false; @@ -49,23 +69,41 @@ namespace handlers_t handlers = defaults; location_t location = LOCATION_UNKNOWN; + +#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER + utest_v1_scheduler_t scheduler = utest_minar_scheduler; +#else + utest_v1_scheduler_t scheduler = {NULL, NULL}; +#endif } static void die() { while(1) ; } -bool Harness::run(const Specification& specification) +bool Harness::set_scheduler(const utest_v1_scheduler_t scheduler) { - return run(specification, 0); + if (!scheduler.post || !scheduler.cancel) + return false; + + ::scheduler = scheduler; + return true; } bool Harness::run(const Specification& specification, std::size_t) +{ + return run(specification); +} + +bool Harness::run(const Specification& specification) { // check if a specification is currently running if (is_busy()) return false; + if (!scheduler.post || !scheduler.cancel) + return false; + test_cases = specification.cases; test_length = specification.length; defaults = specification.defaults; @@ -102,7 +140,7 @@ bool Harness::run(const Specification& specification, std::size_t) case_current = &test_cases[setup_status]; - minar::Scheduler::postCallback(run_next_case); + scheduler.post(run_next_case, 0); return true; } @@ -122,7 +160,7 @@ void Harness::raise_failure(const failure_reason_t reason) if ((fail_status == STATUS_ABORT) && case_timeout_handle) { - minar::Scheduler::cancelCallback(case_timeout_handle); + scheduler.cancel(case_timeout_handle); case_timeout_handle = NULL; } } @@ -175,7 +213,7 @@ void Harness::schedule_next_case() case_repeat_count = 1; test_index_of_case++; } - minar::Scheduler::postCallback(run_next_case); + scheduler.post(run_next_case, 0); } void Harness::handle_timeout() @@ -190,7 +228,7 @@ void Harness::handle_timeout() } if (case_timeout_occurred) { raise_failure(failure_reason_t(REASON_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? REASON_IGNORE : 0))); - minar::Scheduler::postCallback(schedule_next_case); + scheduler.post(schedule_next_case, 0); } } @@ -201,12 +239,12 @@ void Harness::validate_callback(const control_t control) if (case_timeout_handle != NULL || case_control.timeout == TIMEOUT_FOREVER) { - minar::Scheduler::cancelCallback(case_timeout_handle); + scheduler.cancel(case_timeout_handle); case_timeout_handle = NULL; control_t merged_control = case_control + control; case_control.repeat = repeat_t(merged_control.repeat & ~REPEAT_ON_TIMEOUT); case_control.timeout = TIMEOUT_NONE; - minar::Scheduler::postCallback(schedule_next_case); + scheduler.post(schedule_next_case, 0); } } @@ -272,13 +310,11 @@ void Harness::run_next_case() if (case_control.timeout < TIMEOUT_UNDECLR && case_validation_count == 0) { // if await validation _with_ timeout if (case_control.timeout < TIMEOUT_FOREVER) { - case_timeout_handle = minar::Scheduler::postCallback(handle_timeout) - .delay(minar::milliseconds(case_control.timeout)) - .getHandle(); + case_timeout_handle = scheduler.post(handle_timeout, case_control.timeout); } } else { - minar::Scheduler::postCallback(schedule_next_case); + scheduler.post(schedule_next_case, 0); } } } diff --git "a/frameworks\\utest/utest/harness.h" "b/frameworks\\utest/utest/harness.h" index 726f146497..9298af9af3 100644 --- "a/frameworks\\utest/utest/harness.h" +++ "b/frameworks\\utest/utest/harness.h" @@ -27,6 +27,7 @@ #include "case.h" #include "default_handlers.h" #include "specification.h" +#include "scheduler.h" namespace utest { @@ -38,7 +39,12 @@ namespace v1 { * The harness executes the test specification in an asynchronous fashion, therefore * `run()` returns immediately. * - * @note: In case of an test abort, the harness will busy-wait and never finish. + * By default, this harness uses the MINAR scheduler for asynchronous callbacks. + * If you wamt to provide your own custom scheduler, set `config.utest.use_custom_scheduler` to `true` + * inside your yotta config and set a custom scheduler implementation using the `set_scheduler()` function. + * You must set the scheduler before running a specification. + * + * @note In case of an test abort, the harness will busy-wait and never finish. */ class Harness { @@ -48,15 +54,18 @@ namespace v1 { /// @retval `false` if another specification is currently running static bool run(const Specification& specification); - /// Runs a test specification starting at the specified case index - /// @warning if the start index is out of bounds, the call has no effect! - /// @retval `true` if the specification can be run - /// @retval `false` if another specification is currently running, or the start index was out of bounds + /// @cond + __deprecated_message("Start case selection is done by returning the index from the test setup handler!") static bool run(const Specification& specification, size_t start_case); + /// @endcond /// @returns `true` if a test specification is being executed, `false` otherwise static bool is_busy(); + /// Sets the scheduler to be used. + /// @return `true` if scheduler is properly specified (all functions non-null). + static bool set_scheduler(utest_v1_scheduler_t scheduler); + /** Call this function in the asynchronous callback that you have been waiting for. * * You can only validate a callback once, calling this function when no callback is expected From d33aabf7ac95bc292ca195b331fd7f04143f254d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 14:45:20 +0000 Subject: [PATCH 74/88] Handle failure to schedule callback asynchronously. --- "frameworks\\utest/source/harness.cpp" | 4 ++++ "frameworks\\utest/source/types.cpp" | 3 +++ "frameworks\\utest/utest/types.h" | 1 + 3 files changed, 8 insertions(+) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index d66815b184..a5c7420e48 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -311,6 +311,10 @@ void Harness::run_next_case() // if await validation _with_ timeout if (case_control.timeout < TIMEOUT_FOREVER) { case_timeout_handle = scheduler.post(handle_timeout, case_control.timeout); + if (case_timeout_handle == NULL) { + raise_failure(REASON_SCHEDULER); + schedule_next_case(); + } } } else { diff --git "a/frameworks\\utest/source/types.cpp" "b/frameworks\\utest/source/types.cpp" index f9bed9849f..80cf1e743f 100644 --- "a/frameworks\\utest/source/types.cpp" +++ "b/frameworks\\utest/source/types.cpp" @@ -56,6 +56,9 @@ const char* utest::v1::stringify(utest::v1::failure_reason_t reason) case REASON_CASE_INDEX: string = "Ignored: Case Index Invalid"; break; + case REASON_SCHEDULER: + string = "Ignored: Scheduling Asynchronous Callback Failed"; + break; default: case REASON_UNKNOWN: string = "Ignored: Unknown Failure"; diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 8d49176827..8ba36d097f 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -66,6 +66,7 @@ namespace v1 { REASON_CASE_TEARDOWN = (1 << 9), ///< Case teardown failed REASON_CASE_INDEX = (1 << 10), ///< Case index out-of-range + REASON_SCHEDULER = (1 << 11), ///< Asynchronous callback scheduling failed REASON_IGNORE = 0x8000 ///< The failure may be ignored }; From 2fdf7332925980952610454727b89c76bcdc7dc3 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 14:45:28 +0000 Subject: [PATCH 75/88] Update documentation. --- "frameworks\\utest/utest/default_handlers.h" | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 3ef00ce584..76912ed02d 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -159,8 +159,7 @@ namespace v1 { /// Prints the reason of the failure and continues, unless the teardown handler failed, for which it aborts. status_t verbose_case_failure_handler (const Case *const source, const failure_t reason); - /// Prints a helpful error message and aborts. - /// This function **NEEDS** to be overridden by the user when using greentea. + /// Requests the start test case from greentea and continues. status_t greentea_test_setup_handler (const size_t number_of_cases); /// Reports the test results to greentea. void greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure); From 494c303da53923abb9505f3309ecf0f112ee8e8d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 15:23:12 +0000 Subject: [PATCH 76/88] Remove C++11 member initializers. --- "frameworks\\utest/utest/default_handlers.h" | 54 ++++++-------------- "frameworks\\utest/utest/types.h" | 9 ++-- 2 files changed, 22 insertions(+), 41 deletions(-) diff --git "a/frameworks\\utest/utest/default_handlers.h" "b/frameworks\\utest/utest/default_handlers.h" index 76912ed02d..fe372e3829 100644 --- "a/frameworks\\utest/utest/default_handlers.h" +++ "b/frameworks\\utest/utest/default_handlers.h" @@ -34,23 +34,15 @@ namespace v1 { * This type automatically casts itself into the appropriate handler type, when possible. * Use the constants to default a handler unambigously. */ - const struct + static const struct { - const test_setup_handler_t test_setup = test_setup_handler_t(1); - const test_teardown_handler_t test_teardown = test_teardown_handler_t(1); - const test_failure_handler_t test_failure = test_failure_handler_t(1); + operator test_setup_handler_t() const { return test_setup_handler_t(1); } + operator test_teardown_handler_t() const { return test_teardown_handler_t(1); } + operator test_failure_handler_t() const { return test_failure_handler_t(1); } - const case_setup_handler_t case_setup = case_setup_handler_t(1); - const case_teardown_handler_t case_teardown = case_teardown_handler_t(1); - const case_failure_handler_t case_failure = case_failure_handler_t(1); - - operator test_setup_handler_t() const { return test_setup; } - operator test_teardown_handler_t() const { return test_teardown; } - operator test_failure_handler_t() const { return test_failure; } - - operator case_setup_handler_t() const { return case_setup; } - operator case_teardown_handler_t() const { return case_teardown; } - operator case_failure_handler_t() const { return case_failure; } + operator case_setup_handler_t() const { return case_setup_handler_t(1); } + operator case_teardown_handler_t() const { return case_teardown_handler_t(1); } + operator case_failure_handler_t() const { return case_failure_handler_t(1); } } default_handler; /** Ignore handler hint. @@ -59,31 +51,19 @@ namespace v1 { * This type automatically casts itself into the appropriate handler type, when possible. * Use the constants to ignore a handler unambigously. */ - const struct + static const struct { - const case_handler_t handler = case_handler_t(NULL); - const case_control_handler_t control = case_control_handler_t(NULL); - const case_call_count_handler_t call_count = case_call_count_handler_t(NULL); + operator case_handler_t() const { return case_handler_t(NULL); } + operator case_control_handler_t() const { return case_control_handler_t(NULL); } + operator case_call_count_handler_t() const { return case_call_count_handler_t(NULL); } - const test_setup_handler_t test_setup = test_setup_handler_t(NULL); - const test_teardown_handler_t test_teardown = test_teardown_handler_t(NULL); - const test_failure_handler_t test_failure = test_failure_handler_t(NULL); + operator test_setup_handler_t() const { return test_setup_handler_t(NULL); } + operator test_teardown_handler_t() const { return test_teardown_handler_t(NULL); } + operator test_failure_handler_t() const { return test_failure_handler_t(NULL); } - const case_setup_handler_t case_setup = case_setup_handler_t(NULL); - const case_teardown_handler_t case_teardown = case_teardown_handler_t(NULL); - const case_failure_handler_t case_failure = case_failure_handler_t(NULL); - - operator case_handler_t() const { return handler; } - operator case_control_handler_t() const { return control; } - operator case_call_count_handler_t() const { return call_count; } - - operator test_setup_handler_t() const { return test_setup; } - operator test_teardown_handler_t() const { return test_teardown; } - operator test_failure_handler_t() const { return test_failure; } - - operator case_setup_handler_t() const { return case_setup; } - operator case_teardown_handler_t() const { return case_teardown; } - operator case_failure_handler_t() const { return case_failure; } + operator case_setup_handler_t() const { return case_setup_handler_t(NULL); } + operator case_teardown_handler_t() const { return case_teardown_handler_t(NULL); } + operator case_failure_handler_t() const { return case_failure_handler_t(NULL); } } ignore_handler; /** A table of handlers. diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 8ba36d097f..9cf0955545 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -83,8 +83,9 @@ namespace v1 { /// Contains the reason and location of the failure. struct failure_t { - failure_t(failure_reason_t reason) : reason(reason) {} - failure_t(location_t location) : location(location) {} + failure_t() : reason(REASON_NONE), location(LOCATION_NONE) {} + failure_t(failure_reason_t reason) : reason(reason), location(LOCATION_NONE) {} + failure_t(location_t location) : reason(REASON_NONE), location(location) {} failure_t(failure_reason_t reason, location_t location) : reason(reason), location(location) {} /// @returns a copy of the failure with the reason ignored. @@ -92,8 +93,8 @@ namespace v1 { return failure_t(failure_reason_t(reason | REASON_IGNORE), location); } - failure_reason_t reason = REASON_NONE; - location_t location = LOCATION_NONE; + failure_reason_t reason; + location_t location; }; From 6e85376d37c205992c81d90b663317657e226a56 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 21 Mar 2016 16:06:10 +0000 Subject: [PATCH 77/88] Allow case selection from teardown handler. This can be used for arbitrary ordering of test cases. --- "frameworks\\utest/source/harness.cpp" | 28 +++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index a5c7420e48..73dfe6b545 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -54,6 +54,7 @@ namespace size_t test_failed = 0; const Case *case_current = NULL; + size_t case_index = 0; control_t case_control = control_t(REPEAT_SETUP_TEARDOWN); size_t case_repeat_count = 1; @@ -138,7 +139,8 @@ bool Harness::run(const Specification& specification) return true; } - case_current = &test_cases[setup_status]; + case_index = setup_status; + case_current = &test_cases[case_index]; scheduler.post(run_next_case, 0); return true; @@ -169,11 +171,13 @@ void Harness::raise_failure(const failure_reason_t reason) if (handlers.case_teardown && location != LOCATION_CASE_TEARDOWN) { location_t fail_loc(location); location = LOCATION_CASE_TEARDOWN; + status_t teardown_status = handlers.case_teardown(case_current, case_passed, case_failed, failure_t(reason, fail_loc)); - if (teardown_status != STATUS_CONTINUE) { - raise_failure(REASON_CASE_TEARDOWN); - } - else handlers.case_teardown = NULL; + if (teardown_status < STATUS_CONTINUE) raise_failure(REASON_CASE_TEARDOWN); + else if (teardown_status > signed(test_length)) raise_failure(REASON_CASE_INDEX); + else if (teardown_status >= 0) case_index = teardown_status - 1; + + handlers.case_teardown = NULL; } } if (fail_status == STATUS_ABORT) { @@ -194,10 +198,13 @@ void Harness::schedule_next_case() if (case_control.repeat & REPEAT_SETUP_TEARDOWN || !(case_control.repeat & (REPEAT_ON_TIMEOUT | REPEAT_ON_VALIDATE))) { location = LOCATION_CASE_TEARDOWN; - if (handlers.case_teardown && - (handlers.case_teardown(case_current, case_passed, case_failed, - case_failed ? failure_t(REASON_CASES, LOCATION_UNKNOWN) : failure_t(REASON_NONE)) != STATUS_CONTINUE)) { - raise_failure(REASON_CASE_TEARDOWN); + + if (handlers.case_teardown) { + status_t status = handlers.case_teardown(case_current, case_passed, case_failed, + case_failed ? failure_t(REASON_CASES, LOCATION_UNKNOWN) : failure_t(REASON_NONE)); + if (status < STATUS_CONTINUE) raise_failure(REASON_CASE_TEARDOWN); + else if (status > signed(test_length)) raise_failure(REASON_CASE_INDEX); + else if (status >= 0) case_index = status - 1; } } @@ -206,7 +213,8 @@ void Harness::schedule_next_case() else test_passed++; case_control = control_t(REPEAT_SETUP_TEARDOWN); - case_current++; + case_index++; + case_current = &test_cases[case_index]; case_passed = 0; case_failed = 0; case_failed_before = 0; From df1d9f5529b027dcce0e609e5e2ea44b33e1f685 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 5 Apr 2016 16:54:50 +0100 Subject: [PATCH 78/88] Extend scheduler with init and run callbacks. --- "frameworks\\utest/utest/scheduler.h" | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git "a/frameworks\\utest/utest/scheduler.h" "b/frameworks\\utest/utest/scheduler.h" index 243851cb19..55d83e97b2 100644 --- "a/frameworks\\utest/utest/scheduler.h" +++ "b/frameworks\\utest/utest/scheduler.h" @@ -33,6 +33,15 @@ extern "C" { */ typedef void (*utest_v1_harness_callback_t)(void); +/** + * utest calls this function before running the test specification. + * Use this function to initialize your scheduler before the first callback is requested. + * + * @retval `0` if success + * @retval non-zero if failure + */ +typedef int32_t (*utest_v1_scheduler_init_callback_t)(void); + /** * utest calls this function when it needs to schedule a callback with a delay in milliseconds. * `delay_ms` will only be non-zero if an asynchronous test case exists in the test specification. @@ -66,13 +75,25 @@ typedef void *(*utest_v1_scheduler_post_callback_t)(const utest_v1_harness_callb */ typedef int32_t (*utest_v1_scheduler_cancel_callback_t)(void *handle); +/** + * utest calls this function at the end of the `Harness::run()` function, after (!) the first callback has been requested. + * This function is meant to implement an optional event loop, which may very well be blocking (if your scheduler works with that). + * This assumes that `Harness::run()` will be called on the main stack (ie. not in an interrupt!). + * + * @retval `0` if success + * @retval non-zero if failure + */ +typedef int32_t (*utest_v1_scheduler_run_callback_t)(void); + /** * The scheduler interface consists out of the `post` and `cancel` functions, * which you must implement to use `utest`. */ typedef struct { + utest_v1_scheduler_init_callback_t init; utest_v1_scheduler_post_callback_t post; utest_v1_scheduler_cancel_callback_t cancel; + utest_v1_scheduler_run_callback_t run; } utest_v1_scheduler_t; #ifdef __cplusplus From 53377a1f4a20f09da761cbacf0ad7241a023328e Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 5 Apr 2016 16:55:46 +0100 Subject: [PATCH 79/88] Adapt Harness to call init and run functions. --- "frameworks\\utest/source/harness.cpp" | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 73dfe6b545..2c8f7e03f0 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -84,14 +84,14 @@ static void die() { bool Harness::set_scheduler(const utest_v1_scheduler_t scheduler) { - if (!scheduler.post || !scheduler.cancel) + if (!scheduler.init || !scheduler.post || !scheduler.cancel || !scheduler.run) return false; ::scheduler = scheduler; return true; } -bool Harness::run(const Specification& specification, std::size_t) +bool Harness::run(const Specification& specification, size_t) { return run(specification); } @@ -102,7 +102,10 @@ bool Harness::run(const Specification& specification) if (is_busy()) return false; - if (!scheduler.post || !scheduler.cancel) + if (!scheduler.init || !scheduler.post || !scheduler.cancel || !scheduler.run) + return false; + + if (scheduler.init() != 0) return false; test_cases = specification.cases; @@ -143,6 +146,14 @@ bool Harness::run(const Specification& specification) case_current = &test_cases[case_index]; scheduler.post(run_next_case, 0); + if (scheduler.run() != 0) { + failure.reason = REASON_SCHEDULER; + if (handlers.test_failure) handlers.test_failure(failure); + if (handlers.test_teardown) handlers.test_teardown(0, 0, failure); + test_cases = NULL; + exit(1); + return true; + } return true; } From 336bffaf05fb719c75bf300fc387c6cd3b7b77fc Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 5 Apr 2016 16:57:56 +0100 Subject: [PATCH 80/88] Add shim definitions for mbed OS definitions. This allows utest to be used without mbed OS dependencies. --- "frameworks\\utest/source/shim.cpp" | 125 ++++++++++++++++++++++++++++ "frameworks\\utest/utest/shim.h" | 77 +++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 "frameworks\\utest/source/shim.cpp" create mode 100644 "frameworks\\utest/utest/shim.h" diff --git "a/frameworks\\utest/source/shim.cpp" "b/frameworks\\utest/source/shim.cpp" new file mode 100644 index 0000000000..bfb603cee8 --- /dev/null +++ "b/frameworks\\utest/source/shim.cpp" @@ -0,0 +1,125 @@ +/**************************************************************************** + * Copyright (c) 2015, 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 "utest/shim.h" + + +#if UTEST_SHIM_SCHEDULER_USE_MINAR +#include "minar/minar.h" + +static int32_t utest_minar_init() +{ + return 0; +} +static void *utest_minar_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) +{ + void *handle = minar::Scheduler::postCallback(callback).delay(minar::milliseconds(delay_ms)).getHandle(); + return handle; +} +static int32_t utest_minar_cancel(void *handle) +{ + int32_t ret = minar::Scheduler::cancelCallback(handle); + return ret; +} +static int32_t utest_minar_run() +{ + return 0; +} +extern "C" const utest_v1_scheduler_t utest_v1_scheduler = +{ + utest_minar_init, + utest_minar_post, + utest_minar_cancel, + utest_minar_run +}; + +#elif UTEST_SHIM_SCHEDULER_USE_US_TICKER +// only one callback is active at any given time +volatile utest_v1_harness_callback_t minimal_callback; +volatile utest_v1_harness_callback_t ticker_callback; +const ticker_data_t *ticker_data; +ticker_event_t ticker_event; + +static void ticker_handler(uint32_t) +{ + // printf("\t\t>>> Ticker callback fired for %p.\n", ticker_callback); + minimal_callback = ticker_callback; +} + +static int32_t utest_us_ticker_init() +{ + ticker_data = get_us_ticker_data(); + return 0; +} +static void *utest_us_ticker_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) +{ + // printf("\t\t>>> Schedule %p with %ums delay => %p.\n", callback, (unsigned int)delay_ms, (void*)1); + if (delay_ms) { + ticker_callback = callback; + // setup ticker to call the handler manually + ticker_set_handler(ticker_data, ticker_handler); + // fire the interrupt in 1000us * delay_ms + ticker_insert_event(ticker_data, &ticker_event, ticker_read(ticker_data) + delay_ms * 1000, 0); + } else { + minimal_callback = callback; + } + + // return a bogus handle + return (void*)1; +} +static int32_t utest_us_ticker_cancel(void *handle) +{ + // printf("\t\t>>> Cancel %p => %u\n", handle, (unsigned int)0); + (void) handle; + ticker_remove_event(ticker_data, &ticker_event); + return 0; +} +static int32_t utest_us_ticker_run() +{ + while(1) + { + // check if a new callback has been set + if (minimal_callback) + { + // printf("\t\t>>> Firing callback %p\n", minimal_callback); + // copy the callback + utest_v1_harness_callback_t callback = minimal_callback; + // reset the shared callback + minimal_callback = NULL; + // execute the copied callback + callback(); + } + } + return 0; +} +const utest_v1_scheduler_t utest_v1_scheduler = +{ + utest_us_ticker_init, + utest_us_ticker_post, + utest_us_ticker_cancel, + utest_us_ticker_run +}; +#else +const utest_v1_scheduler_t utest_v1_scheduler = +{ + NULL, + NULL, + NULL, + NULL +}; +#endif diff --git "a/frameworks\\utest/utest/shim.h" "b/frameworks\\utest/utest/shim.h" new file mode 100644 index 0000000000..dd8f8437ca --- /dev/null +++ "b/frameworks\\utest/utest/shim.h" @@ -0,0 +1,77 @@ +/**************************************************************************** + * Copyright (c) 2016, 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. + **************************************************************************** + */ + +#ifndef UTEST_SHIM_H +#define UTEST_SHIM_H + +#include +#include +#include +#include "scheduler.h" + +#ifdef YOTTA_CFG +# include "compiler-polyfill/attributes.h" +#else +# ifndef __deprecated_message +# if defined(__CC_ARM) +# define __deprecated_message(msg) __attribute__((deprecated)) +# else +# define __deprecated_message(msg) __attribute__((deprecated(msg))) +# endif +# endif +#endif + +#ifdef YOTTA_CORE_UTIL_VERSION_STRING +# include "core-util/CriticalSectionLock.h" +# define UTEST_ENTER_CRITICAL_SECTION mbed::util::CriticalSectionLock lock +# define UTEST_LEAVE_CRITICAL_SECTION +#else +# ifndef UTEST_ENTER_CRITICAL_SECTION +# error "You must provide a UTEST_ENTER_CRITICAL_SECTION implementation!" +# endif +# ifndef UTEST_LEAVE_CRITICAL_SECTION +# error "You must provide a UTEST_LEAVE_CRITICAL_SECTION implementation!" +# endif +#endif + +#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER +# ifdef YOTTA_MINAR_VERSION_STRING +# define UTEST_MINAR_AVAILABLE 1 +# else +# define UTEST_MINAR_AVAILABLE 0 +# endif +# ifndef UTEST_SHIM_SCHEDULER_USE_MINAR +# define UTEST_SHIM_SCHEDULER_USE_MINAR UTEST_MINAR_AVAILABLE +# endif +# ifndef UTEST_SHIM_SCHEDULER_USE_US_TICKER +# define UTEST_SHIM_SCHEDULER_USE_US_TICKER (!UTEST_MINAR_AVAILABLE) +# endif +#endif // YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER + +#ifdef __cplusplus +extern "C" { +#endif + +/// This is the default scheduler implementation used by the harness. +extern const utest_v1_scheduler_t utest_v1_scheduler; + +#ifdef __cplusplus +} +#endif + +#endif // UTEST_SHIM_H From d5cb178700f9cfd561a4a0fb86e4f09852fea563 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 5 Apr 2016 16:59:05 +0100 Subject: [PATCH 81/88] Use scheduler provided by shim layer in Harness. --- "frameworks\\utest/source/harness.cpp" | 28 +------------------------- "frameworks\\utest/utest/types.h" | 2 +- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index 2c8f7e03f0..a4c6d8f1cb 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -18,28 +18,6 @@ #include "utest/harness.h" #include -#include "core-util/CriticalSectionLock.h" - - -#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER -#include "minar/minar.h" - -static void *utest_minar_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) -{ - void *handle = minar::Scheduler::postCallback(callback).delay(minar::milliseconds(delay_ms)).getHandle(); - return handle; -} -static int32_t utest_minar_cancel(void *handle) -{ - int32_t ret = minar::Scheduler::cancelCallback(handle); - return ret; -} -static const utest_v1_scheduler_t utest_minar_scheduler = -{ - utest_minar_post, - utest_minar_cancel -}; -#endif using namespace utest::v1; @@ -71,11 +49,7 @@ namespace location_t location = LOCATION_UNKNOWN; -#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER - utest_v1_scheduler_t scheduler = utest_minar_scheduler; -#else - utest_v1_scheduler_t scheduler = {NULL, NULL}; -#endif + utest_v1_scheduler_t scheduler = utest_v1_scheduler; } static void die() { diff --git "a/frameworks\\utest/utest/types.h" "b/frameworks\\utest/utest/types.h" index 9cf0955545..ef8c6c3ccf 100644 --- "a/frameworks\\utest/utest/types.h" +++ "b/frameworks\\utest/utest/types.h" @@ -22,7 +22,7 @@ #include #include #include -#include "compiler-polyfill/attributes.h" +#include "shim.h" namespace utest { namespace v1 { From 207660cc865ac0075841a2c439b4b8e27fdd21b4 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 5 Apr 2016 16:59:29 +0100 Subject: [PATCH 82/88] Use shim macros for critical sections in Harness. --- "frameworks\\utest/source/harness.cpp" | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index a4c6d8f1cb..f00b0adc32 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -139,7 +139,7 @@ void Harness::raise_failure(const failure_reason_t reason) status_t fail_status = STATUS_ABORT; { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; if (handlers.test_failure) handlers.test_failure(failure_t(reason, location)); if (handlers.case_failure) fail_status = handlers.case_failure(case_current, failure_t(reason, location)); @@ -150,6 +150,7 @@ void Harness::raise_failure(const failure_reason_t reason) scheduler.cancel(case_timeout_handle); case_timeout_handle = NULL; } + UTEST_LEAVE_CRITICAL_SECTION; } if (fail_status == STATUS_ABORT || reason & REASON_CASE_SETUP) { @@ -212,12 +213,13 @@ void Harness::schedule_next_case() void Harness::handle_timeout() { { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; if (case_timeout_handle != NULL) { case_timeout_handle = NULL; case_timeout_occurred = true; } + UTEST_LEAVE_CRITICAL_SECTION; } if (case_timeout_occurred) { raise_failure(failure_reason_t(REASON_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? REASON_IGNORE : 0))); @@ -227,7 +229,7 @@ void Harness::handle_timeout() void Harness::validate_callback(const control_t control) { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; case_validation_count++; if (case_timeout_handle != NULL || case_control.timeout == TIMEOUT_FOREVER) @@ -239,15 +241,18 @@ void Harness::validate_callback(const control_t control) case_control.timeout = TIMEOUT_NONE; scheduler.post(schedule_next_case, 0); } + UTEST_LEAVE_CRITICAL_SECTION; } bool Harness::is_busy() { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; if (!test_cases) return false; if (!case_current) return false; - return (case_current < (test_cases + test_length)); + bool res = (case_current < (test_cases + test_length)); + UTEST_LEAVE_CRITICAL_SECTION; + return res; } void Harness::run_next_case() @@ -267,11 +272,12 @@ void Harness::run_next_case() repeat_t setup_repeat; { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; case_validation_count = 0; case_timeout_occurred = false; setup_repeat = case_control.repeat; case_control = control_t(); + UTEST_LEAVE_CRITICAL_SECTION; } if (setup_repeat & REPEAT_SETUP_TEARDOWN) { @@ -296,7 +302,7 @@ void Harness::run_next_case() case_repeat_count++; { - mbed::util::CriticalSectionLock lock; + UTEST_ENTER_CRITICAL_SECTION; if (case_validation_count) case_control.repeat = repeat_t(case_control.repeat & ~REPEAT_ON_TIMEOUT); // if timeout valid @@ -313,6 +319,7 @@ void Harness::run_next_case() else { scheduler.post(schedule_next_case, 0); } + UTEST_LEAVE_CRITICAL_SECTION; } } else if (handlers.test_teardown) { From 12a46551a5f72417e2b1be0022cb7bdd109ecbd1 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 6 Apr 2016 22:07:22 +0100 Subject: [PATCH 83/88] Use functions instead of macros for porting. --- "frameworks\\utest/source/harness.cpp" | 25 ++++++++++------ "frameworks\\utest/source/shim.cpp" | 40 +++++++++++++++----------- "frameworks\\utest/utest/shim.h" | 10 +++++-- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git "a/frameworks\\utest/source/harness.cpp" "b/frameworks\\utest/source/harness.cpp" index f00b0adc32..8403bffcd1 100644 --- "a/frameworks\\utest/source/harness.cpp" +++ "b/frameworks\\utest/source/harness.cpp" @@ -49,20 +49,25 @@ namespace location_t location = LOCATION_UNKNOWN; - utest_v1_scheduler_t scheduler = utest_v1_scheduler; + utest_v1_scheduler_t scheduler = {NULL, NULL, NULL, NULL}; } static void die() { while(1) ; } +static bool is_scheduler_valid(const utest_v1_scheduler_t scheduler) +{ + return (scheduler.init && scheduler.post && scheduler.cancel && scheduler.run); +} + bool Harness::set_scheduler(const utest_v1_scheduler_t scheduler) { - if (!scheduler.init || !scheduler.post || !scheduler.cancel || !scheduler.run) - return false; - - ::scheduler = scheduler; - return true; + if (is_scheduler_valid(scheduler)) { + ::scheduler = scheduler; + return true; + } + return false; } bool Harness::run(const Specification& specification, size_t) @@ -76,9 +81,13 @@ bool Harness::run(const Specification& specification) if (is_busy()) return false; - if (!scheduler.init || !scheduler.post || !scheduler.cancel || !scheduler.run) + // if the scheduler is invalid, this is the first time we are calling + if (!is_scheduler_valid(scheduler)) + scheduler = utest_v1_get_scheduler(); + // if the scheduler is still invalid, abort + if (!is_scheduler_valid(scheduler)) return false; - + // if the scheduler failed to initialize, abort if (scheduler.init() != 0) return false; diff --git "a/frameworks\\utest/source/shim.cpp" "b/frameworks\\utest/source/shim.cpp" index bfb603cee8..80d783aae7 100644 --- "a/frameworks\\utest/source/shim.cpp" +++ "b/frameworks\\utest/source/shim.cpp" @@ -18,7 +18,6 @@ #include "utest/shim.h" - #if UTEST_SHIM_SCHEDULER_USE_MINAR #include "minar/minar.h" @@ -40,20 +39,26 @@ static int32_t utest_minar_run() { return 0; } -extern "C" const utest_v1_scheduler_t utest_v1_scheduler = +extern "C" { +static const utest_v1_scheduler_t utest_v1_scheduler = { utest_minar_init, utest_minar_post, utest_minar_cancel, utest_minar_run }; +utest_v1_scheduler_t utest_v1_get_scheduler() +{ + return utest_v1_scheduler; +} +} #elif UTEST_SHIM_SCHEDULER_USE_US_TICKER // only one callback is active at any given time -volatile utest_v1_harness_callback_t minimal_callback; -volatile utest_v1_harness_callback_t ticker_callback; -const ticker_data_t *ticker_data; -ticker_event_t ticker_event; +static volatile utest_v1_harness_callback_t minimal_callback; +static volatile utest_v1_harness_callback_t ticker_callback; +static const ticker_data_t *ticker_data; +static ticker_event_t ticker_event; static void ticker_handler(uint32_t) { @@ -64,6 +69,7 @@ static void ticker_handler(uint32_t) static int32_t utest_us_ticker_init() { ticker_data = get_us_ticker_data(); + ticker_set_handler(ticker_data, ticker_handler); return 0; } static void *utest_us_ticker_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) @@ -71,8 +77,6 @@ static void *utest_us_ticker_post(const utest_v1_harness_callback_t callback, co // printf("\t\t>>> Schedule %p with %ums delay => %p.\n", callback, (unsigned int)delay_ms, (void*)1); if (delay_ms) { ticker_callback = callback; - // setup ticker to call the handler manually - ticker_set_handler(ticker_data, ticker_handler); // fire the interrupt in 1000us * delay_ms ticker_insert_event(ticker_data, &ticker_event, ticker_read(ticker_data) + delay_ms * 1000, 0); } else { @@ -107,19 +111,23 @@ static int32_t utest_us_ticker_run() } return 0; } -const utest_v1_scheduler_t utest_v1_scheduler = +extern "C" { +static const utest_v1_scheduler_t utest_v1_scheduler = { utest_us_ticker_init, utest_us_ticker_post, utest_us_ticker_cancel, utest_us_ticker_run }; -#else -const utest_v1_scheduler_t utest_v1_scheduler = +utest_v1_scheduler_t utest_v1_get_scheduler() { - NULL, - NULL, - NULL, - NULL -}; + return utest_v1_scheduler; +} +} +#endif + +#ifdef YOTTA_CORE_UTIL_VERSION_STRING +// their functionality is implemented using the CriticalSectionLock class +void utest_v1_enter_critical_section(void) {} +void utest_v1_leave_critical_section(void) {} #endif diff --git "a/frameworks\\utest/utest/shim.h" "b/frameworks\\utest/utest/shim.h" index dd8f8437ca..c154bfa83a 100644 --- "a/frameworks\\utest/utest/shim.h" +++ "b/frameworks\\utest/utest/shim.h" @@ -42,10 +42,10 @@ # define UTEST_LEAVE_CRITICAL_SECTION #else # ifndef UTEST_ENTER_CRITICAL_SECTION -# error "You must provide a UTEST_ENTER_CRITICAL_SECTION implementation!" +# define UTEST_ENTER_CRITICAL_SECTION utest_v1_enter_critical_section() # endif # ifndef UTEST_LEAVE_CRITICAL_SECTION -# error "You must provide a UTEST_LEAVE_CRITICAL_SECTION implementation!" +# define UTEST_LEAVE_CRITICAL_SECTION utest_v1_leave_critical_section() # endif #endif @@ -67,8 +67,12 @@ extern "C" { #endif +/// must be implemented by the port +void utest_v1_enter_critical_section(void); +void utest_v1_leave_critical_section(void); + /// This is the default scheduler implementation used by the harness. -extern const utest_v1_scheduler_t utest_v1_scheduler; +utest_v1_scheduler_t utest_v1_get_scheduler(void); #ifdef __cplusplus } From 62dec8f6e0221bc585fad60b5ffa6ba4c9a01b03 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 7 Apr 2016 10:59:42 +0100 Subject: [PATCH 84/88] Don't enable us_ticker scheduler if minar unavail. --- "frameworks\\utest/utest/shim.h" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/frameworks\\utest/utest/shim.h" "b/frameworks\\utest/utest/shim.h" index c154bfa83a..1cec14a9fb 100644 --- "a/frameworks\\utest/utest/shim.h" +++ "b/frameworks\\utest/utest/shim.h" @@ -59,7 +59,7 @@ # define UTEST_SHIM_SCHEDULER_USE_MINAR UTEST_MINAR_AVAILABLE # endif # ifndef UTEST_SHIM_SCHEDULER_USE_US_TICKER -# define UTEST_SHIM_SCHEDULER_USE_US_TICKER (!UTEST_MINAR_AVAILABLE) +# define UTEST_SHIM_SCHEDULER_USE_US_TICKER 0 # endif #endif // YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER From 53b9fe282067320c3eaf28a67c90ee4ab89be090 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 7 Apr 2016 12:43:38 +0100 Subject: [PATCH 85/88] Include us_ticker.h in scheduler implementation. --- "frameworks\\utest/source/shim.cpp" | 5 +++++ 1 file changed, 5 insertions(+) diff --git "a/frameworks\\utest/source/shim.cpp" "b/frameworks\\utest/source/shim.cpp" index 80d783aae7..bb66fff80f 100644 --- "a/frameworks\\utest/source/shim.cpp" +++ "b/frameworks\\utest/source/shim.cpp" @@ -54,6 +54,11 @@ utest_v1_scheduler_t utest_v1_get_scheduler() } #elif UTEST_SHIM_SCHEDULER_USE_US_TICKER +#ifdef YOTTA_MBED_HAL_VERSION_STRING +# include "mbed-hal/us_ticker.h" +#else +# include "us_ticker.h" +#endif // only one callback is active at any given time static volatile utest_v1_harness_callback_t minimal_callback; static volatile utest_v1_harness_callback_t ticker_callback; From d19f51fbb965daae9c1df2c26178d49d4f7e3a47 Mon Sep 17 00:00:00 2001 From: Martin Kojtal Date: Mon, 18 Apr 2016 09:43:11 +0100 Subject: [PATCH 86/88] Shim - mbed SDK uses us ticker by default mbed SDK defines ``__MBED__`` macro (unique, not valid for yotta), this should turn on us ticker by default, as that one is available for mbed SDK targets. --- "frameworks\\utest/utest/shim.h" | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git "a/frameworks\\utest/utest/shim.h" "b/frameworks\\utest/utest/shim.h" index 1cec14a9fb..78a6f6048a 100644 --- "a/frameworks\\utest/utest/shim.h" +++ "b/frameworks\\utest/utest/shim.h" @@ -59,7 +59,11 @@ # define UTEST_SHIM_SCHEDULER_USE_MINAR UTEST_MINAR_AVAILABLE # endif # ifndef UTEST_SHIM_SCHEDULER_USE_US_TICKER -# define UTEST_SHIM_SCHEDULER_USE_US_TICKER 0 +# ifdef __MBED__ +# define UTEST_SHIM_SCHEDULER_USE_US_TICKER 1 +# else +# define UTEST_SHIM_SCHEDULER_USE_US_TICKER 0 +# endif # endif #endif // YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER From 8c9ebde80110e314dc1d17d927809b173151ecb6 Mon Sep 17 00:00:00 2001 From: Martin Kojtal Date: Thu, 28 Apr 2016 15:24:27 -0500 Subject: [PATCH 87/88] utest - add mbed shim layer --- frameworks/utest/mbed-utest-shim.cpp | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 frameworks/utest/mbed-utest-shim.cpp diff --git a/frameworks/utest/mbed-utest-shim.cpp b/frameworks/utest/mbed-utest-shim.cpp new file mode 100644 index 0000000000..db664882e8 --- /dev/null +++ b/frameworks/utest/mbed-utest-shim.cpp @@ -0,0 +1,32 @@ + +/* mbed Microcontroller Library + * Copyright (c) 2013-2016 ARM Limited + * + * 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 "utest/utest.h" + +using namespace utest::v1; + +void utest_v1_enter_critical_section(void) +{ + // will replaced by CriticalSectionLock + __disable_irq(); +} + +void utest_v1_leave_critical_section(void) +{ + __enable_irq(); +} From 2c3ad57a326a45a3b6207c1111db5f76c8e38b53 Mon Sep 17 00:00:00 2001 From: Martin Kojtal Date: Thu, 28 Apr 2016 15:58:08 -0500 Subject: [PATCH 88/88] utest - fix us ticker header file name --- frameworks/utest/source/shim.cpp | 138 +++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 frameworks/utest/source/shim.cpp diff --git a/frameworks/utest/source/shim.cpp b/frameworks/utest/source/shim.cpp new file mode 100644 index 0000000000..4065a16516 --- /dev/null +++ b/frameworks/utest/source/shim.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** + * Copyright (c) 2015, 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 "utest/shim.h" + +#if UTEST_SHIM_SCHEDULER_USE_MINAR +#include "minar/minar.h" + +static int32_t utest_minar_init() +{ + return 0; +} +static void *utest_minar_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) +{ + void *handle = minar::Scheduler::postCallback(callback).delay(minar::milliseconds(delay_ms)).getHandle(); + return handle; +} +static int32_t utest_minar_cancel(void *handle) +{ + int32_t ret = minar::Scheduler::cancelCallback(handle); + return ret; +} +static int32_t utest_minar_run() +{ + return 0; +} +extern "C" { +static const utest_v1_scheduler_t utest_v1_scheduler = +{ + utest_minar_init, + utest_minar_post, + utest_minar_cancel, + utest_minar_run +}; +utest_v1_scheduler_t utest_v1_get_scheduler() +{ + return utest_v1_scheduler; +} +} + +#elif UTEST_SHIM_SCHEDULER_USE_US_TICKER +#ifdef YOTTA_MBED_HAL_VERSION_STRING +# include "mbed-hal/us_ticker_api.h" +#else +# include "us_ticker_api.h" +#endif +// only one callback is active at any given time +static volatile utest_v1_harness_callback_t minimal_callback; +static volatile utest_v1_harness_callback_t ticker_callback; +static const ticker_data_t *ticker_data; +static ticker_event_t ticker_event; + +static void ticker_handler(uint32_t) +{ + // printf("\t\t>>> Ticker callback fired for %p.\n", ticker_callback); + minimal_callback = ticker_callback; +} + +static int32_t utest_us_ticker_init() +{ + ticker_data = get_us_ticker_data(); + ticker_set_handler(ticker_data, ticker_handler); + return 0; +} +static void *utest_us_ticker_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms) +{ + // printf("\t\t>>> Schedule %p with %ums delay => %p.\n", callback, (unsigned int)delay_ms, (void*)1); + if (delay_ms) { + ticker_callback = callback; + // fire the interrupt in 1000us * delay_ms + ticker_insert_event(ticker_data, &ticker_event, ticker_read(ticker_data) + delay_ms * 1000, 0); + } else { + minimal_callback = callback; + } + + // return a bogus handle + return (void*)1; +} +static int32_t utest_us_ticker_cancel(void *handle) +{ + // printf("\t\t>>> Cancel %p => %u\n", handle, (unsigned int)0); + (void) handle; + ticker_remove_event(ticker_data, &ticker_event); + return 0; +} +static int32_t utest_us_ticker_run() +{ + while(1) + { + // check if a new callback has been set + if (minimal_callback) + { + // printf("\t\t>>> Firing callback %p\n", minimal_callback); + // copy the callback + utest_v1_harness_callback_t callback = minimal_callback; + // reset the shared callback + minimal_callback = NULL; + // execute the copied callback + callback(); + } + } + return 0; +} +extern "C" { +static const utest_v1_scheduler_t utest_v1_scheduler = +{ + utest_us_ticker_init, + utest_us_ticker_post, + utest_us_ticker_cancel, + utest_us_ticker_run +}; +utest_v1_scheduler_t utest_v1_get_scheduler() +{ + return utest_v1_scheduler; +} +} +#endif + +#ifdef YOTTA_CORE_UTIL_VERSION_STRING +// their functionality is implemented using the CriticalSectionLock class +void utest_v1_enter_critical_section(void) {} +void utest_v1_leave_critical_section(void) {} +#endif