mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-01 19:58:15 +00:00
* Migrating from Xctests to swift testing This migrates to the new Swift testing framework, which would allow us to always use the latest tech from swift moving forward. * Updates flag to make sure that Wasm testing works
496 lines
15 KiB
Swift
496 lines
15 KiB
Swift
/*
|
|
* Copyright 2024 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 Foundation
|
|
import Testing
|
|
|
|
@testable import FlatBuffers
|
|
|
|
struct FlatBuffersUnionTests {
|
|
|
|
@Test
|
|
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
|
|
#expect(
|
|
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))
|
|
#expect(monster.weapon(at: 0)?.dmg == dmg)
|
|
#expect(monster.weapon(at: 0)?.name == str)
|
|
#expect(monster.weapon(at: 0)?.nameVector == [65, 120, 101])
|
|
let p: Weapon? = monster.equiped()
|
|
#expect(p?.dmg == dmg)
|
|
#expect(p?.name == str)
|
|
#expect(p?.nameVector == [65, 120, 101])
|
|
}
|
|
|
|
@Test
|
|
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
|
|
#expect(
|
|
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
|
|
}
|
|
|
|
@Test
|
|
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
|
|
#expect(
|
|
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.sizedBuffer)
|
|
#expect(monster.colorsCount == 2)
|
|
let colors = monster.colors
|
|
#expect(colors[0] == .blue)
|
|
#expect(colors[1] == .green)
|
|
}
|
|
|
|
@Test
|
|
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 buffer = fb.sizedBuffer
|
|
let movie: Movie = getRoot(byteBuffer: &buffer)
|
|
#expect(movie.charactersType.count == characterType.count)
|
|
#expect(movie.characters.count == characters.count)
|
|
|
|
let bufferCharactersType = movie.charactersType
|
|
for (index, element) in bufferCharactersType.enumerated() {
|
|
#expect(element == characterType[index])
|
|
}
|
|
|
|
#expect(
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead ==
|
|
7)
|
|
#expect(
|
|
movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage ==
|
|
swordDmg)
|
|
#expect(
|
|
movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead ==
|
|
2)
|
|
|
|
var objc: MovieT? = movie.unpack()
|
|
#expect(
|
|
movie.charactersType.count == objc?.characters.count ?? 0)
|
|
#expect(
|
|
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)
|
|
|
|
var _buffer = fb.sizedBuffer
|
|
let packedMovie: Movie = getRoot(byteBuffer: &_buffer)
|
|
|
|
#expect(
|
|
packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead ==
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead)
|
|
#expect(
|
|
packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage ==
|
|
movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage)
|
|
#expect(
|
|
packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead ==
|
|
movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead)
|
|
}
|
|
|
|
@Test
|
|
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 buffer = fb.sizedBuffer
|
|
let movie: Movie = getRoot(byteBuffer: &buffer)
|
|
#expect(movie.mainCharacter(type: String.self) == string)
|
|
#expect(
|
|
movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead ==
|
|
7)
|
|
#expect(movie.characters(at: 1, type: String.self) == string)
|
|
|
|
var objc: MovieT? = movie.unpack()
|
|
#expect(objc?.mainCharacter?.value as? String == string)
|
|
#expect((objc?.characters[0]?.value as? BookReader)?.booksRead == 7)
|
|
#expect(objc?.characters[1]?.value as? String == string)
|
|
fb.clear()
|
|
let newMovie = Movie.pack(&fb, obj: &objc)
|
|
fb.finish(offset: newMovie)
|
|
|
|
var _buffer = fb.sizedBuffer
|
|
let packedMovie: Movie = getRoot(byteBuffer: &_buffer)
|
|
#expect(packedMovie.mainCharacter(type: String.self) == string)
|
|
#expect(
|
|
packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead ==
|
|
7)
|
|
#expect(packedMovie.characters(at: 1, type: String.self) == string)
|
|
}
|
|
|
|
@Test
|
|
func testEncoding() throws {
|
|
let string = "Awesome \\\\t\t\nstring!"
|
|
var fb = FlatBufferBuilder()
|
|
|
|
let stringOffset = fb.create(string: string)
|
|
|
|
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, .other]
|
|
|
|
let characters = [
|
|
fb.create(struct: BookReader(booksRead: 7)),
|
|
attack,
|
|
fb.create(struct: BookReader(booksRead: 2)),
|
|
stringOffset,
|
|
]
|
|
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 sizedBuffer = fb.sizedBuffer
|
|
let reader: Movie = try getCheckedRoot(byteBuffer: &sizedBuffer)
|
|
let encoder = JSONEncoder()
|
|
encoder.keyEncodingStrategy = .convertToSnakeCase
|
|
encoder.outputFormatting = [.sortedKeys]
|
|
let data = try encoder.encode(reader)
|
|
#expect(String(data: data, encoding: .utf8) == jsonData)
|
|
}
|
|
|
|
var jsonData: String {
|
|
"""
|
|
{"characters":[{"books_read":7},{"sword_attack_damage":8},{"books_read":2},"Awesome \\\\\\\\t\\t\\nstring!"],"characters_type":["Belle","MuLan","BookFan","Other"]}
|
|
"""
|
|
}
|
|
}
|
|
|
|
public enum ColorsNameSpace {
|
|
|
|
enum RGB: Int32, Enum, FlatbuffersVectorInitializable {
|
|
static var min: ColorsNameSpace.RGB { .red }
|
|
|
|
typealias T = Int32
|
|
static var byteSize: Int { MemoryLayout<Int32>.size }
|
|
var value: Int32 { rawValue }
|
|
case red = 0, green = 1, blue = 2
|
|
}
|
|
|
|
struct Monster: FlatBufferTable {
|
|
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 var colors: FlatbufferVector<RGB> {
|
|
_accessor.vector(at: 4, byteSize: 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
|
|
case 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: FlatBufferTable>() -> 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: FlatBufferTable {
|
|
|
|
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)
|
|
}
|
|
}
|