You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
10 KiB
338 lines
10 KiB
package.path = string.format("../lua/?.lua;./?.lua;%s",package.path)
|
|
|
|
local function checkReadBuffer(buf, offset, sizePrefix)
|
|
offset = offset or 0
|
|
|
|
if type(buf) == "string" then
|
|
buf = flatbuffers.binaryArray.New(buf)
|
|
end
|
|
|
|
if sizePrefix then
|
|
local size = flatbuffers.N.Int32:Unpack(buf, offset)
|
|
assert(size == #buf - offset - 4)
|
|
offset = offset + flatbuffers.N.Int32.bytewidth
|
|
end
|
|
|
|
local mon = monster.GetRootAsMonster(buf, offset)
|
|
assert(mon:Hp() == 80, "Monster Hp is not 80")
|
|
assert(mon:Mana() == 150, "Monster Mana is not 150")
|
|
assert(mon:Name() == "MyMonster", "Monster Name is not MyMonster")
|
|
|
|
local vec = assert(mon:Pos(), "Monster Position is nil")
|
|
assert(vec:X() == 1.0)
|
|
assert(vec:Y() == 2.0)
|
|
assert(vec:Z() == 3.0)
|
|
assert(vec:Test1() == 3.0)
|
|
assert(vec:Test2() == 2)
|
|
|
|
local t = require("MyGame.Example.Test").New()
|
|
t = assert(vec:Test3(t))
|
|
|
|
assert(t:A() == 5)
|
|
assert(t:B() == 6)
|
|
|
|
local ut = require("MyGame.Example.Any")
|
|
assert(mon:TestType() == ut.Monster)
|
|
|
|
local table2 = mon:Test()
|
|
assert(getmetatable(table2) == "flatbuffers.view.mt")
|
|
|
|
local mon2 = monster.New()
|
|
mon2:Init(table2.bytes, table2.pos)
|
|
|
|
assert(mon2:Name() == "Fred")
|
|
|
|
assert(mon:InventoryLength() == 5)
|
|
local invsum = 0
|
|
for i=1,mon:InventoryLength() do
|
|
local v = mon:Inventory(i)
|
|
invsum = invsum + v
|
|
end
|
|
assert(invsum == 10)
|
|
|
|
for i=1,5 do
|
|
assert(mon:VectorOfLongs(i) == 10^((i-1)*2))
|
|
end
|
|
|
|
local dbls = { -1.7976931348623157e+308, 0, 1.7976931348623157e+308}
|
|
for i=1,mon:VectorOfDoublesLength() do
|
|
assert(mon:VectorOfDoubles(i) == dbls[i])
|
|
end
|
|
|
|
assert(mon:Test4Length() == 2)
|
|
|
|
local test0 = mon:Test4(1)
|
|
local test1 = mon:Test4(2)
|
|
|
|
local v0 = test0:A()
|
|
local v1 = test0:B()
|
|
local v2 = test1:A()
|
|
local v3 = test1:B()
|
|
|
|
local sumtest12 = v0 + v1 + v2 + v3
|
|
assert(sumtest12 == 100)
|
|
|
|
assert(mon:TestarrayofstringLength() == 2)
|
|
assert(mon:Testarrayofstring(1) == "test1")
|
|
assert(mon:Testarrayofstring(2) == "test2")
|
|
|
|
assert(mon:TestarrayoftablesLength() == 0)
|
|
assert(mon:TestnestedflatbufferLength() == 0)
|
|
assert(mon:Testempty() == nil)
|
|
end
|
|
|
|
local function generateMonster(sizePrefix, b)
|
|
if b then b:Clear() end
|
|
b = b or flatbuffers.Builder(0)
|
|
local str = b:CreateString("MyMonster")
|
|
local test1 = b:CreateString("test1")
|
|
local test2 = b:CreateString("test2")
|
|
local fred = b:CreateString("Fred")
|
|
|
|
monster.StartInventoryVector(b, 5)
|
|
b:PrependByte(4)
|
|
b:PrependByte(3)
|
|
b:PrependByte(2)
|
|
b:PrependByte(1)
|
|
b:PrependByte(0)
|
|
local inv = b:EndVector(5)
|
|
|
|
monster.Start(b)
|
|
monster.AddName(b, fred)
|
|
local mon2 = monster.End(b)
|
|
|
|
monster.StartTest4Vector(b, 2)
|
|
test.CreateTest(b, 10, 20)
|
|
test.CreateTest(b, 30, 40)
|
|
local test4 = b:EndVector(2)
|
|
|
|
monster.StartTestarrayofstringVector(b, 2)
|
|
b:PrependUOffsetTRelative(test2)
|
|
b:PrependUOffsetTRelative(test1)
|
|
local testArrayOfString = b:EndVector(2)
|
|
|
|
monster.StartVectorOfLongsVector(b, 5)
|
|
b:PrependInt64(100000000)
|
|
b:PrependInt64(1000000)
|
|
b:PrependInt64(10000)
|
|
b:PrependInt64(100)
|
|
b:PrependInt64(1)
|
|
local vectorOfLongs = b:EndVector(5)
|
|
|
|
monster.StartVectorOfDoublesVector(b, 3)
|
|
b:PrependFloat64(1.7976931348623157e+308)
|
|
b:PrependFloat64(0)
|
|
b:PrependFloat64(-1.7976931348623157e+308)
|
|
local vectorOfDoubles = b:EndVector(3)
|
|
|
|
monster.Start(b)
|
|
local pos = vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
|
|
monster.AddPos(b, pos)
|
|
|
|
monster.AddHp(b, 80)
|
|
monster.AddName(b, str)
|
|
monster.AddInventory(b, inv)
|
|
monster.AddTestType(b, 1)
|
|
monster.AddTest(b, mon2)
|
|
monster.AddTest4(b, test4)
|
|
monster.AddTestbool(b, true)
|
|
monster.AddTestbool(b, false)
|
|
monster.AddTestbool(b, null)
|
|
monster.AddTestbool(b,"true")
|
|
monster.AddTestarrayofstring(b, testArrayOfString)
|
|
monster.AddVectorOfLongs(b, vectorOfLongs)
|
|
monster.AddVectorOfDoubles(b, vectorOfDoubles)
|
|
local mon = monster.End(b)
|
|
|
|
if sizePrefix then
|
|
b:FinishSizePrefixed(mon)
|
|
else
|
|
b:Finish(mon)
|
|
end
|
|
return b:Output(true), b:Head()
|
|
end
|
|
|
|
local function sizePrefix(sizePrefix)
|
|
local buf,offset = generateMonster(sizePrefix)
|
|
checkReadBuffer(buf, offset, sizePrefix)
|
|
end
|
|
|
|
local function fbbClear()
|
|
-- Generate a builder that will be 'cleared' and reused to create two different objects.
|
|
local fbb = flatbuffers.Builder(0)
|
|
|
|
-- First use the builder to read the normal monster data and verify it works
|
|
local buf, offset = generateMonster(false, fbb)
|
|
checkReadBuffer(buf, offset, false)
|
|
|
|
-- Then clear the builder to be used again
|
|
fbb:Clear()
|
|
|
|
-- Storage for the built monsters
|
|
local monsters = {}
|
|
local lastBuf
|
|
|
|
-- Make another builder that will be use identically to the 'cleared' one so outputs can be compared. Build both the
|
|
-- Cleared builder and new builder in the exact same way, so we can compare their results
|
|
for i, builder in ipairs({fbb, flatbuffers.Builder(0)}) do
|
|
local strOffset = builder:CreateString("Hi there")
|
|
monster.Start(builder)
|
|
monster.AddPos(builder, vec3.CreateVec3(builder, 3.0, 2.0, 1.0, 17.0, 3, 100, 123))
|
|
monster.AddName(builder, strOffset)
|
|
monster.AddMana(builder, 123)
|
|
builder:Finish(monster.End(builder))
|
|
local buf = builder:Output(false)
|
|
if not lastBuf then
|
|
lastBuf = buf
|
|
else
|
|
-- the output, sized-buffer should be identical
|
|
assert(lastBuf == buf, "Monster output buffers are not identical")
|
|
end
|
|
monsters[i] = monster.GetRootAsMonster(flatbuffers.binaryArray.New(buf), 0)
|
|
end
|
|
|
|
-- Check that all the fields for the generated monsters are as we expect
|
|
for i, monster in ipairs(monsters) do
|
|
assert(monster:Name() == "Hi there", "Monster Name is not 'Hi There' for monster "..i)
|
|
-- HP is default to 100 in the schema, but we change it in generateMonster to 80, so this is a good test to
|
|
-- see if the cleared builder really clears the data.
|
|
assert(monster:Hp() == 100, "HP doesn't equal the default value for monster "..i)
|
|
assert(monster:Mana() == 123, "Monster Mana is not '123' for monster "..i)
|
|
assert(monster:Pos():X() == 3.0, "Monster vec3.X is not '3' for monster "..i)
|
|
end
|
|
end
|
|
|
|
local function testCanonicalData()
|
|
local f = assert(io.open('monsterdata_test.mon', 'rb'))
|
|
local wireData = f:read("*a")
|
|
f:close()
|
|
checkReadBuffer(wireData)
|
|
end
|
|
|
|
local function benchmarkMakeMonster(count, reuseBuilder)
|
|
local fbb = reuseBuilder and flatbuffers.Builder(0)
|
|
local length = #(generateMonster(false, fbb))
|
|
|
|
local s = os.clock()
|
|
for i=1,count do
|
|
generateMonster(false, fbb)
|
|
end
|
|
local e = os.clock()
|
|
|
|
local dur = (e - s)
|
|
local rate = count / (dur * 1000)
|
|
local data = (length * count) / (1024 * 1024)
|
|
local dataRate = data / dur
|
|
|
|
print(string.format('built %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
|
|
count, length, dur, rate, dataRate))
|
|
end
|
|
|
|
local function benchmarkReadBuffer(count)
|
|
local f = assert(io.open('monsterdata_test.mon', 'rb'))
|
|
local buf = f:read("*a")
|
|
f:close()
|
|
|
|
local s = os.clock()
|
|
for i=1,count do
|
|
checkReadBuffer(buf)
|
|
end
|
|
local e = os.clock()
|
|
|
|
local dur = (e - s)
|
|
local rate = count / (dur * 1000)
|
|
local data = (#buf * count) / (1024 * 1024)
|
|
local dataRate = data / dur
|
|
|
|
print(string.format('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
|
|
count, #buf, dur, rate, dataRate))
|
|
end
|
|
|
|
local tests =
|
|
{
|
|
{
|
|
f = sizePrefix,
|
|
d = "Test size prefix",
|
|
args = {{true}, {false}}
|
|
},
|
|
{
|
|
f = fbbClear,
|
|
d = "FlatBufferBuilder Clear",
|
|
},
|
|
{
|
|
f = testCanonicalData,
|
|
d = "Tests Canonical flatbuffer file included in repo"
|
|
},
|
|
{
|
|
f = benchmarkMakeMonster,
|
|
d = "Benchmark making monsters",
|
|
args = {
|
|
{100},
|
|
{1000},
|
|
{10000},
|
|
{10000, true}
|
|
}
|
|
},
|
|
{
|
|
f = benchmarkReadBuffer,
|
|
d = "Benchmark reading monsters",
|
|
args = {
|
|
{100},
|
|
{1000},
|
|
{10000},
|
|
-- uncomment following to run 1 million to compare.
|
|
-- Took ~141 seconds on my machine
|
|
--{1000000},
|
|
}
|
|
},
|
|
}
|
|
|
|
local result, err = xpcall(function()
|
|
flatbuffers = assert(require("flatbuffers"))
|
|
monster = assert(require("MyGame.Example.Monster"))
|
|
test = assert(require("MyGame.Example.Test"))
|
|
vec3 = assert(require("MyGame.Example.Vec3"))
|
|
|
|
local function buildArgList(tbl)
|
|
local s = ""
|
|
for _,item in ipairs(tbl) do
|
|
s = s .. tostring(item) .. ","
|
|
end
|
|
return s:sub(1,-2)
|
|
end
|
|
|
|
local testsPassed, testsFailed = 0,0
|
|
for _,test in ipairs(tests) do
|
|
local allargs = test.args or {{}}
|
|
for _,args in ipairs(allargs) do
|
|
local results, err = xpcall(test.f,debug.traceback, table.unpack(args))
|
|
if results then
|
|
testsPassed = testsPassed + 1
|
|
else
|
|
testsFailed = testsFailed + 1
|
|
print(string.format(" Test [%s](%s) failed: \n\t%s",
|
|
test.d or "",
|
|
buildArgList(args),
|
|
err))
|
|
end
|
|
end
|
|
end
|
|
|
|
local totalTests = testsPassed + testsFailed
|
|
print(string.format("# of test passed: %d / %d (%.2f%%)",
|
|
testsPassed,
|
|
totalTests,
|
|
totalTests ~= 0
|
|
and 100 * (testsPassed / totalTests)
|
|
or 0)
|
|
)
|
|
|
|
return 0
|
|
end, debug.traceback)
|
|
|
|
if not result then
|
|
print("Unable to run tests due to test framework error: ",err)
|
|
end
|
|
|
|
os.exit(result or -1)
|