reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

event.cpp (5584B)


      1 #include "helper.hpp"
      2 
      3 #include <event.hpp>
      4 
      5 #include <reaper_plugin_functions.h>
      6 
      7 static const char *M = "[event]";
      8 
      9 TEST_CASE("check whether an event has handlers subscribed to it", M) {
     10   Event<void()> e;
     11   REQUIRE_FALSE(e);
     12   e >> []{};
     13   REQUIRE(e);
     14 }
     15 
     16 TEST_CASE("remove all handlers subscribed to an event", M) {
     17   bool run = false;
     18   Event<void()> e;
     19   e >> [&]{ run = true; };
     20 
     21   e.reset();
     22   CHECK_FALSE(e);
     23 
     24   e();
     25   REQUIRE_FALSE(run);
     26 }
     27 
     28 TEST_CASE("Event<void(...)> handlers are run in order", M) {
     29   std::vector<int> bucket;
     30 
     31   Event<void()> e;
     32   e >> [&] { bucket.push_back(1); }
     33     >> [&] { bucket.push_back(2); };
     34 
     35   e();
     36 
     37   REQUIRE(bucket == decltype(bucket){1, 2});
     38 }
     39 
     40 TEST_CASE("Event<R(...)> handlers are run in order", M) {
     41   std::vector<int> bucket;
     42 
     43   Event<std::nullptr_t()> e;
     44   e >> [&] { bucket.push_back(1); return nullptr; }
     45     >> [&] { bucket.push_back(2); return nullptr; };
     46 
     47   e();
     48 
     49   REQUIRE(bucket == decltype(bucket){1, 2});
     50 }
     51 
     52 TEST_CASE("Event<R(...)> returns the last value") {
     53   Event<int()> e;
     54   REQUIRE_FALSE(e().has_value());
     55 
     56   e >> [] { return 1; }
     57     >> [] { return 2; }
     58     >> [] { return 3; };
     59 
     60   REQUIRE(e().has_value());
     61   REQUIRE(*e() == 3);
     62 }
     63 
     64 TEST_CASE("Event<void(...)> arguments are not copied more than necessary", M) {
     65   auto obj = std::make_shared<std::nullptr_t>();
     66   Event<void(decltype(obj), decltype(obj))> e;
     67 
     68   e >> [&obj](decltype(obj) a, decltype(obj) b) {
     69     // original copy + by-value parameter copies
     70     REQUIRE(obj.use_count() == 1 + 2);
     71   };
     72 
     73   e(obj, obj);
     74 };
     75 
     76 TEST_CASE("Event<R(...)> arguments are not copied more than necessary", M) {
     77   auto obj = std::make_shared<std::nullptr_t>();
     78   Event<std::nullptr_t(decltype(obj), decltype(obj))> e;
     79 
     80   e >> [&obj](decltype(obj) a, decltype(obj) b) {
     81     REQUIRE(obj.use_count() == 1 + 2);
     82     return nullptr;
     83   };
     84 
     85   e(obj, obj);
     86 };
     87 
     88 TEST_CASE("multiple AsyncEvent registers a single timer", M) {
     89   static std::vector<std::string> registered;
     90 
     91   plugin_register = [](const char *n, void *) {
     92     registered.push_back(n);
     93     return 0;
     94   };
     95 
     96   {
     97     AsyncEvent<void()> e1, e2;
     98     REQUIRE(registered == decltype(registered){"timer"});
     99   }
    100 
    101   REQUIRE(registered == decltype(registered){"timer", "-timer"});
    102 }
    103 
    104 TEST_CASE("AsyncEvent handlers are run asynchronously in order", M) {
    105   static void (*tick)() = nullptr;
    106   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    107 
    108   std::vector<size_t> bucket;
    109 
    110   AsyncEvent<void(size_t)> e;
    111   e >> [&](size_t i) { bucket.push_back(i); }
    112     >> [&](size_t i) { bucket.push_back(i * 10); };
    113 
    114   e(1);
    115   e(2);
    116   e(3);
    117 
    118   CHECK(bucket.empty());
    119   tick();
    120   REQUIRE(bucket == decltype(bucket){1, 10, 2, 20, 3, 30});
    121 }
    122 
    123 TEST_CASE("AsyncEvent<void(...)> sets the future's value", M) {
    124   static void (*tick)() = nullptr;
    125   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    126 
    127   AsyncEvent<void()> e;
    128   e >> []{};
    129 
    130   std::future<void> ret = e();
    131 
    132   REQUIRE(ret.wait_for(std::chrono::seconds(0)) == std::future_status::timeout);
    133   tick();
    134   REQUIRE(ret.wait_for(std::chrono::seconds(0)) == std::future_status::ready);
    135 }
    136 
    137 TEST_CASE("AsyncEvent<R(...)> sets the future's value", M) {
    138   static void (*tick)() = nullptr;
    139   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    140 
    141   AsyncEvent<std::string()> e;
    142   e >> []{ return "hello world"; }
    143     >> []{ return "foo bar"; };
    144 
    145   std::future<std::optional<std::string>> ret = e();
    146 
    147   REQUIRE(ret.wait_for(std::chrono::seconds(0)) == std::future_status::timeout);
    148   tick();
    149   REQUIRE(ret.wait_for(std::chrono::seconds(0)) == std::future_status::ready);
    150 
    151   std::optional<std::string> val = ret.get();
    152   REQUIRE(val.has_value());
    153   REQUIRE(*val == "foo bar");
    154 }
    155 
    156 TEST_CASE("running an AsyncEvent without handlers returns synchronously", M) {
    157   plugin_register = [](const char *, void *c) { return 0; };
    158 
    159   AsyncEvent<void()> e1;
    160   AsyncEvent<int()> e2;
    161 
    162   auto r1 = e1();
    163   auto r2 = e2();
    164 
    165   REQUIRE(r1.wait_for(std::chrono::seconds(0)) == std::future_status::ready);
    166   REQUIRE_FALSE(r2.get().has_value());
    167 }
    168 
    169 TEST_CASE("AsyncEvent<void(...)> arguments are not copied more than necessary", M) {
    170   static void (*tick)() = nullptr;
    171   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    172 
    173   auto obj = std::make_shared<std::nullptr_t>();
    174   AsyncEvent<void(decltype(obj), decltype(obj))> e;
    175 
    176   e >> [&obj](decltype(obj) a, decltype(obj) b) {
    177     REQUIRE(obj.use_count() == 1 + 2 + 2);
    178   };
    179 
    180   e(obj, obj);
    181   tick();
    182 };
    183 
    184 TEST_CASE("AsyncEvent<R(...)> arguments are not copied more than necessary", M) {
    185   static void (*tick)() = nullptr;
    186   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    187 
    188   auto obj = std::make_shared<std::nullptr_t>();
    189   AsyncEvent<std::nullptr_t(decltype(obj), decltype(obj))> e;
    190 
    191   e >> [&obj](decltype(obj) a, decltype(obj) b) {
    192     // original copy + async copies + by-value parameter copies
    193     REQUIRE(obj.use_count() == 1 + 2 + 2);
    194     return nullptr;
    195   };
    196 
    197   e(obj, obj);
    198   tick();
    199 };
    200 
    201 TEST_CASE("deleted not-yet-posted AsyncEvents are discarded", M) {
    202   static void (*tick)() = nullptr;
    203   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    204 
    205   AsyncEvent<void()> keepTimerAlive;
    206 
    207   {
    208     AsyncEvent<void()> e;
    209     e();
    210   }
    211 
    212   tick();
    213 }
    214 
    215 TEST_CASE("deleting AsyncEvent from handler is safe", M) {
    216   static void (*tick)() = nullptr;
    217   plugin_register = [](const char *, void *c) { tick = (void(*)())c; return 0; };
    218 
    219   auto e = new AsyncEvent<void()>();
    220   *e >> [e] { delete e; };
    221   (*e)();
    222 
    223   tick();
    224 }