|
From: Kouhei S. <nul...@cl...> - 2014-01-26 11:52:18
|
Kouhei Sutou 2014-01-26 20:51:53 +0900 (Sun, 26 Jan 2014) New Revision: 165ef6a08426e637764164e2bf87c46ceb1bfafb https://github.com/clear-code/cutter/commit/165ef6a08426e637764164e2bf87c46ceb1bfafb Message: c++: support calling destructor on stack when an assertion is failed GitHub: fix #10 This change is based on patch by Kazuhiro Yamato. Thanks!!! Modified files: cppcutter/cppcut-iterated-test.cpp cppcutter/cppcut-test-invoke.cpp cppcutter/cppcut-test-invoke.h cppcutter/cppcut-test.cpp cutter/cut-test-context.c cutter/cut-test.c cutter/cut-test.h test/cppcutter/test-cppcut-iterated-test.cpp test/cppcutter/test-cppcut-test.cpp Modified: cppcutter/cppcut-iterated-test.cpp (+14 -1) =================================================================== --- cppcutter/cppcut-iterated-test.cpp 2014-01-26 19:36:49 +0900 (fbcf336) +++ cppcutter/cppcut-iterated-test.cpp 2014-01-26 20:51:53 +0900 (96bff24) @@ -28,6 +28,9 @@ G_BEGIN_DECLS G_DEFINE_TYPE(CppCutIteratedTest, cppcut_iterated_test, CUT_TYPE_ITERATED_TEST) +static void long_jump (CutTest *test, + jmp_buf *jump_buffer, + gint value); static void invoke (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); @@ -39,7 +42,8 @@ cppcut_iterated_test_class_init (CppCutIteratedTestClass *klass) cut_test_class = CUT_TEST_CLASS(klass); - cut_test_class->invoke = invoke; + cut_test_class->long_jump = long_jump; + cut_test_class->invoke = invoke; } static void @@ -64,6 +68,15 @@ cppcut_iterated_test_new (const gchar *name, } static void +long_jump (CutTest *test, jmp_buf *jump_buffer, gint value) +{ + CutTestClass *cut_test_class; + + cut_test_class = CUT_TEST_CLASS(cppcut_iterated_test_parent_class); + cut::test::long_jump(cut_test_class, test, jump_buffer, value); +} + +static void invoke (CutTest *test, CutTestContext *test_context, CutRunContext *run_context) { CutTestClass *cut_test_class; Modified: cppcutter/cppcut-test-invoke.cpp (+62 -9) =================================================================== --- cppcutter/cppcut-test-invoke.cpp 2014-01-26 19:36:49 +0900 (0cc04ed) +++ cppcutter/cppcut-test-invoke.cpp 2014-01-26 20:51:53 +0900 (c6414bd) @@ -29,25 +29,78 @@ #include <cutter.h> +struct LongJumpArguments { + jmp_buf *jump_buffer; + gint value; +}; + +struct CppCutTestTerminated { + LongJumpArguments long_jump_arguments; + + CppCutTestTerminated (jmp_buf *jump_buffer, gint value) + { + long_jump_arguments.jump_buffer = jump_buffer; + long_jump_arguments.value = value; + } +}; + +static const gchar *invoking_data_key = "cppcut-test-invoking"; + +void +cut::test::long_jump (CutTestClass *cut_test_class, + CutTest *test, + jmp_buf *jump_buffer, + gint value) +{ + gpointer invoking_data; + gboolean *invoking; + + invoking_data = g_object_get_data(G_OBJECT(test), invoking_data_key); + invoking = static_cast<gboolean *>(invoking_data); + if (invoking && *invoking && + cut_test_is_own_jump_buffer(test, jump_buffer)) { + throw CppCutTestTerminated(jump_buffer, value); + } else { + cut_test_class->long_jump(test, jump_buffer, value); + } +} + void cut::test::invoke (CutTestClass *cut_test_class, CutTest *test, CutTestContext *test_context, CutRunContext *run_context) { + LongJumpArguments long_jump_arguments; + bool is_terminated = false; + const gchar *terminate_message = NULL; + gboolean invoking = TRUE; + + g_object_set_data(G_OBJECT(test), invoking_data_key, &invoking); try { cut_test_class->invoke(test, test_context, run_context); + } catch (const CppCutTestTerminated &terminated) { + is_terminated = true; + long_jump_arguments = terminated.long_jump_arguments; } catch (const std::exception &exception) { - const gchar *message; - message = cut_take_printf("Unhandled C++ standard exception is thrown: " - "<%s>: %s", - typeid(exception).name(), - exception.what()); - cut_test_terminate(ERROR, message); + terminate_message = + cut_take_printf("Unhandled C++ standard exception is thrown: " + "<%s>: %s", + typeid(exception).name(), + exception.what()); } catch (...) { - const gchar *message; - message = "Unhandled C++ non-standard exception is thrown"; - cut_test_terminate(ERROR, message); + terminate_message = "Unhandled C++ non-standard exception is thrown"; + } + g_object_steal_data(G_OBJECT(test), invoking_data_key); + + if (is_terminated) { + cut_test_class->long_jump(test, + long_jump_arguments.jump_buffer, + long_jump_arguments.value); + } + + if (terminate_message) { + cut_test_terminate(ERROR, terminate_message); } } Modified: cppcutter/cppcut-test-invoke.h (+8 -4) =================================================================== --- cppcutter/cppcut-test-invoke.h 2014-01-26 19:36:49 +0900 (35d5cf0) +++ cppcutter/cppcut-test-invoke.h 2014-01-26 20:51:53 +0900 (78ad069) @@ -26,10 +26,14 @@ namespace cut { namespace test { - void invoke (CutTestClass *cut_test_class, - CutTest *test, - CutTestContext *test_context, - CutRunContext *run_context); + void long_jump (CutTestClass *cut_test_class, + CutTest *test, + jmp_buf *jump_buffer, + gint value); + void invoke (CutTestClass *cut_test_class, + CutTest *test, + CutTestContext *test_context, + CutRunContext *run_context); } } Modified: cppcutter/cppcut-test.cpp (+13 -1) =================================================================== --- cppcutter/cppcut-test.cpp 2014-01-26 19:36:49 +0900 (f13d33a) +++ cppcutter/cppcut-test.cpp 2014-01-26 20:51:53 +0900 (fce833d) @@ -30,6 +30,9 @@ G_BEGIN_DECLS G_DEFINE_TYPE(CppCutTest, cppcut_test, CUT_TYPE_TEST) +static void long_jump (CutTest *test, + jmp_buf *jump_buffer, + gint value); static void invoke (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); @@ -41,7 +44,8 @@ cppcut_test_class_init (CppCutTestClass *klass) cut_test_class = CUT_TEST_CLASS(klass); - cut_test_class->invoke = invoke; + cut_test_class->long_jump = long_jump; + cut_test_class->invoke = invoke; } static void @@ -63,6 +67,14 @@ cppcut_test_new (const gchar *name, CutTestFunction function) } static void +long_jump (CutTest *test, jmp_buf *jump_buffer, gint value) +{ + CutTestClass *cut_test_class = CUT_TEST_CLASS(cppcut_test_parent_class); + + cut::test::long_jump(cut_test_class, test, jump_buffer, value); +} + +static void invoke (CutTest *test, CutTestContext *test_context, CutRunContext *run_context) { CutTestClass *cut_test_class = CUT_TEST_CLASS(cppcut_test_parent_class); Modified: cutter/cut-test-context.c (+7 -1) =================================================================== --- cutter/cut-test-context.c 2014-01-26 19:36:49 +0900 (d06200c) +++ cutter/cut-test-context.c 2014-01-26 20:51:53 +0900 (5a25baa) @@ -855,7 +855,13 @@ cut_test_context_long_jump (CutTestContext *context) } if (cut_test_context_in_user_message_jump(context) || same_thread_p) { - longjmp(*(priv->jump_buffer), CUT_SIGNAL_EXPLICIT_JUMP); + if (priv->test) { + cut_test_long_jump(priv->test, + priv->jump_buffer, + CUT_SIGNAL_EXPLICIT_JUMP); + } else { + longjmp(*(priv->jump_buffer), CUT_SIGNAL_EXPLICIT_JUMP); + } } else { if (priv->parent && cut_test_context_is_failed(context)) { cut_test_context_set_failed(priv->parent, TRUE); Modified: cutter/cut-test.c (+34 -1) =================================================================== --- cutter/cut-test.c 2014-01-26 19:36:49 +0900 (a8468da) +++ cutter/cut-test.c 2014-01-26 20:51:53 +0900 (d9ef5d9) @@ -1,6 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Copyright (C) 2007-2014 Kouhei Sutou <ko...@cl...> + * Copyright (C) 2014 Kazuhiro Yamato <kz...@gm...> * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -54,6 +55,7 @@ struct _CutTestPrivate gdouble elapsed; GHashTable *attributes; gchar *base_directory; + jmp_buf *jump_buffer; }; enum @@ -101,6 +103,9 @@ static void set_elapsed (CutTest *test, gdouble elapsed); static gboolean run (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); +static void long_jump (CutTest *test, + jmp_buf *jump_buffer, + gint value); static gboolean is_available (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); @@ -128,6 +133,7 @@ cut_test_class_init (CutTestClass *klass) klass->get_elapsed = get_elapsed; klass->set_elapsed = set_elapsed; klass->run = run; + klass->long_jump = long_jump; klass->is_available = is_available; klass->invoke = invoke; klass->emit_result_signal = emit_result_signal; @@ -274,6 +280,7 @@ cut_test_init (CutTest *test) priv->elapsed = -1.0; priv->attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + priv->jump_buffer = NULL; } static void @@ -440,8 +447,12 @@ run (CutTest *test, CutTestContext *test_context, CutRunContext *run_context) priv = CUT_TEST_GET_PRIVATE(test); klass = CUT_TEST_GET_CLASS(test); - if (!klass->is_available(test, test_context, run_context)) + priv->jump_buffer = &jump_buffer; + + if (!klass->is_available(test, test_context, run_context)) { + priv->jump_buffer = NULL; return FALSE; + } test_case = cut_test_context_get_test_case(test_context); test_iterator = cut_test_context_get_test_iterator(test_context); @@ -508,9 +519,17 @@ run (CutTest *test, CutTestContext *test_context, CutRunContext *run_context) g_signal_emit_by_name(test, "complete", test_context, success); + priv->jump_buffer = NULL; + return success; } +static void +long_jump (CutTest *test, jmp_buf *jump_buffer, gint value) +{ + longjmp(*jump_buffer, value); +} + gboolean cut_test_run (CutTest *test, CutTestContext *test_context, CutRunContext *run_context) @@ -518,6 +537,20 @@ cut_test_run (CutTest *test, CutTestContext *test_context, return CUT_TEST_GET_CLASS(test)->run(test, test_context, run_context); } +void +cut_test_long_jump (CutTest *test, jmp_buf *jump_buffer, gint value) +{ + return CUT_TEST_GET_CLASS(test)->long_jump(test, jump_buffer, value); +} + +gboolean +cut_test_is_own_jump_buffer (CutTest *test, jmp_buf *jump_buffer) +{ + CutTestPrivate *priv = CUT_TEST_GET_PRIVATE(test); + + return priv->jump_buffer == jump_buffer; +} + const gchar * cut_test_get_name (CutTest *test) { Modified: cutter/cut-test.h (+12 -1) =================================================================== --- cutter/cut-test.h 2014-01-26 19:36:49 +0900 (cda73ef) +++ cutter/cut-test.h 2014-01-26 20:51:53 +0900 (32f311a) @@ -1,6 +1,6 @@ /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* - * Copyright (C) 2007-2009 Kouhei Sutou <ko...@co...> + * Copyright (C) 2007-2014 Kouhei Sutou <ko...@cl...> * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -20,6 +20,8 @@ #ifndef __CUT_TEST_H__ #define __CUT_TEST_H__ +#include <setjmp.h> + #include <glib-object.h> #include <cutter/cut-private.h> @@ -87,6 +89,9 @@ struct _CutTestClass gboolean (*run) (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); + void (*long_jump) (CutTest *test, + jmp_buf *jump_buffer, + gint value); gboolean (*is_available) (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); @@ -108,6 +113,12 @@ gboolean cut_test_run (CutTest *test, CutTestContext *test_context, CutRunContext *run_context); +void cut_test_long_jump (CutTest *test, + jmp_buf *jump_buffer, + gint value); +gboolean cut_test_is_own_jump_buffer (CutTest *test, + jmp_buf *jump_buffer); + const gchar *cut_test_get_name (CutTest *test); void cut_test_set_name (CutTest *test, const gchar *name); Modified: test/cppcutter/test-cppcut-iterated-test.cpp (+32 -0) =================================================================== --- test/cppcutter/test-cppcut-iterated-test.cpp 2014-01-26 19:36:49 +0900 (0d2d687) +++ test/cppcutter/test-cppcut-iterated-test.cpp 2014-01-26 20:51:53 +0900 (55ef541) @@ -33,6 +33,7 @@ namespace cppcut_iterated_test CutRunContext *run_context; CutTestContext *test_context; CutTestResult *test_result; + gint n_destructor_calls; static gboolean run (void) @@ -60,6 +61,7 @@ namespace cppcut_iterated_test run_context = NULL; test_context = NULL; test_result = NULL; + n_destructor_calls = 0; } void @@ -152,6 +154,36 @@ namespace cppcut_iterated_test "void cppcut_test::stub_not_standard_exception()", NULL); } + + class DestructorCallCounter + { + public: + ~DestructorCallCounter() + { + n_destructor_calls++; + } + }; + + static void + stub_unwind_stack (gconstpointer data) + { + DestructorCallCounter counter; + + cut_fail("return from the test"); + } + + void + test_unwind_stack (void) + { + iterated_test = cppcut_iterated_test_new("unwind stack test", + stub_unwind_stack, + test_data); + cut_assert_not_null(iterated_test); + + cut_assert_false(run()); + cut_assert_test_result_summary(run_context, 1, 0, 0, 1, 0, 0, 0, 0); + cut_assert_equal_int(1, n_destructor_calls); + } } /* Modified: test/cppcutter/test-cppcut-test.cpp (+30 -11) =================================================================== --- test/cppcutter/test-cppcut-test.cpp 2014-01-26 19:36:49 +0900 (22a984d) +++ test/cppcutter/test-cppcut-test.cpp 2014-01-26 20:51:53 +0900 (3862137) @@ -27,22 +27,13 @@ #include "../lib/cuttest-assertions.h" -#define MARK_FAIL(assertion) do \ -{ \ - fail_line = __LINE__; \ - assertion; \ -} while (0) - -#define FAIL_LOCATION (cut_take_printf("%s:%d", __FILE__, fail_line)) - namespace cppcut_test { CppCutTest *test; CutRunContext *run_context; CutTestContext *test_context; CutTestResult *test_result; - - gint fail_line; + gint n_destructor_calls; static gboolean run (void) @@ -69,7 +60,7 @@ namespace cppcut_test test_context = NULL; test_result = NULL; - fail_line = 0; + n_destructor_calls = 0; } void @@ -157,6 +148,34 @@ namespace cppcut_test "void cppcut_test::stub_not_standard_exception()", NULL); } + + class DestructorCallCounter + { + public: + ~DestructorCallCounter() + { + n_destructor_calls++; + } + }; + + static void + stub_unwind_stack (void) + { + DestructorCallCounter counter; + + cut_fail("return from the test"); + } + + void + test_unwind_stack (void) + { + test = cppcut_test_new("unwind stack test", stub_unwind_stack); + cut_assert_not_null(test); + + cut_assert_false(run()); + cut_assert_test_result_summary(run_context, 1, 0, 0, 1, 0, 0, 0, 0); + cut_assert_equal_int(1, n_destructor_calls); + } } /* |