parent
e1d32797d7
commit
37fb197a34
@ -0,0 +1,18 @@ |
|||||||
|
all: build test |
||||||
|
|
||||||
|
reset: |
||||||
|
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
||||||
|
|
||||||
|
build: |
||||||
|
meson compile -j 4 -C builddir
|
||||||
|
|
||||||
|
test: build |
||||||
|
./builddir/runtests
|
||||||
|
|
||||||
|
install: build test |
||||||
|
powershell "cp ./builddir/subprojects/libgit2-1.8.1/liblibgit2package.dll ."
|
||||||
|
powershell "cp ./builddir/subprojects/efsw/libefsw.dll ."
|
||||||
|
powershell "cp builddir/escape_turings_tarpit.exe ."
|
||||||
|
|
||||||
|
clean: |
||||||
|
meson compile --clean -C builddir
|
@ -0,0 +1,40 @@ |
|||||||
|
#include "dbc.hpp" |
||||||
|
|
||||||
|
void dbc::log(const string &message) { |
||||||
|
fmt::print("{}\n", message); |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::sentinel(const string &message) { |
||||||
|
string err = fmt::format("[SENTINEL!] {}\n", message); |
||||||
|
throw dbc::SentinelError{err}; |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::pre(const string &message, bool test) { |
||||||
|
if(!test) { |
||||||
|
string err = fmt::format("[PRE!] {}\n", message); |
||||||
|
throw dbc::PreCondError{err}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::pre(const string &message, std::function<bool()> tester) { |
||||||
|
dbc::pre(message, tester()); |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::post(const string &message, bool test) { |
||||||
|
if(!test) { |
||||||
|
string err = fmt::format("[POST!] {}\n", message); |
||||||
|
throw dbc::PostCondError{err}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::post(const string &message, std::function<bool()> tester) { |
||||||
|
dbc::post(message, tester()); |
||||||
|
} |
||||||
|
|
||||||
|
void dbc::check(bool test, const string &message) { |
||||||
|
if(!test) { |
||||||
|
string err = fmt::format("[CHECK!] {}\n", message); |
||||||
|
fmt::println("{}", err); |
||||||
|
throw dbc::CheckError{err}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <fmt/core.h> |
||||||
|
#include <functional> |
||||||
|
|
||||||
|
using std::string; |
||||||
|
|
||||||
|
namespace dbc { |
||||||
|
class Error { |
||||||
|
public: |
||||||
|
const string message; |
||||||
|
Error(string m) : message{m} {} |
||||||
|
Error(const char *m) : message{m} {} |
||||||
|
}; |
||||||
|
|
||||||
|
class CheckError : public Error {}; |
||||||
|
class SentinelError : public Error {}; |
||||||
|
class PreCondError : public Error {}; |
||||||
|
class PostCondError : public Error {}; |
||||||
|
|
||||||
|
void log(const string &message); |
||||||
|
void sentinel(const string &message); |
||||||
|
void pre(const string &message, bool test); |
||||||
|
void pre(const string &message, std::function<bool()> tester); |
||||||
|
void post(const string &message, bool test); |
||||||
|
void post(const string &message, std::function<bool()> tester); |
||||||
|
void check(bool test, const string &message); |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <fmt/core.h> |
||||||
|
|
||||||
|
#ifndef FSM_DEBUG |
||||||
|
#define FSM_STATE(C, S, E, ...) case C::S: S(E, ##__VA_ARGS__); break |
||||||
|
#else |
||||||
|
#define FSM_STATE(C, S, E, ...) case C::S: fmt::println(">> " #C " " #S " event={}, state={}", int(E), int(_state)); S(E, ##__VA_ARGS__); fmt::println("<< " #C " state={}", int(_state)); break |
||||||
|
#endif |
||||||
|
|
||||||
|
template<typename S, typename E> |
||||||
|
class DeadSimpleFSM { |
||||||
|
protected: |
||||||
|
// BUG: don't put this in your class because state() won't work
|
||||||
|
S _state = S::START; |
||||||
|
|
||||||
|
public: |
||||||
|
template<typename... Types> |
||||||
|
void event(E event, Types... args); |
||||||
|
|
||||||
|
void state(S next_state) { |
||||||
|
_state = next_state; |
||||||
|
} |
||||||
|
|
||||||
|
bool in_state(S state) { |
||||||
|
return _state == state; |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,14 @@ |
|||||||
|
project('distributary', 'cpp', |
||||||
|
default_options: ['cpp_std=c++20']) |
||||||
|
|
||||||
|
catch2 = dependency('catch2-with-main') |
||||||
|
fmt = dependency('fmt') |
||||||
|
|
||||||
|
runtests = executable('runtests', [ |
||||||
|
'dbc.cpp', |
||||||
|
'tests/fsm.cpp', |
||||||
|
'tests/dbc.cpp', |
||||||
|
], |
||||||
|
dependencies: [catch2, fmt]) |
||||||
|
|
||||||
|
test('tests', runtests) |
@ -0,0 +1,11 @@ |
|||||||
|
mv .\subprojects\packagecache . |
||||||
|
rm -recurse -force .\subprojects\,.\builddir\ |
||||||
|
mkdir subprojects |
||||||
|
mv .\packagecache .\subprojects\ |
||||||
|
cp *.wrap subprojects |
||||||
|
mkdir builddir |
||||||
|
meson wrap install fmt |
||||||
|
meson wrap install catch2 |
||||||
|
# $env:CC="clang" |
||||||
|
# $env:CXX="clang++" |
||||||
|
meson setup --default-library=static --prefer-static builddir |
@ -0,0 +1,12 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
set -e |
||||||
|
|
||||||
|
mv -f ./subprojects/packagecache . |
||||||
|
rm -rf subprojects builddir |
||||||
|
mkdir subprojects |
||||||
|
mv packagecache ./subprojects/ |
||||||
|
mkdir builddir |
||||||
|
cp *.wrap subprojects |
||||||
|
meson wrap install fmt |
||||||
|
meson wrap install catch2 |
||||||
|
meson setup builddir |
@ -0,0 +1,39 @@ |
|||||||
|
#include <catch2/catch_test_macros.hpp> |
||||||
|
#include "dbc.hpp" |
||||||
|
|
||||||
|
using namespace dbc; |
||||||
|
|
||||||
|
TEST_CASE("basic feature tests", "[utils]") { |
||||||
|
log("Logging a message."); |
||||||
|
|
||||||
|
try { |
||||||
|
sentinel("This shouldn't happen."); |
||||||
|
} catch(SentinelError) { |
||||||
|
log("Sentinel happened."); |
||||||
|
} |
||||||
|
|
||||||
|
pre("confirm positive cases work", 1 == 1); |
||||||
|
pre("confirm positive lambda", [&]{ return 1 == 1;}); |
||||||
|
post("confirm positive post", 1 == 1); |
||||||
|
post("confirm postitive post with lamdba", [&]{ return 1 == 1;}); |
||||||
|
|
||||||
|
check(1 == 1, "one equals 1"); |
||||||
|
|
||||||
|
try { |
||||||
|
check(1 == 2, "this should fail"); |
||||||
|
} catch(CheckError err) { |
||||||
|
log("check fail worked"); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
pre("failing pre", 1 == 3); |
||||||
|
} catch(PreCondError err) { |
||||||
|
log("pre fail worked"); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
post("failing post", 1 == 4); |
||||||
|
} catch(PostCondError err) { |
||||||
|
log("post faile worked"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
#include <catch2/catch_test_macros.hpp> |
||||||
|
#include <fmt/core.h> |
||||||
|
#include <string> |
||||||
|
#include "../fsm.hpp" |
||||||
|
|
||||||
|
using namespace fmt; |
||||||
|
using std::string; |
||||||
|
|
||||||
|
enum class MyState { |
||||||
|
START, RUNNING, END |
||||||
|
}; |
||||||
|
|
||||||
|
enum class MyEvent { |
||||||
|
STARTED, PUSH, QUIT |
||||||
|
}; |
||||||
|
|
||||||
|
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> { |
||||||
|
public: |
||||||
|
void event(MyEvent ev, string data="") { |
||||||
|
switch(_state) { |
||||||
|
FSM_STATE(MyState, START, ev); |
||||||
|
FSM_STATE(MyState, RUNNING, ev, data); |
||||||
|
FSM_STATE(MyState, END, ev); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void START(MyEvent ev) { |
||||||
|
println("<<< START"); |
||||||
|
state(MyState::RUNNING); |
||||||
|
} |
||||||
|
|
||||||
|
void RUNNING(MyEvent ev, string &data) { |
||||||
|
if(ev == MyEvent::QUIT) { |
||||||
|
println("<<< QUITTING {}", data); |
||||||
|
state(MyState::END); |
||||||
|
} else { |
||||||
|
println("<<< RUN: {}", data); |
||||||
|
state(MyState::RUNNING); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void END(MyEvent ev) { |
||||||
|
println("<<< STOP"); |
||||||
|
state(MyState::END); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
TEST_CASE("confirm fsm works with optional data", "[utils]") { |
||||||
|
MyFSM fsm; |
||||||
|
|
||||||
|
REQUIRE(fsm.in_state(MyState::START)); |
||||||
|
|
||||||
|
fsm.event(MyEvent::STARTED); |
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH); |
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH); |
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH); |
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||||
|
|
||||||
|
fsm.event(MyEvent::QUIT, "DONE!"); |
||||||
|
REQUIRE(fsm.in_state(MyState::END)); |
||||||
|
} |
Loading…
Reference in new issue