quic/qbox
Loading...
Searching...
No Matches
test-bench.h
1/*
2 * This file is part of libgsutils
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * Author: GreenSocs 2022
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9/*
10 * GTest helper to workaround SystemC limitations regarding its non-resettable
11 nature.
12 *
13 * You can use the TEST_BENCH macro as you would use the TEST_F GTest macro.
14 * Your fixture class must inherit from the TestBench class.
15 *
16 * Before each test, the test program is forked so that it starts from a fresh
17 * SystemC environment.
18 *
19 *
20 * Using GDB
21 * =========
22 *
23 * Note that debugging with GDB is a little more involved, because of the forks.
24 * You can do something like this:
25 *
26 * (gdb) set detach-on-fork off
27 * (gdb) set non-stop on
28 * (gdb) b somewhere
29 * (gdb) r
30 * Thread 2.1 "xxx" hit Breakpoint 1, somewhere() (...)
31 at ...
32
33 * (gdb) thread 2.1
34 * (gdb) ... you can now debug as normal in the child
35 *
36 * Note that in non-stop mode, other inferiors are still running. To stop one,
37 * select it with the `thread' command and issue the `interrupt' command.
38 *
39 * Example
40 * =======
41 *
42 * class MyTestBench : public TestBench {
43 * private:
44 * SomeModule m_module_under_test;
45 * AnotherModule m_mock_module;
46 *
47 * public:
48 * MyTestBench(const sc_core::sc_module_name &n)
49 * : TestBench(n)
50 * , m_module_under_test("module-under-test")
51 * , m_mock_module("mock-module")
52 * {
53 * m_mock_module.target_socket.bind(m_module_under_test.initiator_socket);
54 * }
55 * };
56 *
57 * TEST_BENCH(MyTestBench, Test0)
58 * {
59 * m_module_under_test.do_something();
60 * ASSERT_TRUE(m_mock_module.expected_result());
61 * }
62 *
63 * int sc_main(int argc, char *argv[])
64 * {
65 * ::testing::InitGoogleTest(&argc, argv);
66 * return RUN_ALL_TESTS();
67 * }
68 *
69 */
70
71#ifndef _GREENSOCS_GSUTILS_TESTS_TEST_BENCH_H
72#define _GREENSOCS_GSUTILS_TESTS_TEST_BENCH_H
73
74#include <systemc>
75
76#include <gtest/gtest.h>
77#include <scp/report.h>
78
79class TestBench : public sc_core::sc_module
80{
81protected:
82 virtual void test_bench_body() = 0;
83
84public:
85 TestBench(const sc_core::sc_module_name& n): sc_core::sc_module(n) {}
86};
87template <class T>
88class TestBenchEnv : public ::testing::Environment
89{
90 // Would be nice to be a smart pointer, but sc_bind takes a pointer.
91 T* instance;
92
93public:
94 void SetUp() override { instance = new T(); }
95 void TearDown() override { delete instance; }
96 T* get() { return instance; }
97};
98
99#ifndef _WIN32
100#include <sys/types.h>
101#include <sys/wait.h>
102#include <unistd.h>
103
104template <class T>
105static inline void run_test_bench(T* instance)
106{
107 sc_spawn(sc_bind(&T::test_bench_body, instance));
108 sc_core::sc_start();
109}
110
111#else /* _WIN32 */
112#include <iostream>
113
114static inline void run_test_bench()
115{
116 SCP_ERR("test_bench") << "Running tests on Windows is not supported.";
117 ASSERT_TRUE(false);
118}
119
120#endif
121
122#define TEST_BENCH_NAME(name) TestBench__##name
123
124#define TEST_BENCH(test_bench, name) \
125 class TEST_BENCH_NAME(name): public test_bench \
126 { \
127 public: \
128 void test_bench_body() override; \
129 \
130 TEST_BENCH_NAME(name)(): test_bench(#name) {} \
131 }; \
132 testing::Environment* const test_bench_env##name = testing::AddGlobalTestEnvironment( \
133 new TestBenchEnv<TEST_BENCH_NAME(name)>()); \
134 TEST(TEST_BENCH_NAME(name), name) \
135 { \
136 run_test_bench<TEST_BENCH_NAME(name)>( \
137 static_cast<TestBenchEnv<TEST_BENCH_NAME(name)>*>(test_bench_env##name)->get()); \
138 } \
139 void TEST_BENCH_NAME(name)::test_bench_body()
140
141#endif
Definition target.h:160
Definition test-bench.h:89
Definition test-bench.h:80