Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <memory>
- namespace base {
- class Clock {
- public:
- virtual int Now() = 0;
- virtual ~Clock() {}
- };
- class DefaultClock : public Clock {
- public:
- DefaultClock() {
- std::cout << "Constructed DefaultClock" << std::endl;
- }
- virtual ~DefaultClock() {
- std::cout << "Destroyed DefaultClock" << std::endl;
- }
- int Now() override {
- static int now = 42;
- return now++;
- };
- };
- class MockClock : public Clock {
- public:
- MockClock(int fixed) : fixed_(fixed), now_(fixed) {
- std::cout << "Constructed MockClock" << fixed_ << std::endl;
- }
- virtual ~MockClock() {
- std::cout << "Destroyed MockClock" << fixed_ << std::endl;
- }
- int Now() override { return now_; }
- void SetNow(int now) { now_ = now; }
- private:
- int fixed_;
- int now_;
- };
- template <typename T, typename O = std::nullptr_t>
- class NoDestructor {
- public:
- // Not constexpr; just write static constexpr T x = ...; if the value should
- // be a constexpr.
- template <typename... Args>
- explicit NoDestructor(Args&&... args) {
- new (storage_) T(std::forward<Args>(args)...);
- }
- // Allows copy and move construction of the contained type, to allow
- // construction from an initializer list, e.g. for std::vector.
- explicit NoDestructor(const T& x) { new (storage_) T(x); }
- explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
- NoDestructor(const NoDestructor&) = delete;
- NoDestructor& operator=(const NoDestructor&) = delete;
- ~NoDestructor() = default;
- const T& operator*() const { return *get(); }
- T& operator*() { return *get(); }
- const T* operator->() const { return get(); }
- T* operator->() { return get(); }
- const T* get() const { return reinterpret_cast<const T*>(storage_); }
- T* get() { return reinterpret_cast<T*>(storage_); }
- private:
- alignas(T) char storage_[sizeof(T)];
- };
- }
- #define STATIC_MOCKABLE(type, name, default) \
- public: \
- template <class T, class... Args> \
- static T* Create##name##ForTesting(Args&&... args) { \
- Get##name##Ptr() = std::make_unique<T>(std::forward<Args>(args)...); \
- return static_cast<T*>(Get##name##Ptr().get()); \
- } \
- private: \
- static std::unique_ptr<type>& Get##name##Ptr() { \
- static base::NoDestructor<std::unique_ptr<type>> instance([] { \
- return default; \
- }()); \
- return *instance; \
- } \
- static type& Get##name() { \
- return *Get##name##Ptr().get(); \
- }
- // Example class allowing to inject custom Clock.
- class Example {
- public:
- static void PrintNow() {
- std::cout << GetClock().Now() << std::endl;
- }
- STATIC_MOCKABLE(base::Clock, Clock, std::make_unique<base::DefaultClock>());
- };
- // Test code.
- void test() {
- auto* clock_mock = Example::CreateClockForTesting<base::MockClock>(11);
- Example::PrintNow();
- clock_mock->SetNow(22);
- }
- int main() {
- std::cout << "Start: nothing should be constructed before" << std::endl;
- std::cout << "===========================================" << std::endl;
- Example::PrintNow();
- Example::PrintNow();
- test();
- Example::PrintNow();
- Example::CreateClockForTesting<base::MockClock>(33);
- Example::PrintNow();
- std::cout << "======================================" << std::endl;
- std::cout << "End: nothing should be destroyed after" << std::endl;
- }
Advertisement
Add Comment
Please, Sign In to add comment