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 }