aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/scripts
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2025-07-31 18:35:42 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2025-07-31 18:35:42 +0200
commitab941c943aedf8f233619773c09c0fde304b8e93 (patch)
tree0fc848eb51519860ed2f4196b3517ba051b088e7 /unit_tests/scripts
parent658f60168004d2a75685c32743fdd84427765af1 (diff)
downloadlanes-master.tar.gz
lanes-master.tar.bz2
lanes-master.zip
Copy deep_userdata_example test script in the test frameworkHEADmaster
* 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/scripts')
-rw-r--r--unit_tests/scripts/misc/deeptest.lua161
1 files changed, 161 insertions, 0 deletions
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 @@
1local fixture = require "fixture"
2local lanes = require("lanes").configure{on_state_create = fixture.on_state_create}
3local l = lanes.linda{name = "my linda"}
4
5local 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
8local 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
11DEEP = DEEP or true
12-- set CLONABLE to any non-false value to run the Clonable Userdata tests
13CLONABLE = 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
17local test_uvtype = (_VERSION == "Lua 5.4") and "function" or (_VERSION == "Lua 5.3") and "string" or "table"
18-- lua 5.4 supports multiple uservalues
19local nupvals = _VERSION == "Lua 5.4" and 3 or 1
20
21local 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
33end
34
35local 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()
51end
52
53local 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])
105end
106
107if 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
152end
153
154if CLONABLE then
155 print "================================================================"
156 print "CLONABLE"
157 performTest( dt.new_clonable(nupvals))
158end
159
160print "================================================================"
161print "TEST OK" \ No newline at end of file