aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/init_and_shutdown.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unit_tests/init_and_shutdown.cpp')
-rw-r--r--unit_tests/init_and_shutdown.cpp793
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
6TEST(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
66class 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
76TEST_F(Configure, AllocatorFalse)
77{
78 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = false}"), LuaError::OK);
79}
80
81// #################################################################################################
82
83TEST_F(Configure, AllocatorTrue)
84{
85 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = true}"), LuaError::OK);
86}
87
88// #################################################################################################
89
90TEST_F(Configure, AllocatorNumber)
91{
92 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 33}"), LuaError::OK);
93}
94
95// #################################################################################################
96
97TEST_F(Configure, AllocatorTable)
98{
99 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = {}}"), LuaError::OK);
100}
101
102// #################################################################################################
103
104TEST_F(Configure, AllocatorLuaFunction)
105{
106 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}"), LuaError::OK);
107}
108
109// #################################################################################################
110
111TEST_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
119TEST_F(Configure, AllocatorTypo)
120{
121 // oops, a typo
122 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 'Protected'}"), LuaError::OK);
123}
124
125// #################################################################################################
126
127TEST_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
135TEST_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
150TEST_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
164TEST_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
180TEST_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
199TEST_F(Configure, InternalAllocatorFalse)
200{
201 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = false}"), LuaError::OK);
202}
203
204// #################################################################################################
205
206TEST_F(Configure, InternalAllocatorTrue)
207{
208 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = true}"), LuaError::OK);
209}
210
211// #################################################################################################
212
213TEST_F(Configure, InternalAllocatorTable)
214{
215 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = {}}"), LuaError::OK);
216}
217
218// #################################################################################################
219
220TEST_F(Configure, InternalAllocatorFunction)
221{
222 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = function() end}"), LuaError::OK);
223}
224
225// #################################################################################################
226
227TEST_F(Configure, InternalAllocatorString)
228{
229 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = 'gluh'}"), LuaError::OK);
230}
231
232// #################################################################################################
233
234TEST_F(Configure, InternalAllocatorLibc)
235{
236 EXPECT_EQ(L.doString("require 'lanes'.configure{internal_allocator = 'libc'}"), LuaError::OK);
237}
238
239// #################################################################################################
240
241TEST_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
250TEST_F(Configure, KeepersGcThresholdTable)
251{
252 EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = {}}"), LuaError::OK);
253}
254
255// #################################################################################################
256
257TEST_F(Configure, KeepersGcThresholdString)
258{
259 EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = 'gluh'}"), LuaError::OK);
260}
261
262// #################################################################################################
263
264TEST_F(Configure, KeepersGcThresholdNegative)
265{
266 EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = -1}"), LuaError::OK);
267}
268
269// #################################################################################################
270
271TEST_F(Configure, KeepersGcThresholdZero)
272{
273 EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = 0}"), LuaError::OK);
274}
275
276// #################################################################################################
277
278TEST_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
287TEST_F(Configure, NbUserKeepersTable)
288{
289 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = {}}"), LuaError::OK);
290}
291
292// #################################################################################################
293
294TEST_F(Configure, NbUserKeepersString)
295{
296 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = 'gluh'}"), LuaError::OK);
297}
298
299// #################################################################################################
300
301TEST_F(Configure, NbUserKeepersNegative)
302{
303 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = -1}"), LuaError::OK);
304}
305
306// #################################################################################################
307
308TEST_F(Configure, NbUserKeepersZero)
309{
310 EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 0}"), LuaError::OK);
311}
312
313// #################################################################################################
314
315TEST_F(Configure, NbUserKeepersHundred)
316{
317 EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 100}"), LuaError::OK);
318}
319
320// #################################################################################################
321
322TEST_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
331TEST_F(Configure, OnStateCreateTable)
332{
333 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = {}}"), LuaError::OK);
334}
335
336// #################################################################################################
337
338TEST_F(Configure, OnStateCreateString)
339{
340 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 'gluh'}"), LuaError::OK);
341}
342
343// #################################################################################################
344
345TEST_F(Configure, OnStateCreateNumber)
346{
347 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 1}"), LuaError::OK);
348}
349
350// #################################################################################################
351
352TEST_F(Configure, OnStateCreateFalse)
353{
354 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = false}"), LuaError::OK);
355}
356
357// #################################################################################################
358
359TEST_F(Configure, OnStateCreateTrue)
360{
361 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = true}"), LuaError::OK);
362}
363
364// #################################################################################################
365
366TEST_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
374TEST_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
386TEST_F(Configure, ShutdownTimeoutTable)
387{
388 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = {}}"), LuaError::OK);
389}
390
391// #################################################################################################
392
393TEST_F(Configure, ShutdownTimeoutString)
394{
395 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = 'gluh'}"), LuaError::OK);
396}
397
398// #################################################################################################
399
400TEST_F(Configure, ShutdownTimeoutNegative)
401{
402 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = -0.001}"), LuaError::OK);
403}
404
405// #################################################################################################
406
407TEST_F(Configure, ShutdownTimeoutZero)
408{
409 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 0}"), LuaError::OK);
410}
411
412// #################################################################################################
413
414TEST_F(Configure, ShutdownTimeoutOne)
415{
416 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 1}"), LuaError::OK);
417}
418
419// #################################################################################################
420
421TEST_F(Configure, ShutdownTimeoutHour)
422{
423 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 3600}"), LuaError::OK);
424}
425
426// #################################################################################################
427
428TEST_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
437TEST_F(Configure, StripFunctionsTable)
438{
439 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = {}}"), LuaError::OK);
440}
441
442// #################################################################################################
443
444TEST_F(Configure, StripFunctionsString)
445{
446 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 'gluh'}"), LuaError::OK);
447}
448
449// #################################################################################################
450
451TEST_F(Configure, StripFunctionsNumber)
452{
453 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 1}"), LuaError::OK);
454}
455
456// #################################################################################################
457
458TEST_F(Configure, StripFunctionsFunction)
459{
460 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = print}"), LuaError::OK);
461}
462
463// #################################################################################################
464
465TEST_F(Configure, StripFunctionsFalse)
466{
467 EXPECT_EQ(L.doString("require 'lanes'.configure{strip_functions = false}"), LuaError::OK);
468}
469
470// #################################################################################################
471
472TEST_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
481TEST_F(Configure, TrackLanesTable)
482{
483 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = {}}"), LuaError::OK);
484}
485
486// #################################################################################################
487
488TEST_F(Configure, TrackLanesString)
489{
490 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 'gluh'}"), LuaError::OK);
491}
492
493// #################################################################################################
494
495TEST_F(Configure, TrackLanesNumber)
496{
497 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 1}"), LuaError::OK);
498}
499
500// #################################################################################################
501
502TEST_F(Configure, TrackLanesFunction)
503{
504 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = print}"), LuaError::OK);
505}
506
507// #################################################################################################
508
509TEST_F(Configure, TrackLanesFalse)
510{
511 EXPECT_EQ(L.doString("require 'lanes'.configure{track_lanes = false}"), LuaError::OK);
512}
513
514// #################################################################################################
515
516TEST_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
525TEST_F(Configure, VerboseErrorsTable)
526{
527 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = {}}"), LuaError::OK);
528}
529
530// #################################################################################################
531
532TEST_F(Configure, VerboseErrorsString)
533{
534 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 'gluh'}"), LuaError::OK);
535}
536
537// #################################################################################################
538
539TEST_F(Configure, VerboseErrorsNumber)
540{
541 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 1}"), LuaError::OK);
542}
543
544// #################################################################################################
545
546TEST_F(Configure, VerboseErrorsFunction)
547{
548 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = print}"), LuaError::OK);
549}
550
551// #################################################################################################
552
553TEST_F(Configure, VerboseErrorsFalse)
554{
555 EXPECT_EQ(L.doString("require 'lanes'.configure{verbose_errors = false}"), LuaError::OK);
556}
557
558// #################################################################################################
559
560TEST_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
569TEST_F(Configure, WithTimersTable)
570{
571 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = {}}"), LuaError::OK);
572}
573
574// #################################################################################################
575
576TEST_F(Configure, WithTimersString)
577{
578 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 'gluh'}"), LuaError::OK);
579}
580
581// #################################################################################################
582
583TEST_F(Configure, WithTimersNumber)
584{
585 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 1}"), LuaError::OK);
586}
587
588// #################################################################################################
589
590TEST_F(Configure, WithTimersFunction)
591{
592 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = print}"), LuaError::OK);
593}
594
595// #################################################################################################
596
597TEST_F(Configure, WithTimersFalse)
598{
599 EXPECT_EQ(L.doString("require 'lanes'.configure{with_timers = false}"), LuaError::OK);
600}
601
602// #################################################################################################
603
604TEST_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
613TEST_F(Configure, UnknownSettingTable)
614{
615 EXPECT_NE(L.doString("require 'lanes'.configure{[{}] = {}}"), LuaError::OK);
616}
617
618// #################################################################################################
619
620TEST_F(Configure, UnknownSettingBool)
621{
622 EXPECT_NE(L.doString("require 'lanes'.configure{[true] = 'gluh'}"), LuaError::OK);
623}
624
625// #################################################################################################
626
627TEST_F(Configure, UnknownSettingFunction)
628{
629 EXPECT_NE(L.doString("require 'lanes'.configure{[function() end] = 1}"), LuaError::OK);
630}
631
632// #################################################################################################
633
634TEST_F(Configure, UnknownSettingNumber)
635{
636 EXPECT_NE(L.doString("require 'lanes'.configure{[1] = function() end}"), LuaError::OK);
637}
638
639// #################################################################################################
640
641TEST_F(Configure, UnknownSettingString)
642{
643 EXPECT_NE(L.doString("require 'lanes'.configure{['gluh'] = false}"), LuaError::OK);
644}
645
646// #################################################################################################
647// #################################################################################################
648
649TEST(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
686namespace
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
700class 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
718TEST_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
729TEST_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
740TEST_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}