blob: e60f837d976667247c874473b8b6eba7883f4fa6 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001package.path = string.format("../lua/?.lua;./?.lua;%s",package.path)
2
3local function checkReadBuffer(buf, offset, sizePrefix)
4 offset = offset or 0
5
6 if type(buf) == "string" then
7 buf = flatbuffers.binaryArray.New(buf)
8 end
9
10 if sizePrefix then
11 local size = flatbuffers.N.Int32:Unpack(buf, offset)
12 assert(size == #buf - offset - 4)
13 offset = offset + flatbuffers.N.Int32.bytewidth
14 end
15
16 local mon = monster.GetRootAsMonster(buf, offset)
17 assert(mon:Hp() == 80, "Monster Hp is not 80")
18 assert(mon:Mana() == 150, "Monster Mana is not 150")
19 assert(mon:Name() == "MyMonster", "Monster Name is not MyMonster")
20
21 local vec = assert(mon:Pos(), "Monster Position is nil")
22 assert(vec:X() == 1.0)
23 assert(vec:Y() == 2.0)
24 assert(vec:Z() == 3.0)
25 assert(vec:Test1() == 3.0)
26 assert(vec:Test2() == 2)
27
28 local t = require("MyGame.Example.Test").New()
29 t = assert(vec:Test3(t))
30
31 assert(t:A() == 5)
32 assert(t:B() == 6)
33
34 local ut = require("MyGame.Example.Any")
35 assert(mon:TestType() == ut.Monster)
36
37 local table2 = mon:Test()
38 assert(getmetatable(table2) == "flatbuffers.view.mt")
39
40 local mon2 = monster.New()
41 mon2:Init(table2.bytes, table2.pos)
42
43 assert(mon2:Name() == "Fred")
44
45 assert(mon:InventoryLength() == 5)
46 local invsum = 0
47 for i=1,mon:InventoryLength() do
48 local v = mon:Inventory(i)
49 invsum = invsum + v
50 end
51 assert(invsum == 10)
52
53 for i=1,5 do
54 assert(mon:VectorOfLongs(i) == 10^((i-1)*2))
55 end
56
57 local dbls = { -1.7976931348623157e+308, 0, 1.7976931348623157e+308}
58 for i=1,mon:VectorOfDoublesLength() do
59 assert(mon:VectorOfDoubles(i) == dbls[i])
60 end
61
62 assert(mon:Test4Length() == 2)
63
64 local test0 = mon:Test4(1)
65 local test1 = mon:Test4(2)
66
67 local v0 = test0:A()
68 local v1 = test0:B()
69 local v2 = test1:A()
70 local v3 = test1:B()
71
72 local sumtest12 = v0 + v1 + v2 + v3
73 assert(sumtest12 == 100)
74
75 assert(mon:TestarrayofstringLength() == 2)
76 assert(mon:Testarrayofstring(1) == "test1")
77 assert(mon:Testarrayofstring(2) == "test2")
78
79 assert(mon:TestarrayoftablesLength() == 0)
80 assert(mon:TestnestedflatbufferLength() == 0)
81 assert(mon:Testempty() == nil)
82end
83
Austin Schuh272c6132020-11-14 16:37:52 -080084local function generateMonster(sizePrefix, b)
85 if b then b:Clear() end
86 b = b or flatbuffers.Builder(0)
Austin Schuhe89fa2d2019-08-14 20:24:23 -070087 local str = b:CreateString("MyMonster")
88 local test1 = b:CreateString("test1")
89 local test2 = b:CreateString("test2")
90 local fred = b:CreateString("Fred")
91
92 monster.StartInventoryVector(b, 5)
93 b:PrependByte(4)
94 b:PrependByte(3)
95 b:PrependByte(2)
96 b:PrependByte(1)
97 b:PrependByte(0)
98 local inv = b:EndVector(5)
99
100 monster.Start(b)
101 monster.AddName(b, fred)
102 local mon2 = monster.End(b)
103
104 monster.StartTest4Vector(b, 2)
105 test.CreateTest(b, 10, 20)
106 test.CreateTest(b, 30, 40)
107 local test4 = b:EndVector(2)
108
109 monster.StartTestarrayofstringVector(b, 2)
110 b:PrependUOffsetTRelative(test2)
111 b:PrependUOffsetTRelative(test1)
112 local testArrayOfString = b:EndVector(2)
113
114 monster.StartVectorOfLongsVector(b, 5)
115 b:PrependInt64(100000000)
116 b:PrependInt64(1000000)
117 b:PrependInt64(10000)
118 b:PrependInt64(100)
119 b:PrependInt64(1)
120 local vectorOfLongs = b:EndVector(5)
121
122 monster.StartVectorOfDoublesVector(b, 3)
123 b:PrependFloat64(1.7976931348623157e+308)
124 b:PrependFloat64(0)
125 b:PrependFloat64(-1.7976931348623157e+308)
126 local vectorOfDoubles = b:EndVector(3)
127
128 monster.Start(b)
129 local pos = vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
130 monster.AddPos(b, pos)
131
132 monster.AddHp(b, 80)
133 monster.AddName(b, str)
134 monster.AddInventory(b, inv)
135 monster.AddTestType(b, 1)
136 monster.AddTest(b, mon2)
137 monster.AddTest4(b, test4)
138 monster.AddTestbool(b, true)
139 monster.AddTestbool(b, false)
140 monster.AddTestbool(b, null)
141 monster.AddTestbool(b,"true")
142 monster.AddTestarrayofstring(b, testArrayOfString)
143 monster.AddVectorOfLongs(b, vectorOfLongs)
144 monster.AddVectorOfDoubles(b, vectorOfDoubles)
145 local mon = monster.End(b)
146
147 if sizePrefix then
148 b:FinishSizePrefixed(mon)
149 else
150 b:Finish(mon)
151 end
152 return b:Output(true), b:Head()
153end
154
155local function sizePrefix(sizePrefix)
156 local buf,offset = generateMonster(sizePrefix)
157 checkReadBuffer(buf, offset, sizePrefix)
158end
159
Austin Schuh272c6132020-11-14 16:37:52 -0800160local function fbbClear()
161 -- Generate a builder that will be 'cleared' and reused to create two different objects.
162 local fbb = flatbuffers.Builder(0)
163
164 -- First use the builder to read the normal monster data and verify it works
165 local buf, offset = generateMonster(false, fbb)
166 checkReadBuffer(buf, offset, false)
167
168 -- Then clear the builder to be used again
169 fbb:Clear()
170
171 -- Storage for the built monsters
172 local monsters = {}
173 local lastBuf
174
175 -- Make another builder that will be use identically to the 'cleared' one so outputs can be compared. Build both the
176 -- Cleared builder and new builder in the exact same way, so we can compare their results
177 for i, builder in ipairs({fbb, flatbuffers.Builder(0)}) do
178 local strOffset = builder:CreateString("Hi there")
179 monster.Start(builder)
180 monster.AddPos(builder, vec3.CreateVec3(builder, 3.0, 2.0, 1.0, 17.0, 3, 100, 123))
181 monster.AddName(builder, strOffset)
182 monster.AddMana(builder, 123)
183 builder:Finish(monster.End(builder))
184 local buf = builder:Output(false)
185 if not lastBuf then
186 lastBuf = buf
187 else
188 -- the output, sized-buffer should be identical
189 assert(lastBuf == buf, "Monster output buffers are not identical")
190 end
191 monsters[i] = monster.GetRootAsMonster(flatbuffers.binaryArray.New(buf), 0)
192 end
193
194 -- Check that all the fields for the generated monsters are as we expect
195 for i, monster in ipairs(monsters) do
196 assert(monster:Name() == "Hi there", "Monster Name is not 'Hi There' for monster "..i)
197 -- HP is default to 100 in the schema, but we change it in generateMonster to 80, so this is a good test to
198 -- see if the cleared builder really clears the data.
199 assert(monster:Hp() == 100, "HP doesn't equal the default value for monster "..i)
200 assert(monster:Mana() == 123, "Monster Mana is not '123' for monster "..i)
201 assert(monster:Pos():X() == 3.0, "Monster vec3.X is not '3' for monster "..i)
202 end
203end
204
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700205local function testCanonicalData()
206 local f = assert(io.open('monsterdata_test.mon', 'rb'))
207 local wireData = f:read("*a")
208 f:close()
209 checkReadBuffer(wireData)
210end
211
Austin Schuh272c6132020-11-14 16:37:52 -0800212local function benchmarkMakeMonster(count, reuseBuilder)
213 local fbb = reuseBuilder and flatbuffers.Builder(0)
214 local length = #(generateMonster(false, fbb))
215
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700216 local s = os.clock()
217 for i=1,count do
Austin Schuh272c6132020-11-14 16:37:52 -0800218 generateMonster(false, fbb)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700219 end
220 local e = os.clock()
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700221
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700222 local dur = (e - s)
223 local rate = count / (dur * 1000)
224 local data = (length * count) / (1024 * 1024)
225 local dataRate = data / dur
226
227 print(string.format('built %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
228 count, length, dur, rate, dataRate))
229end
230
231local function benchmarkReadBuffer(count)
232 local f = assert(io.open('monsterdata_test.mon', 'rb'))
233 local buf = f:read("*a")
234 f:close()
235
236 local s = os.clock()
237 for i=1,count do
238 checkReadBuffer(buf)
239 end
240 local e = os.clock()
241
242 local dur = (e - s)
243 local rate = count / (dur * 1000)
244 local data = (#buf * count) / (1024 * 1024)
245 local dataRate = data / dur
246
247 print(string.format('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
248 count, #buf, dur, rate, dataRate))
249end
250
251local tests =
252{
253 {
254 f = sizePrefix,
255 d = "Test size prefix",
256 args = {{true}, {false}}
257 },
Austin Schuh272c6132020-11-14 16:37:52 -0800258 {
259 f = fbbClear,
260 d = "FlatBufferBuilder Clear",
261 },
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700262 {
263 f = testCanonicalData,
264 d = "Tests Canonical flatbuffer file included in repo"
265 },
266 {
267 f = benchmarkMakeMonster,
268 d = "Benchmark making monsters",
269 args = {
270 {100},
271 {1000},
272 {10000},
Austin Schuh272c6132020-11-14 16:37:52 -0800273 {10000, true}
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700274 }
275 },
276 {
277 f = benchmarkReadBuffer,
278 d = "Benchmark reading monsters",
279 args = {
280 {100},
281 {1000},
282 {10000},
283 -- uncomment following to run 1 million to compare.
284 -- Took ~141 seconds on my machine
Austin Schuh272c6132020-11-14 16:37:52 -0800285 --{1000000},
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700286 }
287 },
288}
289
290local result, err = xpcall(function()
291 flatbuffers = assert(require("flatbuffers"))
292 monster = assert(require("MyGame.Example.Monster"))
293 test = assert(require("MyGame.Example.Test"))
294 vec3 = assert(require("MyGame.Example.Vec3"))
295
296 local function buildArgList(tbl)
297 local s = ""
298 for _,item in ipairs(tbl) do
299 s = s .. tostring(item) .. ","
300 end
301 return s:sub(1,-2)
302 end
303
304 local testsPassed, testsFailed = 0,0
305 for _,test in ipairs(tests) do
306 local allargs = test.args or {{}}
307 for _,args in ipairs(allargs) do
308 local results, err = xpcall(test.f,debug.traceback, table.unpack(args))
309 if results then
310 testsPassed = testsPassed + 1
311 else
312 testsFailed = testsFailed + 1
313 print(string.format(" Test [%s](%s) failed: \n\t%s",
314 test.d or "",
315 buildArgList(args),
316 err))
317 end
318 end
319 end
320
321 local totalTests = testsPassed + testsFailed
322 print(string.format("# of test passed: %d / %d (%.2f%%)",
323 testsPassed,
324 totalTests,
325 totalTests ~= 0
326 and 100 * (testsPassed / totalTests)
327 or 0)
328 )
329
330 return 0
331end, debug.traceback)
332
333if not result then
334 print("Unable to run tests due to test framework error: ",err)
335end
336
337os.exit(result or -1)