diff options
Diffstat (limited to 'unit_tests/init_and_shutdown.cpp')
-rw-r--r-- | unit_tests/init_and_shutdown.cpp | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/unit_tests/init_and_shutdown.cpp b/unit_tests/init_and_shutdown.cpp new file mode 100644 index 0000000..d45b52f --- /dev/null +++ b/unit_tests/init_and_shutdown.cpp | |||
@@ -0,0 +1,793 @@ | |||
1 | #include "_pch.hpp" | ||
2 | #include "shared.h" | ||
3 | |||
4 | // ################################################################################################# | ||
5 | |||
6 | TEST(Require, MissingBaseLibraries) | ||
7 | { | ||
8 | LuaState L{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; | ||
9 | |||
10 | // no base library loaded means no print() | ||
11 | EXPECT_NE(L.doString("print('hello')"), LuaError::OK); | ||
12 | L.stackCheck(1); | ||
13 | lua_pop(L, 1); | ||
14 | |||
15 | // need require() to require lanes | ||
16 | luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 0); | ||
17 | lua_pop(L, 1); | ||
18 | L.stackCheck(0); | ||
19 | |||
20 | // no base library loaded means lanes should issue an error | ||
21 | EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); | ||
22 | lua_pop(L, 1); | ||
23 | L.stackCheck(0); | ||
24 | |||
25 | // need base to make lanes happy | ||
26 | luaL_requiref(L, LUA_GNAME, luaopen_base, 1); | ||
27 | lua_pop(L, 1); | ||
28 | L.stackCheck(0); | ||
29 | |||
30 | // no table library loaded means lanes should issue an error | ||
31 | EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); | ||
32 | L.stackCheck(1); | ||
33 | lua_pop(L, 1); | ||
34 | |||
35 | // need table to make lanes happy | ||
36 | luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1); | ||
37 | lua_pop(L, 1); | ||
38 | L.stackCheck(0); | ||
39 | |||
40 | // no string library loaded means lanes should issue an error | ||
41 | EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); | ||
42 | lua_pop(L, 1); | ||
43 | L.stackCheck(0); | ||
44 | |||
45 | // need string to make lanes happy | ||
46 | luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1); | ||
47 | lua_pop(L, 1); | ||
48 | L.stackCheck(0); | ||
49 | |||
50 | // all required libraries are here: we should be happy | ||
51 | // that's only the case for Lua > 5.1 though, because the latter can't require() a module after a previously failed attempt (like we just did) | ||
52 | if constexpr (LUA_VERSION_NUM > 501) { | ||
53 | ASSERT_EQ(L.doString("require 'lanes'"), LuaError::OK); | ||
54 | } else { | ||
55 | // so let's do a fresh attempt in a virgin state where we have the 3 base libraries we need (plus 'package' to be able to require it of course) | ||
56 | LuaState L51{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; | ||
57 | luaL_requiref(L51, LUA_LOADLIBNAME, luaopen_package, 1); | ||
58 | luaL_requiref(L51, LUA_GNAME, luaopen_base, 1); | ||
59 | luaL_requiref(L51, LUA_TABLIBNAME, luaopen_table, 1); | ||
60 | luaL_requiref(L51, LUA_STRLIBNAME, luaopen_string, 1); | ||
61 | lua_settop(L51, 0); | ||
62 | ASSERT_EQ(L51.doString("require 'lanes'"), LuaError::OK); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | class Configure : public ::testing::Test | ||
67 | { | ||
68 | protected: | ||
69 | LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; | ||
70 | }; | ||
71 | |||
72 | // ################################################################################################# | ||
73 | // ################################################################################################# | ||
74 | // allocator should be "protected", a C function returning a suitable userdata, or nil | ||
75 | |||
76 | TEST_F(Configure, AllocatorFalse) | ||
77 | { | ||
78 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = false}"), LuaError::OK); | ||
79 | } | ||
80 | |||
81 | // ################################################################################################# | ||
82 | |||
83 | TEST_F(Configure, AllocatorTrue) | ||
84 | { | ||
85 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = true}"), LuaError::OK); | ||
86 | } | ||
87 | |||
88 | // ################################################################################################# | ||
89 | |||
90 | TEST_F(Configure, AllocatorNumber) | ||
91 | { | ||
92 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 33}"), LuaError::OK); | ||
93 | } | ||
94 | |||
95 | // ################################################################################################# | ||
96 | |||
97 | TEST_F(Configure, AllocatorTable) | ||
98 | { | ||
99 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = {}}"), LuaError::OK); | ||
100 | } | ||
101 | |||
102 | // ################################################################################################# | ||
103 | |||
104 | TEST_F(Configure, AllocatorLuaFunction) | ||
105 | { | ||
106 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}"), LuaError::OK); | ||
107 | } | ||
108 | |||
109 | // ################################################################################################# | ||
110 | |||
111 | TEST_F(Configure, AllocatorBadCFunction) | ||
112 | { | ||
113 | // a C function that doesn't return what we expect should cause an error too | ||
114 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = print}"), LuaError::OK); | ||
115 | } | ||
116 | |||
117 | // ################################################################################################# | ||
118 | |||
119 | TEST_F(Configure, AllocatorTypo) | ||
120 | { | ||
121 | // oops, a typo | ||
122 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 'Protected'}"), LuaError::OK); | ||
123 | } | ||
124 | |||
125 | // ################################################################################################# | ||
126 | |||
127 | TEST_F(Configure, AllocatorProtected) | ||
128 | { | ||
129 | // no typo, should work | ||
130 | EXPECT_EQ(L.doString("require 'lanes'.configure{allocator = 'protected'}"), LuaError::OK); | ||
131 | } | ||
132 | |||
133 | // ################################################################################################# | ||
134 | |||
135 | TEST_F(Configure, AllocatorCustomOk) | ||
136 | { | ||
137 | // a function that provides what we expect is fine | ||
138 | static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { | ||
139 | lanes::AllocatorDefinition* const _def{ new (L_) lanes::AllocatorDefinition{} }; | ||
140 | _def->initFrom(L_); | ||
141 | return 1; | ||
142 | }; | ||
143 | lua_pushcfunction(L, _provideAllocator); | ||
144 | lua_setglobal(L, "ProvideAllocator"); | ||
145 | EXPECT_EQ(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); | ||
146 | } | ||
147 | |||
148 | // ################################################################################################# | ||
149 | |||
150 | TEST_F(Configure, AllocatorCustomWrongResultType) | ||
151 | { | ||
152 | // a function that provides something that is definitely not an AllocatorDefinition, should cause an error | ||
153 | static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { | ||
154 | lua_newtable(L_); | ||
155 | return 1; | ||
156 | }; | ||
157 | lua_pushcfunction(L, _provideAllocator); | ||
158 | lua_setglobal(L, "ProvideAllocator"); | ||
159 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); | ||
160 | } | ||
161 | |||
162 | // ################################################################################################# | ||
163 | |||
164 | TEST_F(Configure, AllocatorCustomSignatureMismatch) | ||
165 | { | ||
166 | // a function that provides something that is too small to contain an AllocatorDefinition, should cause an error | ||
167 | static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { | ||
168 | // create a full userdata that is too small (it only contains enough to store a version tag, but not the rest | ||
169 | auto* const _duck{ static_cast<lanes::AllocatorDefinition::version_t*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition::version_t))) }; | ||
170 | *_duck = 666777; | ||
171 | return 1; | ||
172 | }; | ||
173 | lua_pushcfunction(L, _provideAllocator); | ||
174 | lua_setglobal(L, "ProvideAllocator"); | ||
175 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); | ||
176 | } | ||
177 | |||
178 | // ################################################################################################# | ||
179 | |||
180 | TEST_F(Configure, AllocatorCustomSizeMismatch) | ||
181 | { | ||
182 | // a function that provides something that attempts to pass as an AllocatorDefinition, but is not, should cause an error | ||
183 | static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { | ||
184 | // create a full userdata of the correct size, but of course the contents don't match | ||
185 | int* const _duck{ static_cast<int*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition))) }; | ||
186 | _duck[0] = 666; | ||
187 | _duck[1] = 777; | ||
188 | return 1; | ||
189 | }; | ||
190 | lua_pushcfunction(L, _provideAllocator); | ||
191 | lua_setglobal(L, "ProvideAllocator"); | ||
192 | EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); | ||
193 | } | ||
194 | |||
195 | // ################################################################################################# | ||
196 | // ################################################################################################# | ||
197 | // internal_allocator should be a string, "libc"/"allocator" | ||
198 | |||
199 | TEST_F(Configure, InternalAllocatorFalse) | ||
200 | { | ||
201 | EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = false}"), LuaError::OK); | ||
202 | } | ||
203 | |||
204 | // ################################################################################################# | ||
205 | |||
206 | TEST_F(Configure, InternalAllocatorTrue) | ||
207 | { | ||
208 | EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = true}"), LuaError::OK); | ||
209 | } | ||
210 | |||
211 | // ################################################################################################# | ||
212 | |||
213 | TEST_F(Configure, InternalAllocatorTable) | ||
214 | { | ||
215 | EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = {}}"), LuaError::OK); | ||
216 | } | ||
217 | |||
218 | // ################################################################################################# | ||
219 | |||
220 | TEST_F(Configure, InternalAllocatorFunction) | ||
221 | { | ||
222 | EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = function() end}"), LuaError::OK); | ||
223 | } | ||
224 | |||
225 | // ################################################################################################# | ||
226 | |||
227 | TEST_F(Configure, InternalAllocatorString) | ||
228 | { | ||
229 | EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = 'gluh'}"), LuaError::OK); | ||
230 | } | ||
231 | |||
232 | // ################################################################################################# | ||
233 | |||
234 | TEST_F(Configure, InternalAllocatorLibc) | ||
235 | { | ||
236 | EXPECT_EQ(L.doString("require 'lanes'.configure{internal_allocator = 'libc'}"), LuaError::OK); | ||
237 | } | ||
238 | |||
239 | // ################################################################################################# | ||
240 | |||
241 | TEST_F(Configure, InternalAllocatorAllocator) | ||
242 | { | ||
243 | EXPECT_EQ(L.doString("require 'lanes'.configure{internal_allocator = 'allocator'}"), LuaError::OK); | ||
244 | } | ||
245 | |||
246 | // ################################################################################################# | ||
247 | // ################################################################################################# | ||
248 | // keepers_gc_threshold should be a number in [0, 100] | ||
249 | |||
250 | TEST_F(Configure, KeepersGcThresholdTable) | ||
251 | { | ||
252 | EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = {}}"), LuaError::OK); | ||
253 | } | ||
254 | |||
255 | // ################################################################################################# | ||
256 | |||
257 | TEST_F(Configure, KeepersGcThresholdString) | ||
258 | { | ||
259 | EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = 'gluh'}"), LuaError::OK); | ||
260 | } | ||
261 | |||
262 | // ################################################################################################# | ||
263 | |||
264 | TEST_F(Configure, KeepersGcThresholdNegative) | ||
265 | { | ||
266 | EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = -1}"), LuaError::OK); | ||
267 | } | ||
268 | |||
269 | // ################################################################################################# | ||
270 | |||
271 | TEST_F(Configure, KeepersGcThresholdZero) | ||
272 | { | ||
273 | EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = 0}"), LuaError::OK); | ||
274 | } | ||
275 | |||
276 | // ################################################################################################# | ||
277 | |||
278 | TEST_F(Configure, KeepersGcThresholdHundred) | ||
279 | { | ||
280 | EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = 100}"), LuaError::OK); | ||
281 | } | ||
282 | |||
283 | // ################################################################################################# | ||
284 | // ################################################################################################# | ||
285 | // nb_user_keepers should be a number in [0, 100] | ||
286 | |||
287 | TEST_F(Configure, NbUserKeepersTable) | ||
288 | { | ||
289 | EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = {}}"), LuaError::OK); | ||
290 | } | ||
291 | |||
292 | // ################################################################################################# | ||
293 | |||
294 | TEST_F(Configure, NbUserKeepersString) | ||
295 | { | ||
296 | EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = 'gluh'}"), LuaError::OK); | ||
297 | } | ||
298 | |||
299 | // ################################################################################################# | ||
300 | |||
301 | TEST_F(Configure, NbUserKeepersNegative) | ||
302 | { | ||
303 | EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = -1}"), LuaError::OK); | ||
304 | } | ||
305 | |||
306 | // ################################################################################################# | ||
307 | |||
308 | TEST_F(Configure, NbUserKeepersZero) | ||
309 | { | ||
310 | EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 0}"), LuaError::OK); | ||
311 | } | ||
312 | |||
313 | // ################################################################################################# | ||
314 | |||
315 | TEST_F(Configure, NbUserKeepersHundred) | ||
316 | { | ||
317 | EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 100}"), LuaError::OK); | ||
318 | } | ||
319 | |||
320 | // ################################################################################################# | ||
321 | |||
322 | TEST_F(Configure, NbUserKeepersHundredAndOne) | ||
323 | { | ||
324 | EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = 101}"), LuaError::OK); | ||
325 | } | ||
326 | |||
327 | // ################################################################################################# | ||
328 | // ################################################################################################# | ||
329 | // on_state_create should be a function, either C or Lua, without upvalues | ||
330 | |||
331 | TEST_F(Configure, OnStateCreateTable) | ||
332 | { | ||
333 | EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = {}}"), LuaError::OK); | ||
334 | } | ||
335 | |||
336 | // ################################################################################################# | ||
337 | |||
338 | TEST_F(Configure, OnStateCreateString) | ||
339 | { | ||
340 | EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 'gluh'}"), LuaError::OK); | ||
341 | } | ||
342 | |||
343 | // ################################################################################################# | ||
344 | |||
345 | TEST_F(Configure, OnStateCreateNumber) | ||
346 | { | ||
347 | EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 1}"), LuaError::OK); | ||
348 | } | ||
349 | |||
350 | // ################################################################################################# | ||
351 | |||
352 | TEST_F(Configure, OnStateCreateFalse) | ||
353 | { | ||
354 | EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = false}"), LuaError::OK); | ||
355 | } | ||
356 | |||
357 | // ################################################################################################# | ||
358 | |||
359 | TEST_F(Configure, OnStateCreateTrue) | ||
360 | { | ||
361 | EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = true}"), LuaError::OK); | ||
362 | } | ||
363 | |||
364 | // ################################################################################################# | ||
365 | |||
366 | TEST_F(Configure, OnStateCreateUpvaluedFunction) | ||
367 | { | ||
368 | // on_state_create isn't called inside a Keeper state if it's a Lua function (which is good as print() doesn't exist there!) | ||
369 | EXPECT_EQ(L.doString("local print = print; require 'lanes'.configure{on_state_create = function() print 'hello' end}"), LuaError::OK); | ||
370 | } | ||
371 | |||
372 | // ################################################################################################# | ||
373 | |||
374 | TEST_F(Configure, OnStateCreateCFunction) | ||
375 | { | ||
376 | // funnily enough, in Lua 5.3, print() uses global tostring(), that doesn't exist in a keeper since we didn't open libs -> "attempt to call a nil value" | ||
377 | // conclusion, don't use print() as a fake on_state_create() callback! | ||
378 | // assert() should be fine since we pass a non-false argument to on_state_create | ||
379 | EXPECT_EQ(L.doString("require 'lanes'.configure{on_state_create = assert}"), LuaError::OK); | ||
380 | } | ||
381 | |||
382 | // ################################################################################################# | ||
383 | // ################################################################################################# | ||
384 | // shutdown_timeout should be a number in [0,3600] | ||
385 | |||
386 | TEST_F(Configure, ShutdownTimeoutTable) | ||
387 | { | ||
388 | EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = {}}"), LuaError::OK); | ||
389 | } | ||
390 | |||
391 | // ################################################################################################# | ||
392 | |||
393 | TEST_F(Configure, ShutdownTimeoutString) | ||
394 | { | ||
395 | EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = 'gluh'}"), LuaError::OK); | ||
396 | } | ||
397 | |||
398 | // ################################################################################################# | ||
399 | |||
400 | TEST_F(Configure, ShutdownTimeoutNegative) | ||
401 | { | ||
402 | EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = -0.001}"), LuaError::OK); | ||
403 | } | ||
404 | |||
405 | // ################################################################################################# | ||
406 | |||
407 | TEST_F(Configure, ShutdownTimeoutZero) | ||
408 | { | ||
409 | EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 0}"), LuaError::OK); | ||
410 | } | ||
411 | |||
412 | // ################################################################################################# | ||
413 | |||
414 | TEST_F(Configure, ShutdownTimeoutOne) | ||
415 | { | ||
416 | EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 1}"), LuaError::OK); | ||
417 | } | ||
418 | |||
419 | // ################################################################################################# | ||
420 | |||
421 | TEST_F(Configure, ShutdownTimeoutHour) | ||
422 | { | ||
423 | EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 3600}"), LuaError::OK); | ||
424 | } | ||
425 | |||
426 | // ################################################################################################# | ||
427 | |||
428 | TEST_F(Configure, ShutdownTimeoutTooLong) | ||
429 | { | ||
430 | EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = 3600.001}"), LuaError::OK); | ||
431 | } | ||
432 | |||
433 | // ################################################################################################# | ||
434 | // ################################################################################################# | ||
435 | // strip_functions should be a boolean | ||
436 | |||
437 | TEST_F(Configure, StripFunctionsTable) | ||
438 | { | ||
439 | EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = {}}"), LuaError::OK); | ||
440 | } | ||
441 | |||
442 | // ################################################################################################# | ||
443 | |||
444 | TEST_F(Configure, StripFunctionsString) | ||
445 | { | ||
446 | EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 'gluh'}"), LuaError::OK); | ||
447 | } | ||
448 | |||
449 | // ################################################################################################# | ||
450 | |||
451 | TEST_F(Configure, StripFunctionsNumber) | ||
452 | { | ||
453 | EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 1}"), LuaError::OK); | ||
454 | } | ||
455 | |||
456 | // ################################################################################################# | ||
457 | |||
458 | TEST_F(Configure, StripFunctionsFunction) | ||
459 | { | ||
460 | EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = print}"), LuaError::OK); | ||
461 | } | ||
462 | |||
463 | // ################################################################################################# | ||
464 | |||
465 | TEST_F(Configure, StripFunctionsFalse) | ||
466 | { | ||
467 | EXPECT_EQ(L.doString("require 'lanes'.configure{strip_functions = false}"), LuaError::OK); | ||
468 | } | ||
469 | |||
470 | // ################################################################################################# | ||
471 | |||
472 | TEST_F(Configure, StripFunctionsTrue) | ||
473 | { | ||
474 | EXPECT_EQ(L.doString("require 'lanes'.configure{strip_functions = true}"), LuaError::OK); | ||
475 | } | ||
476 | |||
477 | // ################################################################################################# | ||
478 | // ################################################################################################# | ||
479 | // track_lanes should be a boolean | ||
480 | |||
481 | TEST_F(Configure, TrackLanesTable) | ||
482 | { | ||
483 | EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = {}}"), LuaError::OK); | ||
484 | } | ||
485 | |||
486 | // ################################################################################################# | ||
487 | |||
488 | TEST_F(Configure, TrackLanesString) | ||
489 | { | ||
490 | EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 'gluh'}"), LuaError::OK); | ||
491 | } | ||
492 | |||
493 | // ################################################################################################# | ||
494 | |||
495 | TEST_F(Configure, TrackLanesNumber) | ||
496 | { | ||
497 | EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 1}"), LuaError::OK); | ||
498 | } | ||
499 | |||
500 | // ################################################################################################# | ||
501 | |||
502 | TEST_F(Configure, TrackLanesFunction) | ||
503 | { | ||
504 | EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = print}"), LuaError::OK); | ||
505 | } | ||
506 | |||
507 | // ################################################################################################# | ||
508 | |||
509 | TEST_F(Configure, TrackLanesFalse) | ||
510 | { | ||
511 | EXPECT_EQ(L.doString("require 'lanes'.configure{track_lanes = false}"), LuaError::OK); | ||
512 | } | ||
513 | |||
514 | // ################################################################################################# | ||
515 | |||
516 | TEST_F(Configure, TrackLanesTrue) | ||
517 | { | ||
518 | EXPECT_EQ(L.doString("require 'lanes'.configure{track_lanes = true}"), LuaError::OK); | ||
519 | } | ||
520 | |||
521 | // ################################################################################################# | ||
522 | // ################################################################################################# | ||
523 | // verbose_errors should be a boolean | ||
524 | |||
525 | TEST_F(Configure, VerboseErrorsTable) | ||
526 | { | ||
527 | EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = {}}"), LuaError::OK); | ||
528 | } | ||
529 | |||
530 | // ################################################################################################# | ||
531 | |||
532 | TEST_F(Configure, VerboseErrorsString) | ||
533 | { | ||
534 | EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 'gluh'}"), LuaError::OK); | ||
535 | } | ||
536 | |||
537 | // ################################################################################################# | ||
538 | |||
539 | TEST_F(Configure, VerboseErrorsNumber) | ||
540 | { | ||
541 | EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 1}"), LuaError::OK); | ||
542 | } | ||
543 | |||
544 | // ################################################################################################# | ||
545 | |||
546 | TEST_F(Configure, VerboseErrorsFunction) | ||
547 | { | ||
548 | EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = print}"), LuaError::OK); | ||
549 | } | ||
550 | |||
551 | // ################################################################################################# | ||
552 | |||
553 | TEST_F(Configure, VerboseErrorsFalse) | ||
554 | { | ||
555 | EXPECT_EQ(L.doString("require 'lanes'.configure{verbose_errors = false}"), LuaError::OK); | ||
556 | } | ||
557 | |||
558 | // ################################################################################################# | ||
559 | |||
560 | TEST_F(Configure, VerboseErrorsTrue) | ||
561 | { | ||
562 | EXPECT_EQ(L.doString("require 'lanes'.configure{verbose_errors = true}"), LuaError::OK); | ||
563 | } | ||
564 | |||
565 | // ################################################################################################# | ||
566 | // ################################################################################################# | ||
567 | // with_timers should be a boolean | ||
568 | |||
569 | TEST_F(Configure, WithTimersTable) | ||
570 | { | ||
571 | EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = {}}"), LuaError::OK); | ||
572 | } | ||
573 | |||
574 | // ################################################################################################# | ||
575 | |||
576 | TEST_F(Configure, WithTimersString) | ||
577 | { | ||
578 | EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 'gluh'}"), LuaError::OK); | ||
579 | } | ||
580 | |||
581 | // ################################################################################################# | ||
582 | |||
583 | TEST_F(Configure, WithTimersNumber) | ||
584 | { | ||
585 | EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 1}"), LuaError::OK); | ||
586 | } | ||
587 | |||
588 | // ################################################################################################# | ||
589 | |||
590 | TEST_F(Configure, WithTimersFunction) | ||
591 | { | ||
592 | EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = print}"), LuaError::OK); | ||
593 | } | ||
594 | |||
595 | // ################################################################################################# | ||
596 | |||
597 | TEST_F(Configure, WithTimersFalse) | ||
598 | { | ||
599 | EXPECT_EQ(L.doString("require 'lanes'.configure{with_timers = false}"), LuaError::OK); | ||
600 | } | ||
601 | |||
602 | // ################################################################################################# | ||
603 | |||
604 | TEST_F(Configure, WithTimersTrue) | ||
605 | { | ||
606 | EXPECT_EQ(L.doString("require 'lanes'.configure{with_timers = true}"), LuaError::OK); | ||
607 | } | ||
608 | |||
609 | // ################################################################################################# | ||
610 | // ################################################################################################# | ||
611 | // any unknown setting should be rejected | ||
612 | |||
613 | TEST_F(Configure, UnknownSettingTable) | ||
614 | { | ||
615 | EXPECT_NE(L.doString("require 'lanes'.configure{[{}] = {}}"), LuaError::OK); | ||
616 | } | ||
617 | |||
618 | // ################################################################################################# | ||
619 | |||
620 | TEST_F(Configure, UnknownSettingBool) | ||
621 | { | ||
622 | EXPECT_NE(L.doString("require 'lanes'.configure{[true] = 'gluh'}"), LuaError::OK); | ||
623 | } | ||
624 | |||
625 | // ################################################################################################# | ||
626 | |||
627 | TEST_F(Configure, UnknownSettingFunction) | ||
628 | { | ||
629 | EXPECT_NE(L.doString("require 'lanes'.configure{[function() end] = 1}"), LuaError::OK); | ||
630 | } | ||
631 | |||
632 | // ################################################################################################# | ||
633 | |||
634 | TEST_F(Configure, UnknownSettingNumber) | ||
635 | { | ||
636 | EXPECT_NE(L.doString("require 'lanes'.configure{[1] = function() end}"), LuaError::OK); | ||
637 | } | ||
638 | |||
639 | // ################################################################################################# | ||
640 | |||
641 | TEST_F(Configure, UnknownSettingString) | ||
642 | { | ||
643 | EXPECT_NE(L.doString("require 'lanes'.configure{['gluh'] = false}"), LuaError::OK); | ||
644 | } | ||
645 | |||
646 | // ################################################################################################# | ||
647 | // ################################################################################################# | ||
648 | |||
649 | TEST(Lanes, Finally) | ||
650 | { | ||
651 | { | ||
652 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; | ||
653 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global | ||
654 | EXPECT_EQ(S.doString("lanes = require 'lanes'"), LuaError::OK) << S; | ||
655 | // we can set a function | ||
656 | EXPECT_EQ(S.doString("lanes.finally(function() end)"), LuaError::OK) << S; | ||
657 | // we can clear it | ||
658 | EXPECT_EQ(S.doString("lanes.finally(nil)"), LuaError::OK) << S; | ||
659 | // we can set a new one | ||
660 | EXPECT_EQ(S.doString("lanes.finally(function() end)"), LuaError::OK) << S; | ||
661 | // we can replace an existing function | ||
662 | EXPECT_EQ(S.doString("lanes.finally(error)"), LuaError::OK) << S; | ||
663 | // even if the finalizer throws a Lua error, it shouldn't crash anything | ||
664 | ASSERT_NO_FATAL_FAILURE(S.close()); | ||
665 | ASSERT_EQ(S.finalizerWasCalled, false); | ||
666 | } | ||
667 | |||
668 | { | ||
669 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; | ||
670 | |||
671 | // we need Lanes to be up. Since we run several 'scripts', we store it as a global | ||
672 | EXPECT_EQ(S.doString("lanes = require 'lanes'"), LuaError::OK) << S; | ||
673 | // works because we have package.preload.fixture = luaopen_fixture | ||
674 | EXPECT_EQ(S.doString("fixture = require 'fixture'"), LuaError::OK) << S; | ||
675 | // set our detectable finalizer | ||
676 | EXPECT_EQ(S.doString("lanes.finally(fixture.throwing_finalizer)"), LuaError::OK) << S; | ||
677 | // even if the finalizer can request a C++ exception, it shouldn't do it just now since we have no dangling lane | ||
678 | ASSERT_NO_THROW(S.close()) << S; | ||
679 | // the finalizer should be called | ||
680 | ASSERT_EQ(S.finalizerWasCalled, true); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | // ################################################################################################# | ||
685 | |||
686 | namespace | ||
687 | { | ||
688 | namespace local | ||
689 | { | ||
690 | std::atomic_int OnStateCreateCallsCount{}; | ||
691 | static int on_state_create(lua_State* const L_) | ||
692 | { | ||
693 | OnStateCreateCallsCount.fetch_add(1, std::memory_order_relaxed); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | } // namespace local | ||
698 | } | ||
699 | |||
700 | class OnStateCreate : public ::testing::Test | ||
701 | { | ||
702 | protected: | ||
703 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; | ||
704 | |||
705 | void SetUp() override | ||
706 | { | ||
707 | local::OnStateCreateCallsCount.store(0, std::memory_order_relaxed); | ||
708 | } | ||
709 | |||
710 | void TearDown() override | ||
711 | { | ||
712 | local::OnStateCreateCallsCount.store(0, std::memory_order_relaxed); | ||
713 | } | ||
714 | }; | ||
715 | |||
716 | // ################################################################################################# | ||
717 | |||
718 | TEST_F(OnStateCreate, CalledInKeepers) | ||
719 | { | ||
720 | // _G.on_state_create = on_state_create; | ||
721 | lua_pushcfunction(S, local::on_state_create); | ||
722 | lua_setglobal(S, "on_state_create"); | ||
723 | ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create, nb_user_keepers = 3}"), LuaError::OK) << S; | ||
724 | ASSERT_EQ(local::OnStateCreateCallsCount.load(std::memory_order_relaxed), 4) << "on_state_create should have been called once in each Keeper state"; | ||
725 | } | ||
726 | |||
727 | // ################################################################################################# | ||
728 | |||
729 | TEST_F(OnStateCreate, CalledInLane) | ||
730 | { | ||
731 | // _G.on_state_create = on_state_create; | ||
732 | lua_pushcfunction(S, local::on_state_create); | ||
733 | lua_setglobal(S, "on_state_create"); | ||
734 | ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create, with_timers = true}"), LuaError::OK) << S; | ||
735 | ASSERT_EQ(local::OnStateCreateCallsCount.load(std::memory_order_relaxed), 2) << "on_state_create should have been called in the Keeper state and the timer lane"; | ||
736 | } | ||
737 | |||
738 | // ################################################################################################# | ||
739 | |||
740 | TEST_F(OnStateCreate, CanPackagePreload) | ||
741 | { | ||
742 | // a C function for which we can test it was called | ||
743 | static bool _doStuffWasCalled{}; | ||
744 | static auto _doStuff = +[](lua_State* const L_) { | ||
745 | _doStuffWasCalled = true; | ||
746 | return 0; | ||
747 | }; | ||
748 | |||
749 | // a module that exports the above function | ||
750 | static auto _luaopen_Stuff = +[](lua_State* const L_) { | ||
751 | lua_newtable(L_); // t | ||
752 | lua_pushstring(L_, "DoStuffInC"); // t "DoStuffInC" | ||
753 | lua_pushcfunction(L_, _doStuff); // t "DoStuffInC" _doStuff | ||
754 | lua_settable(L_, -3); // t | ||
755 | return 1; | ||
756 | }; | ||
757 | |||
758 | // a function that installs the module loader function in package.preload | ||
759 | auto _on_state_create = [](lua_State* const L_) { | ||
760 | |||
761 | lua_getglobal(L_, "package"); // package | ||
762 | if (lua_istable(L_, -1)) { | ||
763 | lua_getfield(L_, -1, "preload"); // package package.preload | ||
764 | if (lua_istable(L_, -1)) { | ||
765 | lua_pushcfunction(L_, _luaopen_Stuff); // package package.preload luaopen_Stuff | ||
766 | lua_setfield(L_, -2, "Stuff"); // package package.preload | ||
767 | } | ||
768 | lua_pop(L_, 1); // package | ||
769 | } | ||
770 | lua_pop(L_, 1); // | ||
771 | |||
772 | return 0; | ||
773 | }; | ||
774 | |||
775 | // _G.on_state_create = on_state_create; | ||
776 | lua_pushcfunction(S, _on_state_create); | ||
777 | lua_setglobal(S, "on_state_create"); | ||
778 | |||
779 | ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create}"), LuaError::OK) << S; | ||
780 | |||
781 | // launch a Lane that requires the module. It should succeed because _on_state_create was called and made it possible | ||
782 | std::string_view const _script{ | ||
783 | " f = lanes.gen('*'," | ||
784 | " function()" | ||
785 | " local Stuff = require ('Stuff')" | ||
786 | " Stuff.DoStuffInC()" | ||
787 | " return true" | ||
788 | " end)" | ||
789 | " f():join()" // start the lane and block until it terminates | ||
790 | }; | ||
791 | ASSERT_EQ(S.doString(_script), LuaError::OK) << S; | ||
792 | ASSERT_TRUE(_doStuffWasCalled); | ||
793 | } | ||