Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
test_main.hxx
Go to the documentation of this file.
1
36#ifdef _UTILS_TEST_MAIN_HXX_
37#error Only ever include test_main into the main unittest file.
38#else
39#define _UTILS_TEST_MAIN_HXX_
40
41#include "nmranet_config.h"
42
43#include <stdio.h>
44#include <stdarg.h>
45#include <memory>
46#include <string>
47#include <functional>
48#include "gtest/gtest.h"
49#include "gmock/gmock.h"
50
51#include "can_frame.h"
53#include "executor/Executor.hxx"
54#include "executor/Service.hxx"
55#include "os/TempFile.hxx"
56#include "os/os.h"
58
59#ifdef WITHGPERFTOOLS
60#include <gperftools/profiler.h>
61
62std::function<void()> profiler_enable{&ProfilerEnable};
63std::function<void()> profiler_disable{&ProfilerDisable};
64#endif
65
66int appl_main(int argc, char *argv[])
67{
68 testing::InitGoogleMock(&argc, argv);
69 return RUN_ALL_TESTS();
70}
71
72bool mute_log_output = false;
73extern "C" {
74
75void log_output(char* buf, int size) {
76 if (size <= 0 || mute_log_output) return;
77 fwrite(buf, size, 1, stderr);
78 fwrite("\n", 1, 1, stderr);
79}
80
81}
82
83
86
87#ifdef __EMSCRIPTEN__
89
90void os_emscripten_yield() {
92}
93#else
95Executor<1> g_executor("ex_thread", 0, 1024);
96#endif
97
98#ifndef NO_GC_OPTIMIZE
100OVERRIDE_CONST(gridconnect_buffer_size, 1);
101#endif
102
103Service g_service(&g_executor);
104
114{
115 std::unique_ptr<ExecutorGuard> guard(new ExecutorGuard(&g_executor));
116 guard->wait_for_notification();
117}
118
122{
124 while (!g_executor.active_timers()->empty())
125 {
126 usleep(20000);
128 }
130}
131
142
146public:
148 typedef void* thread_fn_t(void*);
153 : fn_(fn), arg_(arg) {
154 g_executor.add(this);
155 }
156
159 void run() OVERRIDE {
160 (*fn_)(arg_);
161 delete this;
162 }
163private:
165 void* arg_;
166};
167
170{
171public:
172 FnExecutable(std::function<void()> &&fn)
173 : fn_(std::move(fn))
174 {
175 }
176
178 {
179 fn_();
180 n.notify();
181 }
182
184
185private:
186 std::function<void()> fn_;
187};
188
190void run_x(std::function<void()> fn)
191{
192 g_executor.sync_run(std::move(fn));
193}
194
198{
199public:
200 RunInConstruct(std::function<void()> f)
201 {
202 f();
203 }
204};
205
208{
209public:
210 RunInConstructOnMain(std::function<void()> f)
211 {
212 run_x(f);
213 }
214};
215
218#define RX(statement) run_x([&](){ statement; })
219
221template <class T> struct PendingInvocation
222{
230 bool isWaited {false};
231
233 {
234 wait();
235 }
236
237 void wait()
238 {
239 if (isWaited)
240 {
241 return;
242 }
244 isWaited = true;
245 }
246};
247
251template <class T, typename... Args>
252std::unique_ptr<PendingInvocation<T>> invoke_flow_nowait(
253 FlowInterface<Buffer<T>> *flow, Args &&...args)
254{
255 auto ret = std::make_unique<PendingInvocation<T>>();
256 ret->b.reset(flow->alloc());
257 ret->b->data()->reset(std::forward<Args>(args)...);
258 ret->b->data()->done.reset(&ret->barrier);
259 flow->send(ret->b->ref());
260 return ret;
261}
262
270{
271public:
273 {
274 }
275
280 {
281 if (e)
282 {
283 e->add(this);
284 }
285 else
286 {
287 g_executor.add(this);
288 }
290 }
291
292 virtual void run()
293 {
294 n_.notify();
295#ifndef __EMSCRIPTEN__
297#endif
298 }
299
303 {
305 }
306
309 {
310#ifndef __EMSCRIPTEN__
311 m_.notify();
312#endif
313 }
314
315private:
320};
321
333{
334public:
341 template <class T, typename U>
342 ScopedOverride(T *variable, U new_value)
343 : holder_(new Holder<T>(variable, new_value))
344 {
345 }
346
348 void restore()
349 {
350 holder_.reset();
351 }
352
353private:
356 {
357 public:
358 virtual ~HolderBase()
359 {
360 }
361 };
362
366 template <class T> class Holder : public HolderBase
367 {
368 public:
372 Holder(T *variable, T new_value)
373 : variable_(variable)
374 , oldValue_(*variable)
375 {
376 *variable = new_value;
377 }
378
379 ~Holder()
380 {
382 }
383
384 private:
389 };
390
393 std::unique_ptr<HolderBase> holder_;
394};
395
401int nibble_to_int(char n)
402{
403 if ('0' <= n && n <= '9')
404 {
405 return n - '0';
406 }
407 if ('a' <= n && n <= 'f')
408 {
409 return n - 'a' + 10;
410 }
411 if ('A' <= n && n <= 'F')
412 {
413 return n - 'A' + 10;
414 }
415 DIE("Unknown nibble arrived.");
416}
417
422std::string hex2str(const char *hex)
423{
424 std::string ret;
425 while (*hex && *(hex + 1))
426 {
427 if (*hex == ' ')
428 {
429 ++hex;
430 continue;
431 }
432 ret.push_back((nibble_to_int(*hex) << 4) | (nibble_to_int(*(hex + 1))));
433 hex += 2;
434 }
435 return ret;
436}
437
438const char HEXCHR[17] = "0123456789abcdef";
439
445std::string str2hex(const string &s)
446{
447 std::string ret;
448 for (char c : s)
449 {
450 ret.push_back(HEXCHR[c >> 4]);
451 ret.push_back(HEXCHR[c & 0xf]);
452 }
453 return ret;
454}
455
456#endif // _UTILS_TEST_MAIN_HXX_
AutoReleaseBuffer< T > BufferPtr
Smart pointer for buffers.
Definition Buffer.hxx:259
bool empty()
Definition Timer.cxx:124
A BarrierNotifiable allows to create a number of child Notifiable and wait for all of them to finish.
Utility class to block an executor for a while.
BlockExecutor(ExecutorBase *e)
Creates a block against executor e and waits until the block suceeds.
void wait_for_blocked()
Blocks the current thread until the BlockExecutor manages to block the executor it was scheduled on.
void release_block()
Releases the executor that was blocked.
SyncNotifiable n_
notified (from the executor thread) when the block gets in place.
SyncNotifiable m_
notified (from the test/operator thread) to release the block.
virtual void run()
Entry point.
Base class for all QMember types that hold data in an expandable format.
Definition Buffer.hxx:195
An object that can be scheduled on an executor to run.
Utility class to help running a "pthread"-like thread in the main executor.
thread_fn_t * fn_
pointer to function to run.
void * arg_
argument to pass to function.
ExecuteOnMainExecutor(thread_fn_t *fn, void *arg)
Schedules the function fn with argument arg on the main executor.
void run() OVERRIDE
Runs the intended function with the given argument and then deletes this when done.
void * thread_fn_t(void *)
Function type for a thread's main entry point.
This class implements an execution of tasks pulled off an input queue.
Definition Executor.hxx:64
void sync_run(std::function< void()> fn)
Synchronously runs a closure on this executor.
Definition Executor.cxx:151
ActiveTimers * active_timers()
Definition Executor.hxx:144
virtual void add(Executable *action, unsigned priority=UINT_MAX)=0
Send a message to this Executor's queue.
bool loop_once()
Performs one loop of the execution on the calling thread.
Definition Executor.cxx:165
This class can be given an executor, and will notify itself when that executor is out of work.
Definition Executor.hxx:383
Fixes race condition between test teardown and executor startup.
Implementation the ExecutorBase with a specific number of priority bands.
Definition Executor.hxx:266
void add(Executable *msg, unsigned priority=UINT_MAX) OVERRIDE
Send a message to this Executor's queue.
Definition Executor.hxx:306
Abstract class for message recipients.
Helper class to run a lambda in the main executor.
void run() OVERRIDE
Entry point.
This is an empty struct.
Definition Executor.hxx:256
Runs some code in the constructor on the main executor.
Runs some code in the constructor.
Virtual base class for the destructible holders.
Type-accurate class that holds the temporary variable with the old value, the pointer to the variable...
T * variable_
Points to the variable that needs resetting.
T oldValue_
old value to reset variable_ to when destroyed.
Holder(T *variable, T new_value)
Overrides the value of a variable and restores it to the original value when destructed.
void restore()
Restores the original value.
std::unique_ptr< HolderBase > holder_
Smart ptr that will reset the variable to the previous value when going out of scope.
ScopedOverride(T *variable, U new_value)
Constructor.
Collection of related state machines that pend on incoming messages.
A Notifiable for synchronously waiting for a notification.
void notify() override
Implementation of notification receive.
void wait_for_notification()
Blocks the current thread until the notification is delivered.
#define OVERRIDE_CONST(name, value)
Overrides the value of a constant.
Definition constants.hxx:91
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143
Structure holding returned objects for an invoke_flow_nowait command.
BufferPtr< T > b
Buffer sent to the flow.
SyncNotifiable notifiable
Notifiable to wait for.
bool isWaited
True if wait has been invoked.
BarrierNotifiable barrier
Barrier notifiable given to the buffer.
void wait_for_main_executor()
Blocks the current thread until the main executor has run out of work.
int nibble_to_int(char n)
Converts a character containing a hex digit to the value of that digit.
class ExecutorStartupFix unused_executor_startup_guard_instance
actual instance.
std::unique_ptr< PendingInvocation< T > > invoke_flow_nowait(FlowInterface< Buffer< T > > *flow, Args &&...args)
Executes a callable flow similar to invoke_flow(...) but does not wait for the result to come back.
int appl_main(int argc, char *argv[])
Entry point to application.
Definition test_main.hxx:66
Executor< 1 > g_executor
Global executor thread for tests.
void run_x(std::function< void()> fn)
Synchronously runs a function in the main executor.
std::string hex2str(const char *hex)
Converts a hex string into the respective byte string.
void log_output(char *buf, int size)
Prints a line of log to the log output destination.
Definition test_main.hxx:75
std::string str2hex(const string &s)
Converts a byte string into the hexadecimal representation, with no separators.
void wait_for_main_timers()
Delays the current thread until all asynchronous processing and all pending timers have completed.