1package.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 84local function generateMonster(sizePrefix, b) 85 if b then b:Clear() end 86 b = b or flatbuffers.Builder(0) 87 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 160local 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 205local 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 212local function benchmarkMakeMonster(count, reuseBuilder) 213 local fbb = reuseBuilder and flatbuffers.Builder(0) 214 local length = #(generateMonster(false, fbb)) 215 216 local s = os.clock() 217 for i=1,count do 218 generateMonster(false, fbb) 219 end 220 local e = os.clock() 221 222 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 }, 258 { 259 f = fbbClear, 260 d = "FlatBufferBuilder Clear", 261 }, 262 { 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}, 273 {10000, true} 274 } 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 285 --{1000000}, 286 } 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) 338