aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/linda_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unit_tests/linda_tests.cpp')
-rw-r--r--unit_tests/linda_tests.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/unit_tests/linda_tests.cpp b/unit_tests/linda_tests.cpp
new file mode 100644
index 0000000..b3bad66
--- /dev/null
+++ b/unit_tests/linda_tests.cpp
@@ -0,0 +1,342 @@
1#include "_pch.hpp"
2#include "shared.h"
3
4// #################################################################################################
5
6class OneKeeperLindaTests : public ::testing::Test
7{
8 protected:
9 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
10
11 void SetUp() override
12 {
13 std::ignore = S.doString("lanes = require 'lanes'");
14 }
15};
16
17TEST_F(OneKeeperLindaTests, LindaCreation)
18{
19 // no parameters is ok
20 EXPECT_EQ(S.doString("lanes.linda()"), LuaError::OK) << S;
21 EXPECT_NE(S.doStringAndRet("return tostring(lanes.linda())"), R"===(Linda: <not a string>)===") << S; // unspecified name should not result in <not a string>
22
23 // since we have only one keeper, only group 0 is authorized
24 EXPECT_NE(S.doString("lanes.linda(-1)"), LuaError::OK);
25 EXPECT_EQ(S.doString("lanes.linda(0)"), LuaError::OK) << S;
26 EXPECT_NE(S.doString("lanes.linda(1)"), LuaError::OK);
27
28 // any name is ok
29 EXPECT_EQ(S.doString("lanes.linda('')"), LuaError::OK) << S; // an empty name results in a string conversion of the form "Linda: <some hex value>" that we can't test (but it works)
30 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('short name'))"), R"===(Linda: short name)===") << S;
31 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('very very very very very very long name'))"), R"===(Linda: very very very very very very long name)===") << S;
32 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('auto'))"), R"===(Linda: [string "return tostring(lanes.linda('auto'))"]:1)===") << S;
33
34 if constexpr (LUA_VERSION_NUM == 504) {
35 // a function is acceptable as a __close handler
36 EXPECT_EQ(S.doString("local l <close> = lanes.linda(function() end)"), LuaError::OK) << S;
37 // a callable table too (a callable full userdata as well, but I have none here)
38 EXPECT_EQ(S.doString("local l <close> = lanes.linda(setmetatable({}, {__call = function() end}))"), LuaError::OK) << S;
39 // if the function raises an error, we should get it
40 EXPECT_NE(S.doString("local l <close> = lanes.linda(function() error 'gluh' end)"), LuaError::OK);
41 } else {
42 // no __close support before Lua 5.4
43 EXPECT_NE(S.doString("lanes.linda(function() end)"), LuaError::OK);
44 EXPECT_NE(S.doString("lanes.linda(setmetatable({}, {__call = function() end}))"), LuaError::OK);
45 }
46
47 // mixing parameters in any order is ok: 2 out of 3
48 EXPECT_EQ(S.doString("lanes.linda(0, 'name')"), LuaError::OK) << S;
49 EXPECT_EQ(S.doString("lanes.linda('name', 0)"), LuaError::OK) << S;
50 if constexpr (LUA_VERSION_NUM == 504) {
51 EXPECT_EQ(S.doString("lanes.linda(0, function() end)"), LuaError::OK) << S;
52 EXPECT_EQ(S.doString("lanes.linda(function() end, 0)"), LuaError::OK) << S;
53 EXPECT_EQ(S.doString("lanes.linda('name', function() end)"), LuaError::OK) << S;
54 EXPECT_EQ(S.doString("lanes.linda(function() end, 'name')"), LuaError::OK) << S;
55 }
56
57 // mixing parameters in any order is ok: 3 out of 3
58 if constexpr (LUA_VERSION_NUM == 504) {
59 EXPECT_EQ(S.doString("lanes.linda(0, 'name', function() end)"), LuaError::OK) << S;
60 EXPECT_EQ(S.doString("lanes.linda(0, function() end, 'name')"), LuaError::OK) << S;
61 EXPECT_EQ(S.doString("lanes.linda('name', 0, function() end)"), LuaError::OK) << S;
62 EXPECT_EQ(S.doString("lanes.linda('name', function() end, 0)"), LuaError::OK) << S;
63 EXPECT_EQ(S.doString("lanes.linda(function() end, 0, 'name')"), LuaError::OK) << S;
64 EXPECT_EQ(S.doString("lanes.linda(function() end, 'name', 0)"), LuaError::OK) << S;
65 }
66
67 // unsupported parameters should fail
68 EXPECT_NE(S.doString("lanes.linda(true)"), LuaError::OK);
69 EXPECT_NE(S.doString("lanes.linda(false)"), LuaError::OK);
70 // uncallable table or full userdata
71 EXPECT_NE(S.doString("lanes.linda({})"), LuaError::OK);
72 EXPECT_NE(S.doString("lanes.linda(lanes.linda())"), LuaError::OK);
73}
74
75// #################################################################################################
76
77TEST_F(OneKeeperLindaTests, LindaIndexing)
78{
79 // indexing the linda with an unknown string key should fail
80 EXPECT_NE(S.doString("return lanes.linda().gouikra"), LuaError::OK) << S;
81 // indexing the linda with an unsupported key type should fail
82 EXPECT_NE(S.doString("return lanes.linda()[5]"), LuaError::OK) << S;
83 EXPECT_NE(S.doString("return lanes.linda()[false]"), LuaError::OK) << S;
84 EXPECT_NE(S.doString("return lanes.linda()[{}]"), LuaError::OK) << S;
85 EXPECT_NE(S.doString("return lanes.linda()[function() end]"), LuaError::OK) << S;
86}
87
88// #################################################################################################
89
90TEST_F(OneKeeperLindaTests, LindaSendTimeoutValidation)
91{
92 // timeout checks
93 // linda:send() should fail if the timeout is bad
94 EXPECT_NE(S.doString("lanes.linda():send(-1, 'k', 'v')"), LuaError::OK);
95 // any positive value is ok
96 EXPECT_EQ(S.doString("lanes.linda():send(0, 'k', 'v')"), LuaError::OK) << S;
97 EXPECT_EQ(S.doString("lanes.linda():send(1e20, 'k', 'v')"), LuaError::OK) << S;
98 // nil too (same as 'forever')
99 EXPECT_EQ(S.doString("lanes.linda():send(nil, 'k', 'v')"), LuaError::OK) << S;
100}
101
102// #################################################################################################
103
104TEST_F(OneKeeperLindaTests, LindaSendFailsOnBadKeys)
105{
106 // key checks
107 // linda:send() should fail if the key is unsupported (nil, table, function, full userdata, reserved light userdata)
108 EXPECT_NE(S.doString("lanes.linda():send(0, nil, 'v')"), LuaError::OK);
109 EXPECT_NE(S.doString("lanes.linda():send(0, {}, 'v')"), LuaError::OK);
110 EXPECT_NE(S.doString("lanes.linda():send(0, function() end, 'v')"), LuaError::OK);
111 EXPECT_NE(S.doString("lanes.linda():send(0, io.stdin, 'v')"), LuaError::OK);
112 EXPECT_NE(S.doString("lanes.linda():send(0, lanes.null, 'v')"), LuaError::OK);
113 EXPECT_NE(S.doString("lanes.linda():send(0, lanes.cancel_error, 'v')"), LuaError::OK);
114 EXPECT_NE(S.doString("local l = lanes.linda(); l:send(0, l.batched, 'v')"), LuaError::OK);
115}
116
117// #################################################################################################
118
119TEST_F(OneKeeperLindaTests, LindaSendSucceedsOnSupportedKeys)
120{
121 // supported keys are ok: boolean, number, string, light userdata, deep userdata
122 EXPECT_EQ(S.doString("lanes.linda():send(0, true, 'v')"), LuaError::OK) << S;
123 EXPECT_EQ(S.doString("lanes.linda():send(0, false, 'v')"), LuaError::OK) << S;
124 EXPECT_EQ(S.doString("lanes.linda():send(0, 99, 'v')"), LuaError::OK) << S;
125 EXPECT_EQ(S.doString("local l = lanes.linda(); l:send(0, l:deep(), 'v')"), LuaError::OK) << S;
126}
127
128// #################################################################################################
129
130TEST_F(OneKeeperLindaTests, LindaSendSucceedsOnDeepUserdataKey)
131{
132 EXPECT_EQ(S.doString("local l = lanes.linda(); l:send(0, l, 'v')"), LuaError::OK) << S;
133}
134
135// #################################################################################################
136
137TEST_F(OneKeeperLindaTests, LindaSendSelfValidation)
138{
139 // misuse checks, . instead of :
140 EXPECT_NE(S.doString("lanes.linda().send(nil, 'k', 'v')"), LuaError::OK);
141}
142
143// #################################################################################################
144
145TEST_F(OneKeeperLindaTests, LindaSendValueValidation)
146{
147 // value checks
148 // linda:send() should fail if we don't send anything
149 EXPECT_NE(S.doString("lanes.linda():send()"), LuaError::OK);
150 EXPECT_NE(S.doString("lanes.linda():send(0)"), LuaError::OK);
151 EXPECT_NE(S.doString("lanes.linda():send(0, 'k')"), LuaError::OK);
152 // or non-deep userdata
153 EXPECT_NE(S.doString("lanes.linda():send(0, 'k', fixture.newuserdata())"), LuaError::OK);
154 // or something with a converter that raises an error (maybe that should go to a dedicated __lanesconvert test!)
155 EXPECT_NE(S.doString("lanes.linda():send(0, 'k', setmetatable({}, {__lanesconvert = function(where_) error (where_ .. ': should not send me' end}))"), LuaError::OK);
156 // but a registered non-deep userdata should work
157 EXPECT_EQ(S.doString("lanes.linda():send(0, 'k', io.stdin)"), LuaError::OK);
158}
159
160// #################################################################################################
161
162TEST_F(OneKeeperLindaTests, LindaLimitArgumentValidation)
163{
164 // misuse checks, . instead of :
165 EXPECT_NE(S.doString("lanes.linda().limit()"), LuaError::OK);
166
167 // not enough keys
168 EXPECT_NE(S.doString("lanes.linda():limit()"), LuaError::OK);
169
170 // too many keys?
171 EXPECT_NE(S.doString("lanes.linda():limit('k1', 'k2')"), LuaError::OK);
172 EXPECT_NE(S.doString("lanes.linda():limit('k1', 'k2', 'k3')"), LuaError::OK);
173
174 // non-numeric limit
175 EXPECT_NE(S.doString("lanes.linda():limit('k', false)"), LuaError::OK);
176 EXPECT_NE(S.doString("lanes.linda():limit('k', true)"), LuaError::OK);
177 EXPECT_NE(S.doString("lanes.linda():limit('k', {})"), LuaError::OK);
178 EXPECT_NE(S.doString("lanes.linda():limit('k', lanes.linda():deep())"), LuaError::OK);
179 EXPECT_NE(S.doString("lanes.linda():limit('k', assert)"), LuaError::OK);
180 EXPECT_NE(S.doString("lanes.linda():limit('k', function() end)"), LuaError::OK);
181
182 // negative limit is forbidden
183 EXPECT_NE(S.doString("lanes.linda():limit('k', -1)"), LuaError::OK);
184
185 // we can set a positive limit, or "unlimited"
186 EXPECT_EQ(S.doString("lanes.linda():limit('k', 0)"), LuaError::OK) << S;
187 EXPECT_EQ(S.doString("lanes.linda():limit('k', 1)"), LuaError::OK) << S;
188 EXPECT_EQ(S.doString("lanes.linda():limit('k', 45648946)"), LuaError::OK) << S;
189 EXPECT_EQ(S.doString("lanes.linda():limit('k', 'unlimited')"), LuaError::OK) << S;
190}
191
192// #################################################################################################
193
194TEST_F(OneKeeperLindaTests, LindaCollectGarbage)
195{
196 // linda:collectgarbage() doesn't accept extra arguments
197 EXPECT_NE(S.doString("lanes.linda():collectgarbage(true)"), LuaError::OK) << S;
198 EXPECT_EQ(S.doString("lanes.linda():collectgarbage()"), LuaError::OK) << S;
199}
200
201// #################################################################################################
202
203TEST_F(OneKeeperLindaTests, LindaCount)
204{
205 // counting a non-existent key returns nothing
206 EXPECT_EQ(S.doString("assert(lanes.linda():count('k') == nil)"), LuaError::OK) << S;
207 // counting an existing key returns a correct count
208 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1)"), LuaError::OK) << S;
209 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a', 'b'); assert(l:count('k') == 2)"), LuaError::OK) << S;
210}
211
212// #################################################################################################
213
214TEST_F(OneKeeperLindaTests, LindaLimit)
215{
216 // we can set an inexistent key to unlimited, it should do nothing
217 EXPECT_EQ(S.doString("local r,s = lanes.linda():limit('k', 'unlimited'); assert(r==false and s=='under')"), LuaError::OK) << S;
218 // reading the limit of an unset key should succeed
219 EXPECT_EQ(S.doString("local r,s = lanes.linda():limit('k'); assert(r=='unlimited' and s=='under')"), LuaError::OK) << S;
220 // reading the limit after we set one should yield the correct value
221 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:limit('k', 3); assert(r==false and s=='under'); r,s = l:limit('k'); assert(r==3 and s=='under')"), LuaError::OK) << S;
222 // changing the limit is possible...
223 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:limit('k', 3); r,s = l:limit('k', 5); r,s = l:limit('k'); assert(r==5 and s=='under', 'b')"), LuaError::OK) << S;
224 // ... even if we set a limit below the current count of stored data (which should not change)
225 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:set('k', 'a', 'b', 'c'); assert(r==false and s=='under'); r,s = l:limit('k', 1); assert(r==false and s=='over' and l:count('k') == 3); r,s = l:limit('k'); assert(r==1 and s=='over')"), LuaError::OK) << S;
226 // we can remove the limit on a key
227 EXPECT_EQ(S.doString("lanes.linda():limit('k', 'unlimited')"), LuaError::OK) << S;
228
229 // emptying a limited key should not remove the limit
230 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 5); l:set('k'); assert(l:limit('k')==5)"), LuaError::OK) << S;
231}
232
233// #################################################################################################
234
235TEST_F(OneKeeperLindaTests, LindaRestrict)
236{
237 // we can read the access restriction of an inexistent Linda, it should tell us there is no restriction
238 EXPECT_EQ(S.doString("local r = lanes.linda():restrict('k'); assert(r=='none')"), LuaError::OK) << S;
239 // setting an unknown access restriction should fail
240 EXPECT_NE(S.doString("lanes.linda():restrict('k', 'gleh')"), LuaError::OK) << S;
241 // we can set the access restriction of an inexistent Linda, it should store it and return the previous restriction
242 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'set/get')"), LuaError::OK) << S;
243 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive')"), LuaError::OK) << S;
244
245 // we can replace the restriction on a restricted linda
246 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'set/get'); assert(r1=='none' and r2 == 'send/receive')"), LuaError::OK) << S;
247
248 // we can remove the restriction on a restricted linda
249 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'none'); local r3 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive' and r3 == 'none')"), LuaError::OK) << S;
250
251 // can't use send/receive on a 'set/get'-restricted key
252 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:send('k', 'bob')"), LuaError::OK) << S;
253 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:receive('k')"), LuaError::OK) << S;
254 // can't use get/set on a 'send/receive'-restricted key
255 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:set('k', 'bob')"), LuaError::OK) << S;
256 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:get('k')"), LuaError::OK) << S;
257
258 // emptying a restricted key should not cause the restriction to be forgotten
259 EXPECT_EQ(S.doString("local l = lanes.linda(); l:restrict('k', 'set/get'); l:set('k'); assert(l:restrict('k')=='set/get')"), LuaError::OK) << S;
260}
261
262// #################################################################################################
263
264TEST_F(OneKeeperLindaTests, LindaSet)
265{
266 // we can store more data than the specified limit
267 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a', 'b', 'c'); assert(r == false and s == 'over'); assert(l:count('k') == 3)"), LuaError::OK) << S;
268 // setting nothing in an inexistent key does not create it
269 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k'); assert(l:count('k') == nil)"), LuaError::OK) << S;
270 // setting a key with some values yields the correct count
271 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1) "), LuaError::OK) << S;
272 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a'); assert(r == false and s == 'exact'); assert(l:count('k') == 1)"), LuaError::OK) << S;
273 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a', 'b', 'c', 'd'); assert(l:count('k') == 4) "), LuaError::OK) << S;
274 // setting nothing in an existing key removes it ...
275 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1); l:set('k'); assert(l:count('k') == nil) "), LuaError::OK) << S;
276 // ... but not if there is a limit (because we don't want to forget it)
277 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); l:set('k', 'a'); l:set('k'); assert(l:count('k') == 0) "), LuaError::OK) << S;
278}
279
280// #################################################################################################
281
282TEST_F(OneKeeperLindaTests, LindaCancel)
283{
284 // unknown linda cancellation mode should raise an error
285 EXPECT_NE(S.doString("local l = lanes.linda(); l:cancel('zbougli');"), LuaError::OK) << S;
286 // cancelling a linda should change its cancel status to 'cancelled'
287 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('read'); assert(l.status == 'cancelled')"), LuaError::OK) << S;
288 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('write'); assert(l.status == 'cancelled')"), LuaError::OK) << S;
289 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('both'); assert(l.status == 'cancelled')"), LuaError::OK) << S;
290 // resetting the linda cancel status
291 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('none'); assert(l.status == 'active')"), LuaError::OK) << S;
292}
293
294// #################################################################################################
295
296TEST_F(OneKeeperLindaTests, LindaWake)
297{
298 // unknown linda wake mode should raise an error
299 EXPECT_NE(S.doString("local l = lanes.linda(); l:wake('boulgza');"), LuaError::OK) << S;
300 // waking a linda should not change its cancel status
301 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('read'); assert(l.status == 'active')"), LuaError::OK) << S;
302 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('write'); assert(l.status == 'active')"), LuaError::OK) << S;
303 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('both'); assert(l.status == 'active')"), LuaError::OK) << S;
304}
305
306// #################################################################################################
307// #################################################################################################
308
309class MultiKeeperLindaTests : public ::testing::Test
310{
311 protected:
312 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
313
314 void SetUp() override
315 {
316 std::ignore = S.doString("lanes = require 'lanes'.configure{nb_user_keepers = 3}");
317 }
318};
319
320TEST_F(MultiKeeperLindaTests, LindaCreation)
321{
322 EXPECT_NE(S.doString("lanes.linda(-1)"), LuaError::OK);
323 EXPECT_EQ(S.doString("lanes.linda(0)"), LuaError::OK) << S;
324 EXPECT_EQ(S.doString("lanes.linda(1)"), LuaError::OK) << S;
325 EXPECT_EQ(S.doString("lanes.linda(2)"), LuaError::OK) << S;
326 EXPECT_EQ(S.doString("lanes.linda(3)"), LuaError::OK) << S;
327 EXPECT_NE(S.doString("lanes.linda(4)"), LuaError::OK);
328}
329
330// #################################################################################################
331// #################################################################################################
332
333INSTANTIATE_TEST_CASE_P(
334 LindaScriptedTests,
335 UnitTestRunner,
336 ::testing::Values(
337 FileRunnerParam{ "linda/send_receive", TestType::AssertNoLuaError },
338 FileRunnerParam{ "linda/send_registered_userdata", TestType::AssertNoLuaError },
339 FileRunnerParam{ "linda/multiple_keepers", TestType::AssertNoLuaError }
340 )
341 //,[](::testing::TestParamInfo<FileRunnerParam> const& info_) { return std::string{ info_.param.script }; }
342);