Add support for throwing RAII destructors 56/110056/7
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Thu, 12 Jan 2017 11:16:26 +0000 (12:16 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 17 Mar 2017 17:01:45 +0000 (18:01 +0100)
When a test finishes or fails the stack is unwinded some of such objects'
destructors still perform actions that may report an error/throw an exception.
If we just surround these actions with try/catch block we'll lose information
about errors in these destructors. If we let destructors throw it may lead to
program termination (unhandled exception during stack unwind caused by another
exception).

To prevent program termination and still get the information about errors in
destructors surround the throwing code in your RAII object destructor with
SafeCleanup::run.

Tests for cleanup exception handling are added and can be executed with:
cleanup_test.sh

Change-Id: Id4e257aadea9b18fe890c89d8f182082a7f191a3

packaging/security-tests.spec
src/framework/config.cmake
src/framework/include/dpl/test/safe_cleanup.h [new file with mode: 0644]
src/framework/src/safe_cleanup.cpp [new file with mode: 0644]
src/framework/src/test_runner.cpp
src/framework/src/test_runner_child.cpp
tests/CMakeLists.txt
tests/cleanup/CMakeLists.txt [new file with mode: 0644]
tests/cleanup/cleanup_test.sh [new file with mode: 0755]
tests/cleanup/expected_results.txt [new file with mode: 0644]
tests/cleanup/test_cases_cleanup.cpp [new file with mode: 0644]

index d9319fa..4efc6b0 100644 (file)
@@ -30,6 +30,7 @@ BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(libgum) >= 1.0.5
 Requires: perf
 Requires: gdb
+Requires: diffutils
 
 %global ckm_test_dir %{?TZ_SYS_SHARE:%TZ_SYS_SHARE/ckm-test/}%{!?TZ_SYS_SHARE:/usr/share/ckm-test/}
 %global ckm_rw_data_dir %{?TZ_SYS_DATA:%TZ_SYS_DATA/ckm/}%{!?TZ_SYS_DATA:/opt/data/ckm/}
@@ -100,8 +101,12 @@ echo "security-tests postinst done ..."
 /usr/lib/security-tests/cynara-tests/plugins/multiple-policy/*
 /usr/lib/security-tests/cynara-tests/plugins/test-agent/*
 /usr/bin/security-tests-inner-test
+/usr/bin/security-tests-cleanup-test
+/usr/bin/cleanup_test.sh
 /usr/bin/libwebappenc-tests
 %{_prefix}/share/yaca-test
+%dir %{_prefix}/share/security-tests-cleanup-test
+%{_prefix}/share/security-tests-cleanup-test/*
 
 %postun
 id -u security_test_user 1>/dev/null 2>&1 && gum-utils -o -d --uid=`id -u security_test_user`
index 791e546..374d323 100644 (file)
@@ -41,6 +41,7 @@ SET(DPL_FRAMEWORK_TEST_SOURCES
     ${PROJECT_SOURCE_DIR}/src/framework/src/test_runner_child.cpp
     ${PROJECT_SOURCE_DIR}/src/framework/src/test_runner.cpp
     ${PROJECT_SOURCE_DIR}/src/framework/src/test_runner_multiprocess.cpp
+    ${PROJECT_SOURCE_DIR}/src/framework/src/safe_cleanup.cpp
 )
 
 IF(DPL_WITH_DLOG)
diff --git a/src/framework/include/dpl/test/safe_cleanup.h b/src/framework/include/dpl/test/safe_cleanup.h
new file mode 100644 (file)
index 0000000..2aca009
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/*
+ * @file       safe_cleanup.h
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#pragma once
+
+#include <string>
+#include <functional>
+
+/*
+ * Utility that is intended for use in destructors of so called "scoped objects"
+ * or RAII objects. When a test finishes or fails the stack is unwinded some of
+ * such objects' destructors still perform actions that may report an
+ * error/throw an exception. If we just surround these actions with try/catch
+ * block we'll lose information about errors in these destructors. If we let
+ * destructors throw it may lead to program termination (unhandled exception
+ * during stack unwind caused by another exception).
+ *
+ * To prevent program termination and still get the information about errors in
+ * destructors surround the throwing code in your RAII object destructor like
+ * this:
+ *
+ * struct ThrowingRAII {
+ *     ~ThrowingRAII() {
+ *         SafeCleanup::run([]{
+ *             cleanup_code_that_may_throw();
+ *         });
+ *     }
+ * };
+ *
+ * Framework will take care of displaying all exceptions catched this way after
+ * test case is finished.
+ */
+namespace SafeCleanup {
+
+/*
+ * Remove all collected exceptions from the internal list. To be used by
+ * framework only. Function is NOT thread safe.
+ */
+void reset();
+
+/*
+ * Dump exceptions collected during test. To be used by framework only. Function
+ * is NOT thread safe.
+ */
+std::string dump();
+
+/**
+ * Run cleanup code that may throw an exception. Function is thread safe.
+ */
+void run(const std::function<void()>& snippet);
+
+} // namespace SafeCleanup
diff --git a/src/framework/src/safe_cleanup.cpp b/src/framework/src/safe_cleanup.cpp
new file mode 100644 (file)
index 0000000..cfdbedb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/*
+ * @file       safe_cleanup.cpp
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#include <dpl/test/safe_cleanup.h>
+
+#include <sstream>
+#include <exception>
+#include <vector>
+#include <mutex>
+
+#include <dpl/test/test_failed.h>
+#include <dpl/gdbbacktrace.h>
+
+namespace {
+
+std::vector<std::string> g_errors;
+std::mutex g_mutex;
+
+void pushError(const std::string& msg)
+{
+    std::lock_guard<std::mutex> guard(g_mutex);
+    g_errors.push_back(msg);
+}
+
+} // anonymous namespace
+
+void SafeCleanup::reset()
+{
+    g_errors.clear();
+}
+std::string SafeCleanup::dump()
+{
+    std::ostringstream os;
+    for(const auto& e : g_errors)
+        os << e << std::endl;
+    g_errors.clear();
+
+    return os.str();
+}
+
+void SafeCleanup::run(const std::function<void()>& snippet)
+{
+    try {
+        snippet();
+    } catch (const DPL::Test::TestFailed& e) {
+        pushError(e.GetMessage());
+    } catch (...) {
+        std::ostringstream is;
+        is << "Unknown exception:" << DPL::gdbbacktrace();
+        pushError(is.str());
+    }
+}
index f4a625f..ec67029 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #include <dpl/test/test_ignored.h>
 #include <dpl/test/test_runner.h>
 #include <dpl/test/test_results_collector.h>
+#include <dpl/test/safe_cleanup.h>
 #include <dpl/exception.h>
 #include <dpl/scoped_free.h>
 #include <dpl/log/log.h>
@@ -244,6 +245,8 @@ void TestRunner::RunTestCase(TestCasePtr testCase)
         return;
     }
 
+    SafeCleanup::reset();
+
     std::string testReason;
     TestResult::FailStatus testStatus = TryCatch(std::bind(&TestCase::Test, testCase),
                                                  testReason);
@@ -253,12 +256,19 @@ void TestRunner::RunTestCase(TestCasePtr testCase)
                                                    finishReason);
     finishReason = getConcatedFailReason(finishReason);
 
+    std::string cleanupReason = SafeCleanup::dump();
+
     switch (finishStatus) {
         case TestResult::FailStatus::FAILED:
             testStatus = TestResult::FailStatus::FAILED;
             if (!testReason.empty())
                 testReason += "\n";
             testReason += finishReason;
+            if (!cleanupReason.empty()) {
+                if (!testReason.empty())
+                    testReason += "\n";
+                testReason += cleanupReason;
+            }
             break;
         case TestResult::FailStatus::IGNORED:
             if (testStatus == TestResult::FailStatus::NONE)
@@ -267,6 +277,13 @@ void TestRunner::RunTestCase(TestCasePtr testCase)
                 testReason += "\n";
             testReason += finishReason;
         case TestResult::FailStatus::NONE:
+            if (!cleanupReason.empty()) {
+                if (!testReason.empty())
+                    testReason += "\n";
+                testReason += cleanupReason;
+                if (testStatus == TestResult::FailStatus::NONE)
+                    testStatus = TestResult::FailStatus::FAILED;
+            }
             break;
         default:
             Assert(false && "Unhandled fail status");
index c0cd93f..1516334 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2013-2017 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
 #include <dpl/test/test_runner.h>
 #include <dpl/test/test_runner_child.h>
 #include <dpl/test/test_results_collector.h>
+#include <dpl/test/safe_cleanup.h>
 #include <dpl/binary_queue.h>
 #include <dpl/exception.h>
 #include <dpl/scoped_free.h>
@@ -349,6 +350,8 @@ void RunChildProc(const std::function<void(void)> &testFunc)
 
         pipe.setUsage(PipeWrapper::WRITEONLY);
 
+        SafeCleanup::reset();
+
         int code;
         std::string msg;
         switch (TryCatch(testFunc, msg)) {
@@ -365,6 +368,18 @@ void RunChildProc(const std::function<void(void)> &testFunc)
                 Assert(false && "Unhandled fail status");
         }
 
+        std::string cleanup;
+        if (code != CHILD_TEST_IGNORED)
+        {
+            cleanup = SafeCleanup::dump();
+            if (!cleanup.empty()) {
+                code = CHILD_TEST_FAIL;
+                if (!msg.empty())
+                    msg += '\n';
+                msg += cleanup;
+            }
+        }
+
         if (allowLogs) {
             closeOutput();
         }
index b1b4d87..37ad4de 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
 #
 #    Licensed under the Apache License, Version 2.0 (the "License");
 #    you may not use this file except in compliance with the License.
@@ -61,3 +61,5 @@ INSTALL(TARGETS ${INNER_TARGET_TEST}
                 WORLD_READ
                 WORLD_EXECUTE
     )
+
+ADD_SUBDIRECTORY(cleanup)
\ No newline at end of file
diff --git a/tests/cleanup/CMakeLists.txt b/tests/cleanup/CMakeLists.txt
new file mode 100644 (file)
index 0000000..03b7b2d
--- /dev/null
@@ -0,0 +1,64 @@
+# Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    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.
+#
+
+cmake_minimum_required(VERSION 2.8.3)
+
+SET(CLEANUP_TARGET_TEST "security-tests-cleanup-test")
+
+#files to compile
+SET(CLEANUP_TARGET_TEST_SOURCES
+    ${PROJECT_SOURCE_DIR}/tests/cleanup/test_cases_cleanup.cpp
+    )
+
+#header directories
+INCLUDE_DIRECTORIES(
+    ${PROJECT_SOURCE_DIR}/src/framework/include/
+    ${PROJECT_SOURCE_DIR}/src/
+    )
+
+#output format
+ADD_EXECUTABLE(${CLEANUP_TARGET_TEST} ${CLEANUP_TARGET_TEST_SOURCES})
+
+#linker directories
+TARGET_LINK_LIBRARIES(${CLEANUP_TARGET_TEST}
+    tests-common
+    dpl-test-framework
+    )
+
+#place for output file
+INSTALL(TARGETS ${CLEANUP_TARGET_TEST}
+    DESTINATION /usr/bin
+    PERMISSIONS OWNER_READ
+                OWNER_WRITE
+                OWNER_EXECUTE
+                GROUP_READ
+                GROUP_EXECUTE
+                WORLD_READ
+                WORLD_EXECUTE
+    )
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cleanup_test.sh
+    DESTINATION /usr/bin
+    PERMISSIONS OWNER_READ
+                OWNER_WRITE
+                OWNER_EXECUTE
+                GROUP_READ
+                GROUP_EXECUTE
+                WORLD_READ
+                WORLD_EXECUTE
+    )
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/expected_results.txt
+    DESTINATION  "${SHARE_INSTALL_PREFIX}/${CLEANUP_TARGET_TEST}/")
diff --git a/tests/cleanup/cleanup_test.sh b/tests/cleanup/cleanup_test.sh
new file mode 100755 (executable)
index 0000000..9582d4b
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+EXPECTED=/usr/share/security-tests-cleanup-test/expected_results.txt
+OUTPUT=/tmp/cleanup_test_output.txt
+
+>| $OUTPUT
+for TEST in `security-tests-cleanup-test --list | cut -d':' -f3`
+do
+    echo $TEST | tee -a $OUTPUT
+    security-tests-cleanup-test --regexp=$TEST 2>/dev/null | grep "Assertion failed\|Unknown exception\|Ignored test" | rev | cut -d' ' -f1,2 | rev | sed 's/\x1B\[0;33m//' |tee -a $OUTPUT
+    echo | tee -a $OUTPUT
+done
+
+diff $EXPECTED $OUTPUT && echo "[SUCCESS] Result matches expectations" && exit
+
+echo "[FAILED] Result is different than expected ($EXPECTED != $OUTPUT)"
+exit 1
diff --git a/tests/cleanup/expected_results.txt b/tests/cleanup/expected_results.txt
new file mode 100644 (file)
index 0000000..9e4ca78
--- /dev/null
@@ -0,0 +1,82 @@
+cl0010_same_process_no_fixture_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+
+cl0020_same_process_no_fixture_fail
+[test] DPL::Test::TestFailed
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+
+cl0030_same_process_fixture_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0040_same_process_fixture_fail
+[test] DPL::Test::TestFailed
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0050_same_process_multiple_fixtures_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture2] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0060_same_process_test_per_fixture_success_fixture1
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0060_same_process_test_per_fixture_success_fixture2
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture2] DPL::Test::TestFailed
+Unknown exception:
+
+cl0070_same_process_fixture_ignored
+Ignored test
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0110_child_no_fixture_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+
+cl0120_child_no_fixture_fail
+[test] DPL::Test::TestFailed
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+
+cl0130_child_fixture_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0140_child_fixture_fail
+[test] DPL::Test::TestFailed
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0150_child_multiple_fixtures_success
+[dtor] DPL::Test::TestFailed
+Unknown exception:
+[fixture2] DPL::Test::TestFailed
+Unknown exception:
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
+cl0170_child_fixture_ignored
+Ignored test
+[fixture] DPL::Test::TestFailed
+Unknown exception:
+
diff --git a/tests/cleanup/test_cases_cleanup.cpp b/tests/cleanup/test_cases_cleanup.cpp
new file mode 100644 (file)
index 0000000..f52f749
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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
+ */
+/*
+ * @file       test_cases_cleanup.cpp
+ * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
+ * @version    1.0
+ */
+
+#include <exception>
+#include <sstream>
+#include <string>
+
+#include <dpl/test/safe_cleanup.h>
+
+#include <dpl/test/test_runner.h>
+#include <dpl/test/test_runner_child.h>
+
+namespace {
+
+const std::string FAIL_MSG = "[test] DPL::Test::TestFailed";
+const std::string DTOR_TAG = "[dtor]";
+
+void runnerFail(const std::string& tag) {
+    std::ostringstream os;
+    os << tag << " DPL::Test::TestFailed";
+    RUNNER_FAIL_MSG(os.str());
+}
+
+void runtimeException() {
+    throw std::runtime_error("");
+}
+
+struct ScopedObject {
+    explicit ScopedObject(const std::string& tag = DTOR_TAG) : m_tag(tag) {}
+    ~ScopedObject() {
+        SafeCleanup::run([this]{
+            runnerFail(m_tag);
+        });
+        SafeCleanup::run([]{
+            runtimeException();
+        });
+    }
+private:
+    std::string m_tag;
+};
+
+struct CleanupFixture {
+    void init(const std::string&)
+    {}
+    void finish()
+    {
+        ScopedObject so("[fixture]");
+    }
+
+    static std::string suffix() { return "_fixture1"; }
+};
+
+struct CleanupFixture2 : public CleanupFixture {
+    static std::string suffix() { return "_fixture2"; }
+
+    void finish()
+    {
+        ScopedObject so("[fixture2]");
+    }
+};
+
+} // anonymous namespace
+
+int main(int argc, char *argv[])
+{
+    int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);
+    return status;
+}
+
+/*
+ *  These tests are supposed to fail in a specific manner. Please see the
+ *  description or use cleanup_test.sh.
+ */
+RUNNER_TEST_GROUP_INIT(CLEANUP)
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0010_same_process_no_fixture_success)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - [test] DPL::Test::TestFailed
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0020_same_process_no_fixture_fail)
+{
+    ScopedObject so;
+
+    RUNNER_FAIL_MSG(FAIL_MSG);
+}
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0030_same_process_fixture_success, CleanupFixture)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - [test] DPL::Test::TestFailed
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0040_same_process_fixture_fail, CleanupFixture)
+{
+    ScopedObject so;
+
+    RUNNER_FAIL_MSG(FAIL_MSG);
+}
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture2] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0050_same_process_multiple_fixtures_success, CleanupFixture, CleanupFixture2)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result (CleanupFixture):
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ *
+ * Expected result (CleanupFixture2):
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture2] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST_MULTIPLE(cl0060_same_process_test_per_fixture_success, CleanupFixture, CleanupFixture2)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - Ignored test
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_TEST(cl0070_same_process_fixture_ignored, CleanupFixture)
+{
+    RUNNER_IGNORED_MSG("Ignored test");
+
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0110_child_no_fixture_success)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - [test] DPL::Test::TestFailed
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0120_child_no_fixture_fail)
+{
+    ScopedObject so;
+
+    RUNNER_FAIL_MSG(FAIL_MSG);
+}
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0130_child_fixture_success, CleanupFixture)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - [test] DPL::Test::TestFailed
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0140_child_fixture_fail, CleanupFixture)
+{
+    ScopedObject so;
+
+    RUNNER_FAIL_MSG(FAIL_MSG);
+}
+
+/*
+ * Expected result:
+ * - [dtor] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture2] DPL::Test::TestFailed
+ * - Unknown exception
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0150_child_multiple_fixtures_success, CleanupFixture, CleanupFixture2)
+{
+    ScopedObject so;
+}
+
+/*
+ * Expected result:
+ * - Ignored test
+ * - [fixture] DPL::Test::TestFailed
+ * - Unknown exception
+ */
+RUNNER_CHILD_TEST(cl0170_child_fixture_ignored, CleanupFixture)
+{
+    RUNNER_IGNORED_MSG("Ignored test");
+
+    ScopedObject so;
+}