add fake event queue for unittests

pull/14737/head
Paul Szczepanek 2021-06-06 11:25:38 +01:00
parent 5047bd3c27
commit 3290c944e8
5 changed files with 283 additions and 0 deletions

View File

@ -58,3 +58,5 @@ if (VALGRIND)
endif(VALGRIND)
add_subdirectory(stubs)
add_subdirectory(fakes)

View File

@ -0,0 +1,4 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(events)

View File

@ -0,0 +1,20 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
add_library(mbed-fakes-event-queue)
target_sources(mbed-fakes-event-queue
PRIVATE
events/EventQueue.cpp
)
target_include_directories(mbed-fakes-event-queue
PUBLIC
.
)
target_link_libraries(mbed-fakes-event-queue
PRIVATE
mbed-headers
gcov
)

View File

@ -0,0 +1,120 @@
/* mbed Microcontroller Library
* Copyright (c) 2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "EventQueue.h"
namespace events {
handle_t EventQueue::call_handler(function_t handler)
{
return call_handler_in(0, handler);
}
handle_t EventQueue::call_handler_in(tick_t ms, function_t handler)
{
_handler_id++;
_handlers.push_back(
internal_event{
std::unique_ptr<function_t>(new function_t(handler)),
_now + ms,
_handler_id
}
);
return _handler_id;
}
bool EventQueue::cancel_handler(handle_t handle)
{
if (!handle) {
return false;
}
auto found = std::remove_if(
_handlers.begin(),
_handlers.end(),
[handle](internal_event& element) -> bool {
return (handle == element.handle);
}
);
if (found != _handlers.end()) {
_handlers.erase(
found,
_handlers.end()
);
return true;
}
return false;
}
void EventQueue::process_events(tick_t duration_ms)
{
// execute all events during the duration
for (uint64_t i = 0; i < duration_ms; ++i) {
process_events();
_now++;
}
// last round to execute immediate events
process_events();
}
void EventQueue::process_events() {
while (true) {
if (_handlers.empty()) {
return;
}
/* to guarantee order we only dispatch one tick at a time*/
auto smallest = std::min_element(
_handlers.begin(),
_handlers.end(),
[](internal_event& element, internal_event& smallest){
return (element.tick < smallest.tick);
}
);
tick_t earliest_tick = smallest->tick;
/* stop if all elements happen later */
if (earliest_tick > _now) {
return;
}
/* dispatch all handlers that happen at this time */
auto found = std::remove_if(
_handlers.begin(),
_handlers.end(),
[earliest_tick](internal_event& element) -> bool {
if (earliest_tick >= element.tick) {
(*(element.handler))();
return true;
} else {
return false;
}
}
);
if (found != _handlers.end()) {
_handlers.erase(found, _handlers.end());
}
}
}
}

View File

@ -0,0 +1,137 @@
/* mbed Microcontroller Library
* Copyright (c) 2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EVENTQUEUE_FAKE_H
#define EVENTQUEUE_FAKE_H
#include <map>
#include <memory>
#include <functional>
#include <algorithm>
#include <vector>
#include "events/EventQueue.h"
#include <chrono>
#include <mstd_tuple>
namespace events {
typedef int handle_t;
typedef std::function<void()> function_t;
typedef unsigned tick_t;
class EventQueue {
using duration = std::chrono::duration<int, std::milli>;
public:
EventQueue(unsigned size = 0, unsigned char *buffer = NULL) { delete buffer; };
~EventQueue() { };
/** This will advence time by given amount of milliseonds and then dispatch all events that were set to happen in that time.
*
* @param ms number of miliseconds to advance time
*/
void dispatch(int milliseconds = -1) {
if (milliseconds > 0) {
process_events(milliseconds);
} else {
_now = (tick_t)-1;
process_events();
_now = 0;
}
};
tick_t tick() {
return _now;
};
bool cancel(handle_t id) {
return cancel_handler(id);
};
/** Get number of events in queue.
*
* @return Number of events waiting in the queue.
*/
size_t size() const {
return _handlers.size();
}
template<typename F, typename ... ArgTs>
handle_t call(F f, ArgTs... args) {
return call_handler(
[f, args = mstd::make_tuple(args...)]() {
mstd::apply(f, args);
}
);
}
template<typename F, typename ... ArgTs>
handle_t call_in(duration ms, F f, ArgTs... args) {
return call_handler_in(
ms.count(),
[f, args = mstd::make_tuple(args...)]() {
mstd::apply(f, args);
}
);
}
template <typename T, typename R, typename... ArgTs>
int call(T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
return call_handler(
[obj, method, args = mstd::make_tuple(args...)]() {
mstd::apply(method, obj, args);
}
);
}
template <typename T, typename R, typename... ArgTs>
int call_in(duration ms, T *obj, R(T::*method)(ArgTs...), ArgTs... args) {
return call_handler_in(
ms.count(),
[obj, method, args = mstd::make_tuple(args...)]() {
mstd::apply(method, obj, args);
}
);
}
private:
handle_t call_handler(function_t handler);
handle_t call_handler_in(tick_t ms, function_t handler);
bool cancel_handler(handle_t handle);
void process_events(tick_t duration_ms);
void process_events();
private:
struct internal_event {
std::unique_ptr<function_t> handler;
tick_t tick;
handle_t handle;
};
std::vector<internal_event> _handlers;
tick_t _now = 0;
handle_t _handler_id = 0;
};
}
#endif //EVENTQUEUE_FAKE_H