diff options
Diffstat (limited to '')
| -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 | ||
