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 
15 namespace 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  */
47 template <typename Mock>
48 class 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 };
81 template <typename Mock>
83 
84 } // namespace global_mock
85 #endif // OPENTITAN_SW_DEVICE_LIB_BASE_GLOBAL_MOCK_H_