3 * Copyright (c) 2020 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This file implements a test for CHIP Callback
24 #include <core/CHIPCallback.h>
25 #include <support/CHIPMem.h>
26 #include <support/UnitTestRegistration.h>
28 #include <nlunit-test.h>
30 using namespace chip::Callback;
33 * An example Callback registrar. Resumer::Resume() accepts Callbacks
34 * to be run during the next call to Resumer::Dispatch(). In an environment
35 * completely driven by callbacks, an application's main() would just call
36 * something like Resumer::Dispatch() in a loop.
38 class Resumer : private CallbackDeque
42 * @brief run this callback next Dispatch
44 void Resume(Callback<> * cb)
46 // always first thing: cancel to take ownership of
48 Enqueue(cb->Cancel());
57 // runs the ready list
58 while (ready.mNext != &ready)
60 Callback<> * cb = Callback<>::FromCancelable(ready.mNext);
64 cb->mCall(cb->mContext);
69 static void increment(int * v)
80 static void resume(struct Resume * me)
82 me->resumer->Resume(me->cb);
85 static void canceler(Cancelable * ca)
90 static void ResumerTest(nlTestSuite * inSuite, void * inContext)
93 Callback<> cb(reinterpret_cast<CallFn>(increment), &n);
94 Callback<> cancelcb(reinterpret_cast<CallFn>(canceler), cb.Cancel());
102 NL_TEST_ASSERT(inSuite, n == 3);
105 // test cb->Cancel() cancels
109 NL_TEST_ASSERT(inSuite, n == 1);
112 // Cancel cb before Dispatch() gets around to us (tests FIFO *and* cancel() from readylist)
113 resumer.Resume(&cancelcb);
116 NL_TEST_ASSERT(inSuite, n == 1);
119 // 2nd Resume() cancels first registration
121 resumer.Resume(&cb); // cancels previous registration
122 resumer.Dispatch(); // runs the list
123 resumer.Dispatch(); // runs an empty list
124 NL_TEST_ASSERT(inSuite, n == 2);
127 // Resume() during Dispatch() runs only once, but enqueues for next dispatch
128 struct Resume res = { .cb = &cb, .resumer = &resumer };
129 Callback<> resumecb(reinterpret_cast<CallFn>(resume), &res);
131 resumer.Resume(&resumecb);
133 NL_TEST_ASSERT(inSuite, n == 2);
135 NL_TEST_ASSERT(inSuite, n == 3);
137 Callback<> * pcb = chip::Platform::New<Callback<>>(reinterpret_cast<CallFn>(increment), &n);
140 // cancel on destruct
143 NL_TEST_ASSERT(inSuite, n == 2);
146 chip::Platform::Delete(pcb);
148 NL_TEST_ASSERT(inSuite, n == 2);
152 * An example Callback registrar. Notifier implements persistently-registered
153 * semantics, and uses Callbacks with a non-default signature.
155 class Notifier : private CallbackDeque
158 typedef void (*NotifyFn)(void *, int);
161 * run all the callers
165 for (Cancelable * ca = mNext; ca != this; ca = ca->mNext)
167 // persistent registration semantics, with data
169 Callback<NotifyFn> * cb = Callback<NotifyFn>::FromCancelable(ca);
170 cb->mCall(cb->mContext, v);
177 static void Cancel(Cancelable * cb)
179 Dequeue(cb); // take off ready list
183 * @brief illustrate a case where this needs notification of cancellation
185 void Register(Callback<NotifyFn> * cb) { Enqueue(cb->Cancel(), Cancel); }
188 static void increment_by(int * n, int by)
193 static void NotifierTest(nlTestSuite * inSuite, void * inContext)
196 Callback<Notifier::NotifyFn> cb(reinterpret_cast<Notifier::NotifyFn>(increment_by), &n);
197 Callback<Notifier::NotifyFn> cancelcb(reinterpret_cast<Notifier::NotifyFn>(canceler), cb.Cancel());
199 // safe to call anytime
204 // Simple stuff works, e.g. and there's persistent registration
205 notifier.Register(&cb);
208 NL_TEST_ASSERT(inSuite, n == 10);
211 // Cancel cb before Dispatch() gets around to us (tests FIFO *and* cancel() from readylist)
212 notifier.Register(&cancelcb);
213 notifier.Register(&cb);
215 NL_TEST_ASSERT(inSuite, n == 1);
222 * Set up the test suite.
224 int TestCHIPCallback_Setup(void * inContext)
226 CHIP_ERROR error = chip::Platform::MemoryInit();
227 if (error != CHIP_NO_ERROR)
233 * Tear down the test suite.
235 int TestCHIPCallback_Teardown(void * inContext)
237 chip::Platform::MemoryShutdown();
242 * Test Suite. It lists all the test functions.
246 static const nlTest sTests[] =
248 NL_TEST_DEF("ResumerTest", ResumerTest),
249 NL_TEST_DEF("NotifierTest", NotifierTest),
255 int TestCHIPCallback(void)
258 nlTestSuite theSuite =
262 TestCHIPCallback_Setup,
263 TestCHIPCallback_Teardown
267 nlTestRunner(&theSuite, nullptr);
269 return (nlTestRunnerStats(&theSuite));
272 CHIP_REGISTER_TEST_SUITE(TestCHIPCallback)