aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/lane_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--unit_tests/lane_tests.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/unit_tests/lane_tests.cpp b/unit_tests/lane_tests.cpp
new file mode 100644
index 0000000..14a327f
--- /dev/null
+++ b/unit_tests/lane_tests.cpp
@@ -0,0 +1,209 @@
1#include "_pch.hpp"
2#include "shared.h"
3
4// #################################################################################################
5// #################################################################################################
6
7class LaneTests : public ::testing::Test
8{
9 protected:
10 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
11
12 void SetUp() override
13 {
14 std::ignore = S.doString("lanes = require 'lanes'.configure()");
15 }
16};
17
18// #################################################################################################
19
20TEST_F(LaneTests, GeneratorCreation)
21{
22 // no parameter is bad
23 EXPECT_NE(S.doString("lanes.gen()"), LuaError::OK);
24
25 // minimal generator needs a function
26 EXPECT_EQ(S.doString("lanes.gen(function() end)"), LuaError::OK) << S;
27
28 // acceptable parameters for the generator are strings, tables, nil, followed by the function body
29 EXPECT_EQ(S.doString("lanes.gen(nil, function() end)"), LuaError::OK) << S;
30 EXPECT_EQ(S.doString("lanes.gen('', function() end)"), LuaError::OK) << S;
31 EXPECT_EQ(S.doString("lanes.gen({}, function() end)"), LuaError::OK) << S;
32 EXPECT_EQ(S.doString("lanes.gen('', {}, function() end)"), LuaError::OK) << S;
33 EXPECT_EQ(S.doString("lanes.gen({}, '', function() end)"), LuaError::OK) << S;
34 EXPECT_EQ(S.doString("lanes.gen('', '', function() end)"), LuaError::OK) << S;
35 EXPECT_EQ(S.doString("lanes.gen({}, {}, function() end)"), LuaError::OK) << S;
36
37 // anything different should fail: booleans, numbers, any userdata
38 EXPECT_NE(S.doString("lanes.gen(false, function() end)"), LuaError::OK);
39 EXPECT_NE(S.doString("lanes.gen(true, function() end)"), LuaError::OK);
40 EXPECT_NE(S.doString("lanes.gen(42, function() end)"), LuaError::OK);
41 EXPECT_NE(S.doString("lanes.gen(io.stdin, function() end)"), LuaError::OK);
42 EXPECT_NE(S.doString("lanes.gen(lanes.linda(), function() end)"), LuaError::OK);
43 EXPECT_NE(S.doString("lanes.gen(lanes.linda():deep(), function() end)"), LuaError::OK);
44
45 // even if parameter types are correct, the function must come last
46 EXPECT_NE(S.doString("lanes.gen(function() end, '')"), LuaError::OK);
47
48 // the strings should only list "known base libraries", in any order, or "*"
49 // if the particular Lua flavor we build for doesn't support them, they raise an error unless postfixed by '?'
50 EXPECT_EQ(S.doString("lanes.gen('base', function() end)"), LuaError::OK) << S;
51
52 // bit, ffi, jit are LuaJIT-specific
53#if LUAJIT_FLAVOR() == 0
54 EXPECT_NE(S.doString("lanes.gen('bit,ffi,jit', function() end)"), LuaError::OK);
55 EXPECT_EQ(S.doString("lanes.gen('bit?,ffi?,jit?', function() end)"), LuaError::OK) << S;
56#endif // LUAJIT_FLAVOR()
57
58 // bit32 library existed only in Lua 5.2, there is still a loader that will raise an error in Lua 5.3
59#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
60 EXPECT_EQ(S.doString("lanes.gen('bit32', function() end)"), LuaError::OK) << S;
61#else // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
62 EXPECT_NE(S.doString("lanes.gen('bit32', function() end)"), LuaError::OK);
63 EXPECT_EQ(S.doString("lanes.gen('bit32?', function() end)"), LuaError::OK) << S;
64#endif // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
65
66 // coroutine library appeared with Lua 5.2
67#if LUA_VERSION_NUM == 501
68 EXPECT_NE(S.doString("lanes.gen('coroutine', function() end)"), LuaError::OK);
69 EXPECT_EQ(S.doString("lanes.gen('coroutine?', function() end)"), LuaError::OK) << S;
70#endif // LUA_VERSION_NUM == 501
71
72 EXPECT_EQ(S.doString("lanes.gen('debug', function() end)"), LuaError::OK) << S;
73 EXPECT_EQ(S.doString("lanes.gen('io', function() end)"), LuaError::OK) << S;
74 EXPECT_EQ(S.doString("lanes.gen('math', function() end)"), LuaError::OK) << S;
75 EXPECT_EQ(S.doString("lanes.gen('os', function() end)"), LuaError::OK) << S;
76 EXPECT_EQ(S.doString("lanes.gen('package', function() end)"), LuaError::OK) << S;
77 EXPECT_EQ(S.doString("lanes.gen('string', function() end)"), LuaError::OK) << S;
78 EXPECT_EQ(S.doString("lanes.gen('table', function() end)"), LuaError::OK) << S;
79
80 // utf8 library appeared with Lua 5.3
81#if LUA_VERSION_NUM < 503
82 EXPECT_NE(S.doString("lanes.gen('utf8', function() end)"), LuaError::OK);
83 EXPECT_EQ(S.doString("lanes.gen('utf8?', function() end)"), LuaError::OK) << S;
84#endif // LUA_VERSION_NUM < 503
85
86 EXPECT_EQ(S.doString("lanes.gen('lanes.core', function() end)"), LuaError::OK) << S;
87 // "*" repeated or combined with anything else is forbidden
88 EXPECT_NE(S.doString("lanes.gen('*', '*', function() end)"), LuaError::OK);
89 EXPECT_NE(S.doString("lanes.gen('base', '*', function() end)"), LuaError::OK);
90 // unknown names are forbidden
91 EXPECT_NE(S.doString("lanes.gen('Base', function() end)"), LuaError::OK);
92 // repeating the same library more than once is forbidden
93 EXPECT_NE(S.doString("lanes.gen('base,base', function() end)"), LuaError::OK);
94}
95
96// #################################################################################################
97
98TEST_F(LaneTests, UncooperativeShutdown)
99{
100 // prepare a callback for lanes.finally()
101 static bool _wasCalled{};
102 static bool _allLanesTerminated{};
103 auto _finallyCB{ +[](lua_State* const L_) { _wasCalled = true; _allLanesTerminated = lua_toboolean(L_, 1); return 0; } };
104 lua_pushcfunction(S, _finallyCB);
105 lua_setglobal(S, "finallyCB");
106 // start a lane that lasts a long time
107 std::string_view const script{
108 " lanes.finally(finallyCB)"
109 " print ('in Master')"
110 " f = lanes.gen('*',"
111 " {name = 'auto'},"
112 " function()"
113 " for i = 1,1e37 do end" // no cooperative cancellation checks here!
114 " end)"
115 " f()"
116 };
117 ASSERT_EQ(S.doString(script), LuaError::OK) << S;
118 // close the state before the lane ends.
119 // since we don't wait at all, it is possible that the OS thread for the lane hasn't even started at that point
120 S.close();
121 // the finally handler should have been called, and told all lanes are stopped
122 ASSERT_EQ(_wasCalled, true) << S;
123 ASSERT_EQ(_allLanesTerminated, true) << S;
124}
125
126// #################################################################################################
127// #################################################################################################
128
129class LaneCancel : public ::testing::Test
130{
131 protected:
132 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
133
134 void SetUp() override
135 {
136 // need the timers so that there is a lane running on which we can operate
137 std::ignore = S.doString("timer_lane = require 'lanes'.configure{with_timers = true}.timer_lane");
138 }
139};
140
141// #################################################################################################
142
143TEST_F(LaneCancel, FailsOnBadArguments)
144{
145 //FAIL() << "Make sure the failures fail the way we expect them";
146 // make sure we have the timer lane and its cancel method handy
147 ASSERT_EQ(S.doString("assert(timer_lane and timer_lane.cancel)"), LuaError::OK);
148 // as well as the fixture module
149 ASSERT_EQ(S.doString("fixture = require 'fixture'"), LuaError::OK) << S;
150
151 // cancel operation must be a known string
152 ASSERT_NE(S.doString("timer_lane:cancel('gleh')"), LuaError::OK);
153 ASSERT_NE(S.doString("timer_lane:cancel(function() end)"), LuaError::OK);
154 ASSERT_NE(S.doString("timer_lane:cancel({})"), LuaError::OK);
155 ASSERT_NE(S.doString("timer_lane:cancel(fixture.newuserdata())"), LuaError::OK);
156 ASSERT_NE(S.doString("timer_lane:cancel(fixture.newlightuserdata())"), LuaError::OK);
157
158 // cancel doesn't expect additional non-number/bool arguments after the mode
159 ASSERT_NE(S.doString("timer_lane:cancel('soft', 'gleh')"), LuaError::OK);
160 ASSERT_NE(S.doString("timer_lane:cancel('soft', function() end)"), LuaError::OK);
161 ASSERT_NE(S.doString("timer_lane:cancel('soft', {})"), LuaError::OK);
162 ASSERT_NE(S.doString("timer_lane:cancel('soft', fixture.newuserdata())"), LuaError::OK);
163 ASSERT_NE(S.doString("timer_lane:cancel('soft', fixture.newlightuserdata())"), LuaError::OK);
164
165 // hook-based cancellation expects a number for the count. IOW, a bool is not valid
166 ASSERT_NE(S.doString("timer_lane:cancel('call', true)"), LuaError::OK);
167 ASSERT_NE(S.doString("timer_lane:cancel('ret', true)"), LuaError::OK);
168 ASSERT_NE(S.doString("timer_lane:cancel('line', true)"), LuaError::OK);
169 ASSERT_NE(S.doString("timer_lane:cancel('count', true)"), LuaError::OK);
170 ASSERT_NE(S.doString("timer_lane:cancel('all', true)"), LuaError::OK);
171
172 // non-hook should only have one number after the mode (the timeout), else it means we have a count
173 ASSERT_NE(S.doString("timer_lane:cancel('hard', 10, 10)"), LuaError::OK);
174
175 // extra arguments are not accepted either
176 ASSERT_NE(S.doString("timer_lane:cancel('hard', 10, true, 10)"), LuaError::OK);
177 ASSERT_NE(S.doString("timer_lane:cancel('call', 10, 10, 10)"), LuaError::OK);
178 ASSERT_NE(S.doString("timer_lane:cancel('line', 10, 10, true, 10)"), LuaError::OK);
179
180 // out-of-range hook count is not valid
181 ASSERT_NE(S.doString("timer_lane:cancel('call', -1)"), LuaError::OK);
182 ASSERT_NE(S.doString("timer_lane:cancel('call', 0)"), LuaError::OK);
183
184 // out-of-range duration is not valid
185 ASSERT_NE(S.doString("timer_lane:cancel('soft', -1)"), LuaError::OK);
186}
187
188// #################################################################################################
189// #################################################################################################
190
191INSTANTIATE_TEST_CASE_P(
192 LaneScriptedTests,
193 UnitTestRunner,
194 ::testing::Values(
195 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0
196 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertThrows },
197 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2
198 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3
199 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4
200 FileRunnerParam{ "lane/tasking_communications", TestType::AssertNoLuaError },
201 FileRunnerParam{ "lane/tasking_error", TestType::AssertNoLuaError }, // 6
202 FileRunnerParam{ "lane/tasking_join_test", TestType::AssertNoLuaError }, // 7
203 FileRunnerParam{ "lane/tasking_send_receive_code", TestType::AssertNoLuaError },
204 FileRunnerParam{ "lane/stdlib_naming", TestType::AssertNoLuaError },
205 FileRunnerParam{ "coro/basics", TestType::AssertNoLuaError }, // 10
206 FileRunnerParam{ "coro/error_handling", TestType::AssertNoLuaError }
207 )
208 //,[](::testing::TestParamInfo<FileRunnerParam> const& info_) { return std::string{ info_.param.script };}
209);