Software APIs
global_mock.h
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#ifndef OPENTITAN_SW_DEVICE_LIB_BASE_GLOBAL_MOCK_H_
6#define OPENTITAN_SW_DEVICE_LIB_BASE_GLOBAL_MOCK_H_
7
8#include <sstream>
9#include <typeinfo>
10#include <utility>
11
12#include "gmock/gmock.h"
13#include "gtest/gtest.h"
14
15namespace global_mock {
16
17/**
18 * Base class for mocks used in unit tests.
19 *
20 * If a class `Mock` derives from `GlobalMock<Mock>`, `GlobalMock<Mock>`
21 * ensures that there is at most one instance of `Mock` at a time (checked at
22 * runtime) and makes this instance globally accessible via the static `Mock
23 * &Instance()` method.
24 *
25 * Mock classes should be globally accessible so that mock functions can call
26 * their methods during tests. They can also be strict or nice depending on
27 * tests' needs. Mock classes that satisfy both requirements can be defined as
28 * follows:
29 *
30 * namespace global_mock {
31 * namespace internal {
32 * class MockFoo : public GlobalMock<MockFoo> {
33 * ...
34 * };
35 * } // namespace internal
36 * // Type alias for making `internal::MockFoo` a strict mock.
37 * using MockFoo = testing::StrictMock<internal::MockFoo>;
38 * // Type alias for making `internal::MockFoo` a nice mock if needed.
39 * using NiceMockFoo = testing::NiceMock<internal::MockFoo>;
40 * ...
41 * } // namespace rom_test
42 *
43 * This construction also ensures that we cannot have `MockFoo` and
44 * `NiceMockFoo` instantiated at the same time since they both derive from the
45 * same class, i.e. `GlobalMock<internal::MockFoo>`.
46 */
47template <typename Mock>
48class GlobalMock {
49 public:
50 GlobalMock() {
51 if (instance_ != nullptr) {
52 std::stringstream ss;
53 ss << "Mock `" << typeid(GlobalMock).name()
54 << "` is already instantiated.";
55 throw std::runtime_error(std::move(ss).str());
56 }
57 instance_ = this;
58 }
59
60 // Note: Destructors of mock classes must be virtual for `testing::StrictMock`
61 // and `testing::NiceMock` to work correctly.
62 virtual ~GlobalMock() { instance_ = nullptr; }
63
64 static Mock &Instance() {
65 if (instance_ == nullptr) {
66 std::stringstream ss;
67 ss << "Mock `" << typeid(GlobalMock).name() << "` not instantiated yet.";
68 throw std::runtime_error(std::move(ss).str());
69 }
70 return *static_cast<Mock *>(instance_);
71 }
72
73 GlobalMock(const GlobalMock &) = delete;
74 GlobalMock &operator=(const GlobalMock &) = delete;
75 GlobalMock(GlobalMock &&) = delete;
76 GlobalMock &operator=(GlobalMock &&) = delete;
77
78 private:
79 static GlobalMock<Mock> *instance_;
80};
81template <typename Mock>
82GlobalMock<Mock> *GlobalMock<Mock>::instance_ = nullptr;
83
84} // namespace global_mock
85#endif // OPENTITAN_SW_DEVICE_LIB_BASE_GLOBAL_MOCK_H_