diff options
Diffstat (limited to 'unit_tests/scripts')
-rw-r--r-- | unit_tests/scripts/misc/deeptest.lua | 161 |
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 @@ | |||
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 | ||