From 5aeecd3a7adef6d1e944ff130f703b664f4bca25 Mon Sep 17 00:00:00 2001 From: Jan Henrik Weinstock Date: Mon, 9 Oct 2023 10:41:07 +0200 Subject: [PATCH] Adding exception catcher around system::run --- src/vcml/core/system.cpp | 42 ++++++++++++++++++++++++++-------------- test/core/CMakeLists.txt | 3 ++- test/core/system.cpp | 40 ++++++++++++++++++++++++++++++++++++++ test/testing.h | 23 ++++++++++++++++++++++ 4 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 test/core/system.cpp diff --git a/src/vcml/core/system.cpp b/src/vcml/core/system.cpp index 1adca9d1..7ae643a9 100644 --- a/src/vcml/core/system.cpp +++ b/src/vcml/core/system.cpp @@ -73,21 +73,33 @@ int system::run() { broker::report_unused(); tlm::tlm_global_quantum::instance().set(quantum); - if (session >= 0) { - vcml::debugging::vspserver vspsession(session); - vspsession.echo(session_debug); - vspsession.start(); - } else if (duration != sc_core::SC_ZERO_TIME) { - log_info("starting simulation until %s using %s quantum", - duration.get().to_string().c_str(), - quantum.get().to_string().c_str()); - sc_core::sc_start(); - log_info("simulation stopped"); - } else { - log_info("starting infinite simulation using %s quantum", - quantum.get().to_string().c_str()); - sc_core::sc_start(); - log_info("simulation stopped"); + + try { + if (session >= 0) { + vcml::debugging::vspserver vspsession(session); + vspsession.echo(session_debug); + vspsession.start(); + } else if (duration != sc_core::SC_ZERO_TIME) { + log_info("starting simulation until %s using %s quantum", + duration.get().to_string().c_str(), + quantum.get().to_string().c_str()); + sc_core::sc_start(); + log_info("simulation stopped"); + } else { + log_info("starting infinite simulation using %s quantum", + quantum.get().to_string().c_str()); + sc_core::sc_start(); + log_info("simulation stopped"); + } + } catch (sc_report& rep) { + log_error("%s", rep.what()); + return EXIT_FAILURE; + } catch (std::exception& ex) { + log_error("Caught c++ exception: %s", ex.what()); + return EXIT_FAILURE; + } catch (...) { + log_error("Caught unknown exception"); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index 3d2c1182..27920efa 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -55,7 +55,8 @@ core_test("tracing") core_test("async_timer") core_test("memory") core_test("disk") -core_tesT("model") +core_test("model") +core_test("system") if(LUA_FOUND) core_test("lua") diff --git a/test/core/system.cpp b/test/core/system.cpp new file mode 100644 index 00000000..401e31d9 --- /dev/null +++ b/test/core/system.cpp @@ -0,0 +1,40 @@ +/****************************************************************************** + * * + * Copyright (C) 2023 MachineWare GmbH * + * All Rights Reserved * + * * + * This is work is licensed under the terms described in the LICENSE file * + * found in the root directory of this source tree. * + * * + ******************************************************************************/ + +#include "testing.h" + +class harness : public vcml::system +{ +public: + mwr::publishers::terminal term; + mock_publisher pub; + + harness(const sc_module_name& nm): vcml::system(nm), term(), pub() { + SC_HAS_PROCESS(harness); + SC_METHOD(test_method); + pub.expect(LOG_INFO, "starting infinite simulation"); + } + + virtual ~harness() = default; + + void test_method() { + pub.expect(LOG_ERROR, "wait() is only allowed in SC_THREADs"); + wait(SC_ZERO_TIME); + } +}; + +TEST(system, exceptions) { + // restore default handler, otherwise reports will count as a failure + auto handler = ::sc_core::sc_report_handler::default_handler; + ::sc_core::sc_report_handler::set_handler(handler); + + harness test("harness"); + EXPECT_EQ(test.run(), EXIT_FAILURE); +} diff --git a/test/testing.h b/test/testing.h index adb73285..2343dbf8 100644 --- a/test/testing.h +++ b/test/testing.h @@ -32,6 +32,29 @@ using namespace ::vcml; #define EXPECT_SUCCESS(fn) EXPECT_TRUE(vcml::success(fn)) #define EXPECT_FAILURE(fn) EXPECT_TRUE(vcml::failure(fn)) +MATCHER_P2(match_log, lvl, txt, "Matches a log message on level and text") { + if (arg.level != lvl) + return false; + + for (const string& line : arg.lines) + if (line.find(txt) != std::string::npos) + return true; + + return false; +} + +class mock_publisher : public mwr::publisher +{ +public: + mock_publisher(): mwr::publisher(LOG_ERROR, LOG_DEBUG) {} + mock_publisher(log_level min, log_level max): mwr::publisher(min, max) {} + MOCK_METHOD(void, publish, (const mwr::logmsg&), (override)); + + void expect(log_level lvl, const string& message) { + EXPECT_CALL(*this, publish(match_log(lvl, message))); + } +}; + class test_base : public component { private: