mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-16 17:22:21 +00:00
Updates test cases on linux Adhere to new protocol naming Adds fuzzing Adds documentation Adds support for string unions Updated fuzzer generated code
359 lines
13 KiB
Swift
359 lines
13 KiB
Swift
/*
|
|
* Copyright 2021 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import XCTest
|
|
@testable import FlatBuffers
|
|
|
|
final class FlatBuffersUnionTests: XCTestCase {
|
|
|
|
func testCreateMonstor() {
|
|
|
|
var b = FlatBufferBuilder(initialSize: 20)
|
|
let dmg: Int16 = 5
|
|
let str = "Axe"
|
|
let axe = b.create(string: str)
|
|
let weapon = Weapon.createWeapon(builder: &b, offset: axe, dmg: dmg)
|
|
let weapons = b.createVector(ofOffsets: [weapon])
|
|
let root = LocalMonster.createMonster(
|
|
builder: &b,
|
|
offset: weapons,
|
|
equipment: .Weapon,
|
|
equippedOffset: weapon.o)
|
|
b.finish(offset: root)
|
|
let buffer = b.sizedByteArray
|
|
// swiftformat:disable all
|
|
XCTAssertEqual(buffer, [16, 0, 0, 0, 0, 0, 10, 0, 16, 0, 8, 0, 7, 0, 12, 0, 10, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 20, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0])
|
|
// swiftformat:enable all
|
|
let monster = LocalMonster.getRootAsMonster(bb: ByteBuffer(bytes: buffer))
|
|
XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg)
|
|
XCTAssertEqual(monster.weapon(at: 0)?.name, str)
|
|
XCTAssertEqual(monster.weapon(at: 0)?.nameVector, [65, 120, 101])
|
|
let p: Weapon? = monster.equiped()
|
|
XCTAssertEqual(p?.dmg, dmg)
|
|
XCTAssertEqual(p?.name, str)
|
|
XCTAssertEqual(p?.nameVector, [65, 120, 101])
|
|
}
|
|
|
|
func testEndTableFinish() {
|
|
var builder = FlatBufferBuilder(initialSize: 20)
|
|
let sword = builder.create(string: "Sword")
|
|
let axe = builder.create(string: "Axe")
|
|
let weaponOne = Weapon.createWeapon(builder: &builder, offset: sword, dmg: 3)
|
|
let weaponTwo = Weapon.createWeapon(builder: &builder, offset: axe, dmg: 5)
|
|
let name = builder.create(string: "Orc")
|
|
let inventory: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
let inv = builder.createVector(inventory, size: 10)
|
|
let weapons = builder.createVector(ofOffsets: [weaponOne, weaponTwo])
|
|
let path = builder.createVector(ofStructs: [
|
|
Vec(x: 4.0, y: 5.0, z: 6.0),
|
|
Vec(x: 1.0, y: 2.0, z: 3.0),
|
|
])
|
|
let orc = FinalMonster.createMonster(
|
|
builder: &builder,
|
|
position: Vec(x: 1, y: 2, z: 3),
|
|
hp: 300,
|
|
name: name,
|
|
inventory: inv,
|
|
color: .red,
|
|
weapons: weapons,
|
|
equipment: .Weapon,
|
|
equippedOffset: weaponTwo,
|
|
path: path)
|
|
builder.finish(offset: orc)
|
|
// swiftformat:disable all
|
|
XCTAssertEqual(builder.sizedByteArray, [32, 0, 0, 0, 0, 0, 26, 0, 48, 0, 36, 0, 0, 0, 34, 0, 28, 0, 0, 0, 24, 0, 23, 0, 16, 0, 15, 0, 8, 0, 4, 0, 26, 0, 0, 0, 44, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 76, 0, 0, 0, 0, 0, 44, 1, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 0, 0, 128, 64, 0, 0, 160, 64, 0, 0, 192, 64, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 2, 0, 0, 0, 52, 0, 0, 0, 28, 0, 0, 0, 10, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 3, 0, 0, 0, 79, 114, 99, 0, 244, 255, 255, 255, 0, 0, 5, 0, 24, 0, 0, 0, 8, 0, 12, 0, 8, 0, 6, 0, 8, 0, 0, 0, 0, 0, 3, 0, 12, 0, 0, 0, 3, 0, 0, 0, 65, 120, 101, 0, 5, 0, 0, 0, 83, 119, 111, 114, 100, 0, 0, 0])
|
|
// swiftformat:enable all
|
|
}
|
|
|
|
func testEnumVector() {
|
|
let vectorOfEnums: [ColorsNameSpace.RGB] = [.blue, .green]
|
|
|
|
var builder = FlatBufferBuilder(initialSize: 1)
|
|
let off = builder.createVector(vectorOfEnums)
|
|
let start = ColorsNameSpace.Monster.startMonster(&builder)
|
|
ColorsNameSpace.Monster.add(colors: off, &builder)
|
|
let end = ColorsNameSpace.Monster.endMonster(&builder, start: start)
|
|
builder.finish(offset: end)
|
|
// swiftformat:disable all
|
|
XCTAssertEqual(builder.sizedByteArray, [12, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0])
|
|
// swiftformat:enable all
|
|
let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer)
|
|
XCTAssertEqual(monster.colorsCount, 2)
|
|
XCTAssertEqual(monster.colors(at: 0), .blue)
|
|
XCTAssertEqual(monster.colors(at: 1), .green)
|
|
}
|
|
|
|
func testUnionVector() {
|
|
var fb = FlatBufferBuilder()
|
|
|
|
let swordDmg: Int32 = 8
|
|
let attackStart = Attacker.startAttacker(&fb)
|
|
Attacker.add(swordAttackDamage: swordDmg, &fb)
|
|
let attack = Attacker.endAttacker(&fb, start: attackStart)
|
|
|
|
let characterType: [Character] = [.belle, .mulan, .bookfan]
|
|
|
|
let characters = [
|
|
fb.create(struct: BookReader(booksRead: 7)),
|
|
attack,
|
|
fb.create(struct: BookReader(booksRead: 2)),
|
|
]
|
|
let types = fb.createVector(characterType)
|
|
let characterVector = fb.createVector(ofOffsets: characters)
|
|
let end = Movie.createMovie(
|
|
&fb,
|
|
charactersTypeVectorOffset: types,
|
|
charactersVectorOffset: characterVector)
|
|
Movie.finish(&fb, end: end)
|
|
|
|
var movie = Movie.getRootAsMovie(bb: fb.buffer)
|
|
XCTAssertEqual(movie.charactersTypeCount, Int32(characterType.count))
|
|
XCTAssertEqual(movie.charactersCount, Int32(characters.count))
|
|
|
|
for i in 0..<movie.charactersTypeCount {
|
|
XCTAssertEqual(movie.charactersType(at: i), characterType[Int(i)])
|
|
}
|
|
|
|
XCTAssertEqual(
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
|
7)
|
|
XCTAssertEqual(
|
|
movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage,
|
|
swordDmg)
|
|
XCTAssertEqual(
|
|
movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead,
|
|
2)
|
|
|
|
var objc: MovieT? = movie.unpack()
|
|
XCTAssertEqual(movie.charactersTypeCount, Int32(objc?.characters.count ?? 0))
|
|
XCTAssertEqual(
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
|
(objc?.characters[0]?.value as? BookReader)?.booksRead)
|
|
fb.clear()
|
|
let newMovie = Movie.pack(&fb, obj: &objc)
|
|
fb.finish(offset: newMovie)
|
|
|
|
let packedMovie = Movie.getRootAsMovie(bb: fb.buffer)
|
|
|
|
XCTAssertEqual(
|
|
packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead)
|
|
XCTAssertEqual(
|
|
packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage,
|
|
movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage)
|
|
XCTAssertEqual(
|
|
packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead,
|
|
movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead)
|
|
}
|
|
|
|
func testStringUnion() {
|
|
let string = "Awesome \\\\t\t\nstring!"
|
|
var fb = FlatBufferBuilder()
|
|
let stringOffset = fb.create(string: string)
|
|
let characterType: [Character] = [.bookfan, .other]
|
|
|
|
let characters = [
|
|
fb.create(struct: BookReader(booksRead: 7)),
|
|
stringOffset,
|
|
]
|
|
let types = fb.createVector(characterType)
|
|
let characterVector = fb.createVector(ofOffsets: characters)
|
|
|
|
let end = Movie.createMovie(
|
|
&fb,
|
|
mainCharacterType: .other,
|
|
mainCharacterOffset: Offset(offset: stringOffset.o),
|
|
charactersTypeVectorOffset: types,
|
|
charactersVectorOffset: characterVector)
|
|
Movie.finish(&fb, end: end)
|
|
|
|
var movie = Movie.getRootAsMovie(bb: fb.sizedBuffer)
|
|
XCTAssertEqual(movie.mainCharacter(type: String.self), string)
|
|
XCTAssertEqual(
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
|
7)
|
|
XCTAssertEqual(movie.characters(at: 1, type: String.self), string)
|
|
|
|
var objc: MovieT? = movie.unpack()
|
|
XCTAssertEqual(objc?.mainCharacter?.value as? String, string)
|
|
XCTAssertEqual((objc?.characters[0]?.value as? BookReader)?.booksRead, 7)
|
|
XCTAssertEqual(objc?.characters[1]?.value as? String, string)
|
|
fb.clear()
|
|
let newMovie = Movie.pack(&fb, obj: &objc)
|
|
fb.finish(offset: newMovie)
|
|
|
|
let packedMovie = Movie.getRootAsMovie(bb: fb.buffer)
|
|
XCTAssertEqual(packedMovie.mainCharacter(type: String.self), string)
|
|
XCTAssertEqual(
|
|
packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
|
|
7)
|
|
XCTAssertEqual(packedMovie.characters(at: 1, type: String.self), string)
|
|
}
|
|
}
|
|
|
|
public enum ColorsNameSpace {
|
|
|
|
enum RGB: Int32, Enum {
|
|
typealias T = Int32
|
|
static var byteSize: Int { MemoryLayout<Int32>.size }
|
|
var value: Int32 { rawValue }
|
|
case red = 0, green = 1, blue = 2
|
|
}
|
|
|
|
struct Monster: FlatBufferObject {
|
|
var __buffer: ByteBuffer! { _accessor.bb }
|
|
|
|
private var _accessor: Table
|
|
static func getRootAsMonster(bb: ByteBuffer) -> Monster { Monster(Table(
|
|
bb: bb,
|
|
position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }
|
|
|
|
init(_ t: Table) { _accessor = t }
|
|
init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
|
|
|
|
public var colorsCount: Int32 { let o = _accessor.offset(4); return o == 0 ? 0 : _accessor.vector(count: o) }
|
|
public func colors(at index: Int32) -> ColorsNameSpace.RGB? { let o = _accessor.offset(4); return o == 0 ? ColorsNameSpace.RGB(rawValue: 0)! : ColorsNameSpace.RGB(rawValue: _accessor.directRead(
|
|
of: Int32.self,
|
|
offset: _accessor.vector(at: o) + index * 4)) }
|
|
static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
|
|
static func add(colors: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(
|
|
offset: colors,
|
|
at: 4) }
|
|
static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
|
|
}
|
|
}
|
|
|
|
|
|
enum Equipment: Byte { case none, Weapon }
|
|
|
|
enum Color3: Int8 { case red = 0, green, blue }
|
|
|
|
struct FinalMonster {
|
|
|
|
@inlinable
|
|
static func createMonster(
|
|
builder: inout FlatBufferBuilder,
|
|
position: Vec,
|
|
hp: Int16,
|
|
name: Offset,
|
|
inventory: Offset,
|
|
color: Color3,
|
|
weapons: Offset,
|
|
equipment: Equipment = .none,
|
|
equippedOffset: Offset,
|
|
path: Offset) -> Offset
|
|
{
|
|
let start = builder.startTable(with: 11)
|
|
builder.create(struct: position, position: 4)
|
|
builder.add(element: hp, def: 100, at: 8)
|
|
builder.add(offset: name, at: 10)
|
|
builder.add(offset: inventory, at: 14)
|
|
builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 16)
|
|
builder.add(offset: weapons, at: 18)
|
|
builder.add(
|
|
element: equipment.rawValue,
|
|
def: Equipment.none.rawValue,
|
|
at: 20)
|
|
builder.add(offset: equippedOffset, at: 22)
|
|
builder.add(offset: path, at: 24)
|
|
return Offset(offset: builder.endTable(at: start))
|
|
}
|
|
}
|
|
|
|
struct LocalMonster {
|
|
|
|
private var __t: Table
|
|
|
|
init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o) }
|
|
init(_ t: Table) { __t = t }
|
|
|
|
func weapon(at index: Int32) -> Weapon? { let o = __t.offset(4); return o == 0 ? nil : Weapon.assign(
|
|
__t.indirect(__t.vector(at: o) + (index * 4)),
|
|
__t.bb) }
|
|
|
|
func equiped<T: FlatBufferObject>() -> T? {
|
|
let o = __t.offset(8); return o == 0 ? nil : __t.union(o)
|
|
}
|
|
|
|
static func getRootAsMonster(bb: ByteBuffer) -> LocalMonster {
|
|
LocalMonster(Table(
|
|
bb: bb,
|
|
position: Int32(bb.read(def: UOffset.self, position: 0))))
|
|
}
|
|
|
|
@inlinable
|
|
static func createMonster(
|
|
builder: inout FlatBufferBuilder,
|
|
offset: Offset,
|
|
equipment: Equipment = .none,
|
|
equippedOffset: UOffset) -> Offset
|
|
{
|
|
let start = builder.startTable(with: 3)
|
|
builder.add(element: equippedOffset, def: 0, at: 8)
|
|
builder.add(offset: offset, at: 4)
|
|
builder.add(element: equipment.rawValue, def: Equipment.none.rawValue, at: 6)
|
|
return Offset(offset: builder.endTable(at: start))
|
|
}
|
|
}
|
|
|
|
struct Weapon: FlatBufferObject {
|
|
|
|
var __buffer: ByteBuffer! { __t.bb }
|
|
|
|
static let offsets: (name: VOffset, dmg: VOffset) = (4, 6)
|
|
private var __t: Table
|
|
|
|
init(_ t: Table) { __t = t }
|
|
init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)}
|
|
|
|
var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(
|
|
of: Int16.self,
|
|
at: o) }
|
|
var nameVector: [UInt8]? { __t.getVector(at: 4) }
|
|
var name: String? { let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
|
|
|
|
static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(
|
|
bb: bb,
|
|
position: i)) }
|
|
|
|
@inlinable
|
|
static func createWeapon(
|
|
builder: inout FlatBufferBuilder,
|
|
offset: Offset,
|
|
dmg: Int16) -> Offset
|
|
{
|
|
let _start = builder.startTable(with: 2)
|
|
Weapon.add(builder: &builder, name: offset)
|
|
Weapon.add(builder: &builder, dmg: dmg)
|
|
return Weapon.end(builder: &builder, startOffset: _start)
|
|
}
|
|
|
|
@inlinable
|
|
static func end(builder: inout FlatBufferBuilder, startOffset: UOffset) -> Offset {
|
|
Offset(offset: builder.endTable(at: startOffset))
|
|
}
|
|
|
|
@inlinable
|
|
static func add(builder: inout FlatBufferBuilder, name: Offset) {
|
|
builder.add(offset: name, at: Weapon.offsets.name)
|
|
}
|
|
|
|
@inlinable
|
|
static func add(builder: inout FlatBufferBuilder, dmg: Int16) {
|
|
builder.add(element: dmg, def: 0, at: Weapon.offsets.dmg)
|
|
}
|
|
}
|