1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include "pw_async/dispatcher.h" 17 #include "pw_async_backend/fake_dispatcher.h" // nogncheck 18 19 namespace pw::async::test { 20 21 /// FakeDispatcher is a facade for an implementation of Dispatcher that is used 22 /// in unit tests. FakeDispatcher uses simulated time. RunUntil() and RunFor() 23 /// advance time immediately, and now() returns the current simulated time. 24 /// 25 /// To support various Task backends, FakeDispatcher wraps a 26 /// backend::NativeFakeDispatcher that implements standard FakeDispatcher 27 /// behavior using backend::NativeTask objects. 28 class FakeDispatcher final : public Dispatcher { 29 public: FakeDispatcher()30 FakeDispatcher() : native_dispatcher_(*this) {} 31 32 /// Execute all runnable tasks and return without advancing simulated time. RunUntilIdle()33 void RunUntilIdle() { native_dispatcher_.RunUntilIdle(); } 34 35 /// Run the dispatcher until Now() has reached `end_time`, executing all tasks 36 /// that come due before then. RunUntil(chrono::SystemClock::time_point end_time)37 void RunUntil(chrono::SystemClock::time_point end_time) { 38 native_dispatcher_.RunUntil(end_time); 39 } 40 41 /// Run the Dispatcher until `duration` has elapsed, executing all tasks that 42 /// come due in that period. RunFor(chrono::SystemClock::duration duration)43 void RunFor(chrono::SystemClock::duration duration) { 44 native_dispatcher_.RunFor(duration); 45 } 46 47 /// Stop processing tasks. After calling RequestStop(), the next time the 48 /// Dispatcher is run, all waiting Tasks will be dequeued and their 49 /// TaskFunctions called with a PW_STATUS_CANCELLED status. RequestStop()50 void RequestStop() { native_dispatcher_.RequestStop(); } 51 52 // Dispatcher overrides: Post(Task & task)53 void Post(Task& task) override { native_dispatcher_.Post(task); } PostAfter(Task & task,chrono::SystemClock::duration delay)54 void PostAfter(Task& task, chrono::SystemClock::duration delay) override { 55 native_dispatcher_.PostAfter(task, delay); 56 } PostAt(Task & task,chrono::SystemClock::time_point time)57 void PostAt(Task& task, chrono::SystemClock::time_point time) override { 58 native_dispatcher_.PostAt(task, time); 59 } PostPeriodic(Task & task,chrono::SystemClock::duration interval)60 void PostPeriodic(Task& task, 61 chrono::SystemClock::duration interval) override { 62 native_dispatcher_.PostPeriodic(task, interval); 63 } PostPeriodicAt(Task & task,chrono::SystemClock::duration interval,chrono::SystemClock::time_point start_time)64 void PostPeriodicAt(Task& task, 65 chrono::SystemClock::duration interval, 66 chrono::SystemClock::time_point start_time) override { 67 native_dispatcher_.PostPeriodicAt(task, interval, start_time); 68 } Cancel(Task & task)69 bool Cancel(Task& task) override { return native_dispatcher_.Cancel(task); } 70 71 // VirtualSystemClock overrides: now()72 chrono::SystemClock::time_point now() override { 73 return native_dispatcher_.now(); 74 } 75 76 // Returns the inner NativeFakeDispatcher containing backend-specific 77 // state/logic. Only non-portable code should call these methods! native_type()78 backend::NativeFakeDispatcher& native_type() { return native_dispatcher_; } native_type()79 const backend::NativeFakeDispatcher& native_type() const { 80 return native_dispatcher_; 81 } 82 83 private: 84 backend::NativeFakeDispatcher native_dispatcher_; 85 }; 86 87 } // namespace pw::async::test 88