Skip to content

Commit 3290c94

Browse files
add fake event queue for unittests
1 parent 5047bd3 commit 3290c94

File tree

5 files changed

+283
-0
lines changed

5 files changed

+283
-0
lines changed

UNITTESTS/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ if (VALGRIND)
5858
endif(VALGRIND)
5959

6060
add_subdirectory(stubs)
61+
add_subdirectory(fakes)
62+

UNITTESTS/fakes/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) 2020 ARM Limited. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
add_subdirectory(events)

UNITTESTS/fakes/events/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2020 ARM Limited. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
add_library(mbed-fakes-event-queue)
5+
6+
target_sources(mbed-fakes-event-queue
7+
PRIVATE
8+
events/EventQueue.cpp
9+
)
10+
11+
target_include_directories(mbed-fakes-event-queue
12+
PUBLIC
13+
.
14+
)
15+
16+
target_link_libraries(mbed-fakes-event-queue
17+
PRIVATE
18+
mbed-headers
19+
gcov
20+
)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2020 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "EventQueue.h"
19+
20+
namespace events {
21+
22+
handle_t EventQueue::call_handler(function_t handler)
23+
{
24+
return call_handler_in(0, handler);
25+
}
26+
27+
handle_t EventQueue::call_handler_in(tick_t ms, function_t handler)
28+
{
29+
_handler_id++;
30+
31+
_handlers.push_back(
32+
internal_event{
33+
std::unique_ptr<function_t>(new function_t(handler)),
34+
_now + ms,
35+
_handler_id
36+
}
37+
);
38+
39+
return _handler_id;
40+
}
41+
42+
bool EventQueue::cancel_handler(handle_t handle)
43+
{
44+
if (!handle) {
45+
return false;
46+
}
47+
48+
auto found = std::remove_if(
49+
_handlers.begin(),
50+
_handlers.end(),
51+
[handle](internal_event& element) -> bool {
52+
return (handle == element.handle);
53+
}
54+
);
55+
56+
if (found != _handlers.end()) {
57+
_handlers.erase(
58+
found,
59+
_handlers.end()
60+
);
61+
return true;
62+
}
63+
64+
return false;
65+
}
66+
67+
void EventQueue::process_events(tick_t duration_ms)
68+
{
69+
// execute all events during the duration
70+
for (uint64_t i = 0; i < duration_ms; ++i) {
71+
process_events();
72+
_now++;
73+
}
74+
75+
// last round to execute immediate events
76+
process_events();
77+
}
78+
79+
void EventQueue::process_events() {
80+
while (true) {
81+
if (_handlers.empty()) {
82+
return;
83+
}
84+
85+
/* to guarantee order we only dispatch one tick at a time*/
86+
auto smallest = std::min_element(
87+
_handlers.begin(),
88+
_handlers.end(),
89+
[](internal_event& element, internal_event& smallest){
90+
return (element.tick < smallest.tick);
91+
}
92+
);
93+
tick_t earliest_tick = smallest->tick;
94+
95+
/* stop if all elements happen later */
96+
if (earliest_tick > _now) {
97+
return;
98+
}
99+
100+
/* dispatch all handlers that happen at this time */
101+
auto found = std::remove_if(
102+
_handlers.begin(),
103+
_handlers.end(),
104+
[earliest_tick](internal_event& element) -> bool {
105+
if (earliest_tick >= element.tick) {
106+
(*(element.handler))();
107+
return true;
108+
} else {
109+
return false;
110+
}
111+
}
112+
);
113+
114+
if (found != _handlers.end()) {
115+
_handlers.erase(found, _handlers.end());
116+
}
117+
}
118+
}
119+
120+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2020 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef EVENTQUEUE_FAKE_H
19+
#define EVENTQUEUE_FAKE_H
20+
21+
#include <map>
22+
#include <memory>
23+
#include <functional>
24+
#include <algorithm>
25+
#include <vector>
26+
#include "events/EventQueue.h"
27+
#include <chrono>
28+
#include <mstd_tuple>
29+
30+
namespace events {
31+
32+
typedef int handle_t;
33+
typedef std::function<void()> function_t;
34+
typedef unsigned tick_t;
35+
36+
class EventQueue {
37+
using duration = std::chrono::duration<int, std::milli>;
38+
39+
public:
40+
EventQueue(unsigned size = 0, unsigned char *buffer = NULL) { delete buffer; };
41+
42+
~EventQueue() { };
43+
44+
/** This will advence time by given amount of milliseonds and then dispatch all events that were set to happen in that time.
45+
*
46+
* @param ms number of miliseconds to advance time
47+
*/
48+
void dispatch(int milliseconds = -1) {
49+
if (milliseconds > 0) {
50+
process_events(milliseconds);
51+
} else {
52+
_now = (tick_t)-1;
53+
process_events();
54+
_now = 0;
55+
}
56+
};
57+
58+
tick_t tick() {
59+
return _now;
60+
};
61+
62+
bool cancel(handle_t id) {
63+
return cancel_handler(id);
64+
};
65+
66+
/** Get number of events in queue.
67+
*
68+
* @return Number of events waiting in the queue.
69+
*/
70+
size_t size() const {
71+
return _handlers.size();
72+
}
73+
74+
template<typename F, typename ... ArgTs>
75+
handle_t call(F f, ArgTs... args) {
76+
return call_handler(
77+
[f, args = mstd::make_tuple(args...)]() {
78+
mstd::apply(f, args);
79+
}
80+
);
81+
}
82+
83+
template<typename F, typename ... ArgTs>
84+
handle_t call_in(duration ms, F f, ArgTs... args) {
85+
return call_handler_in(
86+
ms.count(),
87+
[f, args = mstd::make_tuple(args...)]() {
88+
mstd::apply(f, args);
89+
}
90+
);
91+
}
92+
93+
template <typename T, typename R, typename... ArgTs>
94+
int call(T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
95+
return call_handler(
96+
[obj, method, args = mstd::make_tuple(args...)]() {
97+
mstd::apply(method, obj, args);
98+
}
99+
);
100+
}
101+
102+
template <typename T, typename R, typename... ArgTs>
103+
int call_in(duration ms, T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
104+
return call_handler_in(
105+
ms.count(),
106+
[obj, method, args = mstd::make_tuple(args...)]() {
107+
mstd::apply(method, obj, args);
108+
}
109+
);
110+
}
111+
112+
private:
113+
handle_t call_handler(function_t handler);
114+
115+
handle_t call_handler_in(tick_t ms, function_t handler);
116+
117+
bool cancel_handler(handle_t handle);
118+
119+
void process_events(tick_t duration_ms);
120+
121+
void process_events();
122+
123+
private:
124+
struct internal_event {
125+
std::unique_ptr<function_t> handler;
126+
tick_t tick;
127+
handle_t handle;
128+
};
129+
130+
std::vector<internal_event> _handlers;
131+
tick_t _now = 0;
132+
handle_t _handler_id = 0;
133+
};
134+
135+
}
136+
137+
#endif //EVENTQUEUE_FAKE_H

0 commit comments

Comments
 (0)