diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2025-07-31 18:35:42 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2025-07-31 18:35:42 +0200 |
commit | ab941c943aedf8f233619773c09c0fde304b8e93 (patch) | |
tree | 0fc848eb51519860ed2f4196b3517ba051b088e7 /unit_tests | |
parent | 658f60168004d2a75685c32743fdd84427765af1 (diff) | |
download | lanes-master.tar.gz lanes-master.tar.bz2 lanes-master.zip |
* I need to keep deep_userdata_example hackishly built-in inside the unit tests executable, because using the external module cause a crash in Lua51 tests (module is unloaded before some deep objects are GCed...)
* copy the test script in the proper location and invoke it as part of the tests
Diffstat (limited to 'unit_tests')
-rw-r--r-- | unit_tests/UnitTests.vcxproj | 1 | ||||
-rw-r--r-- | unit_tests/UnitTests.vcxproj.filters | 6 | ||||
-rw-r--r-- | unit_tests/deep_tests.cpp | 11 | ||||
-rw-r--r-- | unit_tests/scripts/misc/deeptest.lua | 161 | ||||
-rw-r--r-- | unit_tests/shared.cpp | 2 |
5 files changed, 179 insertions, 2 deletions
diff --git a/unit_tests/UnitTests.vcxproj b/unit_tests/UnitTests.vcxproj index 2b0c281..2093063 100644 --- a/unit_tests/UnitTests.vcxproj +++ b/unit_tests/UnitTests.vcxproj | |||
@@ -1160,6 +1160,7 @@ | |||
1160 | <None Include="scripts\lane\tasking_cancelling_with_hook.lua" /> | 1160 | <None Include="scripts\lane\tasking_cancelling_with_hook.lua" /> |
1161 | <None Include="scripts\linda\send_receive_func_and_string.lua" /> | 1161 | <None Include="scripts\linda\send_receive_func_and_string.lua" /> |
1162 | <None Include="scripts\linda\wake_period.lua" /> | 1162 | <None Include="scripts\linda\wake_period.lua" /> |
1163 | <None Include="scripts\misc\deeptest.lua" /> | ||
1163 | <None Include="scripts\_utils54.lua" /> | 1164 | <None Include="scripts\_utils54.lua" /> |
1164 | <None Include="UnitTests.makefile" /> | 1165 | <None Include="UnitTests.makefile" /> |
1165 | <None Include="scripts\coro\index_suspended.lua" /> | 1166 | <None Include="scripts\coro\index_suspended.lua" /> |
diff --git a/unit_tests/UnitTests.vcxproj.filters b/unit_tests/UnitTests.vcxproj.filters index 33d484a..df82447 100644 --- a/unit_tests/UnitTests.vcxproj.filters +++ b/unit_tests/UnitTests.vcxproj.filters | |||
@@ -54,6 +54,9 @@ | |||
54 | <Filter Include="Make"> | 54 | <Filter Include="Make"> |
55 | <UniqueIdentifier>{c62af5d9-9161-4ca1-9b58-6837e2907e35}</UniqueIdentifier> | 55 | <UniqueIdentifier>{c62af5d9-9161-4ca1-9b58-6837e2907e35}</UniqueIdentifier> |
56 | </Filter> | 56 | </Filter> |
57 | <Filter Include="Scripts\misc"> | ||
58 | <UniqueIdentifier>{1fbb1341-2f93-4eaa-924c-1df79e083704}</UniqueIdentifier> | ||
59 | </Filter> | ||
57 | </ItemGroup> | 60 | </ItemGroup> |
58 | <ItemGroup> | 61 | <ItemGroup> |
59 | <None Include="scripts\linda\send_receive.lua"> | 62 | <None Include="scripts\linda\send_receive.lua"> |
@@ -149,5 +152,8 @@ | |||
149 | <None Include="scripts\linda\send_receive_func_and_string.lua"> | 152 | <None Include="scripts\linda\send_receive_func_and_string.lua"> |
150 | <Filter>Scripts\linda</Filter> | 153 | <Filter>Scripts\linda</Filter> |
151 | </None> | 154 | </None> |
155 | <None Include="scripts\misc\deeptest.lua"> | ||
156 | <Filter>Scripts\misc</Filter> | ||
157 | </None> | ||
152 | </ItemGroup> | 158 | </ItemGroup> |
153 | </Project> \ No newline at end of file | 159 | </Project> \ No newline at end of file |
diff --git a/unit_tests/deep_tests.cpp b/unit_tests/deep_tests.cpp index e21072c..f18ff81 100644 --- a/unit_tests/deep_tests.cpp +++ b/unit_tests/deep_tests.cpp | |||
@@ -92,4 +92,13 @@ TEST_CASE("misc.deep_userdata.example") | |||
92 | " assert(due.get_deep_count() == 0)" | 92 | " assert(due.get_deep_count() == 0)" |
93 | ); | 93 | ); |
94 | } | 94 | } |
95 | } \ No newline at end of file | 95 | } |
96 | |||
97 | #define MAKE_TEST_CASE(DIR, FILE, CONDITION) \ | ||
98 | TEST_CASE("scripted_tests." #DIR "." #FILE) \ | ||
99 | { \ | ||
100 | FileRunner _runner(R"(.\unit_tests\scripts)"); \ | ||
101 | _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::CONDITION }); \ | ||
102 | } | ||
103 | |||
104 | MAKE_TEST_CASE(misc, deeptest, AssertNoLuaError) | ||
diff --git a/unit_tests/scripts/misc/deeptest.lua b/unit_tests/scripts/misc/deeptest.lua new file mode 100644 index 0000000..542c35b --- /dev/null +++ b/unit_tests/scripts/misc/deeptest.lua | |||
@@ -0,0 +1,161 @@ | |||
1 | local fixture = require "fixture" | ||
2 | local lanes = require("lanes").configure{on_state_create = fixture.on_state_create} | ||
3 | local l = lanes.linda{name = "my linda"} | ||
4 | |||
5 | local table_unpack = table.unpack or unpack -- Lua 5.1 support | ||
6 | |||
7 | -- we will transfer userdata created by this module, so we need to make Lanes aware of it | ||
8 | local dt = lanes.require "deep_userdata_example" | ||
9 | |||
10 | -- set DEEP to any non-false value to run the Deep Userdata tests. "gc" selects a special test for debug purposes | ||
11 | DEEP = DEEP or true | ||
12 | -- set CLONABLE to any non-false value to run the Clonable Userdata tests | ||
13 | CLONABLE = CLONABLE or true | ||
14 | |||
15 | -- lua 5.1->5.2 support a single table uservalue | ||
16 | -- lua 5.3->5.4 supports an arbitrary type uservalue | ||
17 | local test_uvtype = (_VERSION == "Lua 5.4") and "function" or (_VERSION == "Lua 5.3") and "string" or "table" | ||
18 | -- lua 5.4 supports multiple uservalues | ||
19 | local nupvals = _VERSION == "Lua 5.4" and 3 or 1 | ||
20 | |||
21 | local makeUserValue = function( obj_) | ||
22 | if test_uvtype == "table" then | ||
23 | return {"some uservalue"} | ||
24 | elseif test_uvtype == "string" then | ||
25 | return "some uservalue" | ||
26 | elseif test_uvtype == "function" then | ||
27 | -- a function that pull the userdata as upvalue | ||
28 | local f = function() | ||
29 | return "-> '" .. tostring( obj_) .. "'" | ||
30 | end | ||
31 | return f | ||
32 | end | ||
33 | end | ||
34 | |||
35 | local printDeep = function( prefix_, obj_, t_) | ||
36 | print( prefix_, obj_) | ||
37 | for uvi = 1, nupvals do | ||
38 | local uservalue = obj_:getuv(uvi) | ||
39 | print ("uv #" .. uvi, type( uservalue), uservalue, type(uservalue) == "function" and uservalue() or "") | ||
40 | end | ||
41 | if t_ then | ||
42 | local count = 0 | ||
43 | for k, v in ipairs( t_) do | ||
44 | print( "t["..tostring(k).."]", v) | ||
45 | count = count + 1 | ||
46 | end | ||
47 | -- we should have only 2 indexed entries with the same value | ||
48 | assert(count == 2 and t_[1] == t_[2]) | ||
49 | end | ||
50 | print() | ||
51 | end | ||
52 | |||
53 | local performTest = function( obj_) | ||
54 | -- setup the userdata with some value and a uservalue | ||
55 | obj_:set( 666) | ||
56 | obj_:setuv( 1, makeUserValue( obj_)) | ||
57 | if nupvals > 1 then | ||
58 | -- keep uv #2 as nil | ||
59 | obj_:setuv( 3, "ENDUV") | ||
60 | end | ||
61 | |||
62 | local t = | ||
63 | { | ||
64 | -- two indices with an identical value: we should also have identical values on the other side (even if not the same as the original ones when they are clonables) | ||
65 | obj_, | ||
66 | obj_, | ||
67 | -- this one won't transfer because we don't support full uservalue as keys | ||
68 | [obj_] = "val" | ||
69 | } | ||
70 | |||
71 | -- read back the contents of the object | ||
72 | printDeep( "immediate:", obj_, t) | ||
73 | |||
74 | -- send the object in a linda, get it back out, read the contents | ||
75 | l:set( "key", obj_, t) | ||
76 | -- when obj_ is a deep userdata, out is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy) | ||
77 | -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier | ||
78 | local _n, _val1, _val2 = l:get( "key", 2) | ||
79 | assert(_n == (_val2 and 2 or 1)) | ||
80 | printDeep( "out of linda:", _val1, _val2) | ||
81 | |||
82 | -- send the object in a lane through argument passing, the lane body returns it as return value, read the contents | ||
83 | local g = lanes.gen( | ||
84 | "package" | ||
85 | , { | ||
86 | name = 'auto', | ||
87 | required = { "deep_userdata_example"} -- we will transfer userdata created by this module, so we need to make this lane aware of it | ||
88 | } | ||
89 | , function( arg_, t_) | ||
90 | -- read contents inside lane: arg_ and t_ by argument | ||
91 | printDeep( "in lane, as arguments:", arg_, t_) | ||
92 | -- read contents inside lane: obj_ and t by upvalue | ||
93 | printDeep( "in lane, as upvalues:", obj_, t) | ||
94 | -- read contents inside lane: in linda | ||
95 | local _n, _val1, _val2 = l:get( "key", 2) | ||
96 | assert(_n == (_val2 and 2 or 1)) | ||
97 | printDeep( "in lane, from linda:", _val1, _val2) | ||
98 | return arg_, t_ | ||
99 | end | ||
100 | ) | ||
101 | h = g( obj_, t) | ||
102 | -- when obj_ is a deep userdata, from_lane is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy) | ||
103 | -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier | ||
104 | printDeep( "from lane:", h[1], h[2]) | ||
105 | end | ||
106 | |||
107 | if DEEP then | ||
108 | print "================================================================" | ||
109 | print "DEEP" | ||
110 | local d = dt.new_deep(nupvals) | ||
111 | if type(DEEP) == "string" then | ||
112 | local gc_tests = { | ||
113 | thrasher = function(repeat_, size_) | ||
114 | print "in thrasher" | ||
115 | -- result is a table of repeat_ tables, each containing size_ entries | ||
116 | local result = {} | ||
117 | for i = 1, repeat_ do | ||
118 | local batch_values = {} | ||
119 | for j = 1, size_ do | ||
120 | table.insert(batch_values, j) | ||
121 | end | ||
122 | table.insert(result, batch_values) | ||
123 | end | ||
124 | print "thrasher done" | ||
125 | return result | ||
126 | end, | ||
127 | stack_abuser = function(repeat_, size_) | ||
128 | print "in stack_abuser" | ||
129 | for i = 1, repeat_ do | ||
130 | local batch_values = {} | ||
131 | for j = 1, size_ do | ||
132 | table.insert(batch_values, j) | ||
133 | end | ||
134 | -- return size_ values | ||
135 | local _ = table_unpack(batch_values) | ||
136 | end | ||
137 | print "stack_abuser done" | ||
138 | return result | ||
139 | end | ||
140 | } | ||
141 | -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!) | ||
142 | local testf = gc_tests[DEEP] | ||
143 | if testf then | ||
144 | local r = d:invoke(gc_tests[DEEP], REPEAT or 10, SIZE or 10) | ||
145 | print("invoke -> ", tostring(r)) | ||
146 | else | ||
147 | print("unknown test '" .. DEEP .. "'") | ||
148 | end | ||
149 | else | ||
150 | performTest(d) | ||
151 | end | ||
152 | end | ||
153 | |||
154 | if CLONABLE then | ||
155 | print "================================================================" | ||
156 | print "CLONABLE" | ||
157 | performTest( dt.new_clonable(nupvals)) | ||
158 | end | ||
159 | |||
160 | print "================================================================" | ||
161 | print "TEST OK" \ No newline at end of file | ||
diff --git a/unit_tests/shared.cpp b/unit_tests/shared.cpp index daac5a2..9f3b08e 100644 --- a/unit_tests/shared.cpp +++ b/unit_tests/shared.cpp | |||
@@ -51,7 +51,7 @@ namespace | |||
51 | return 1; | 51 | return 1; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | // a function that enables any lane to require "fixture" | 54 | // a function that enables any lane to require "fixture" and "deep_userdata_example" |
55 | lua_CFunction sOnStateCreate = +[](lua_State* const L_) { | 55 | lua_CFunction sOnStateCreate = +[](lua_State* const L_) { |
56 | PreloadModule(L_, "fixture", luaopen_fixture); | 56 | PreloadModule(L_, "fixture", luaopen_fixture); |
57 | PreloadModule(L_, "deep_userdata_example", luaopen_deep_userdata_example); | 57 | PreloadModule(L_, "deep_userdata_example", luaopen_deep_userdata_example); |