• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import XCTest
18 @testable import FlatBuffers
19 
20 final class FlatBuffersUnionTests: XCTestCase {
21 
testCreateMonstornull22   func testCreateMonstor() {
23 
24     var b = FlatBufferBuilder(initialSize: 20)
25     let dmg: Int16 = 5
26     let str = "Axe"
27     let axe = b.create(string: str)
28     let weapon = Weapon.createWeapon(builder: &b, offset: axe, dmg: dmg)
29     let weapons = b.createVector(ofOffsets: [weapon])
30     let root = LocalMonster.createMonster(
31       builder: &b,
32       offset: weapons,
33       equipment: .Weapon,
34       equippedOffset: weapon.o)
35     b.finish(offset: root)
36     let buffer = b.sizedByteArray
37     // swiftformat:disable all
38     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])
39     // swiftformat:enable all
40     let monster = LocalMonster.getRootAsMonster(bb: ByteBuffer(bytes: buffer))
41     XCTAssertEqual(monster.weapon(at: 0)?.dmg, dmg)
42     XCTAssertEqual(monster.weapon(at: 0)?.name, str)
43     XCTAssertEqual(monster.weapon(at: 0)?.nameVector, [65, 120, 101])
44     let p: Weapon? = monster.equiped()
45     XCTAssertEqual(p?.dmg, dmg)
46     XCTAssertEqual(p?.name, str)
47     XCTAssertEqual(p?.nameVector, [65, 120, 101])
48   }
49 
testEndTableFinishnull50   func testEndTableFinish() {
51     var builder = FlatBufferBuilder(initialSize: 20)
52     let sword = builder.create(string: "Sword")
53     let axe = builder.create(string: "Axe")
54     let weaponOne = Weapon.createWeapon(
55       builder: &builder,
56       offset: sword,
57       dmg: 3)
58     let weaponTwo = Weapon.createWeapon(builder: &builder, offset: axe, dmg: 5)
59     let name = builder.create(string: "Orc")
60     let inventory: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
61     let inv = builder.createVector(inventory, size: 10)
62     let weapons = builder.createVector(ofOffsets: [weaponOne, weaponTwo])
63     let path = builder.createVector(ofStructs: [
64       Vec(x: 4.0, y: 5.0, z: 6.0),
65       Vec(x: 1.0, y: 2.0, z: 3.0),
66     ])
67     let orc = FinalMonster.createMonster(
68       builder: &builder,
69       position: Vec(x: 1, y: 2, z: 3),
70       hp: 300,
71       name: name,
72       inventory: inv,
73       color: .red,
74       weapons: weapons,
75       equipment: .Weapon,
76       equippedOffset: weaponTwo,
77       path: path)
78     builder.finish(offset: orc)
79     // swiftformat:disable all
80     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])
81     // swiftformat:enable all
82   }
83 
testEnumVectornull84   func testEnumVector() {
85     let vectorOfEnums: [ColorsNameSpace.RGB] = [.blue, .green]
86 
87     var builder = FlatBufferBuilder(initialSize: 1)
88     let off = builder.createVector(vectorOfEnums)
89     let start = ColorsNameSpace.Monster.startMonster(&builder)
90     ColorsNameSpace.Monster.add(colors: off, &builder)
91     let end = ColorsNameSpace.Monster.endMonster(&builder, start: start)
92     builder.finish(offset: end)
93     // swiftformat:disable all
94     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])
95     // swiftformat:enable all
96     let monster = ColorsNameSpace.Monster.getRootAsMonster(bb: builder.buffer)
97     XCTAssertEqual(monster.colorsCount, 2)
98     XCTAssertEqual(monster.colors(at: 0), .blue)
99     XCTAssertEqual(monster.colors(at: 1), .green)
100   }
101 
testUnionVectornull102   func testUnionVector() {
103     var fb = FlatBufferBuilder()
104 
105     let swordDmg: Int32 = 8
106     let attackStart = Attacker.startAttacker(&fb)
107     Attacker.add(swordAttackDamage: swordDmg, &fb)
108     let attack = Attacker.endAttacker(&fb, start: attackStart)
109 
110     let characterType: [Character] = [.belle, .mulan, .bookfan]
111 
112     let characters = [
113       fb.create(struct: BookReader(booksRead: 7)),
114       attack,
115       fb.create(struct: BookReader(booksRead: 2)),
116     ]
117     let types = fb.createVector(characterType)
118     let characterVector = fb.createVector(ofOffsets: characters)
119     let end = Movie.createMovie(
120       &fb,
121       charactersTypeVectorOffset: types,
122       charactersVectorOffset: characterVector)
123     Movie.finish(&fb, end: end)
124 
125     var buffer = fb.buffer
126     var movie: Movie = getRoot(byteBuffer: &buffer)
127     XCTAssertEqual(movie.charactersTypeCount, Int32(characterType.count))
128     XCTAssertEqual(movie.charactersCount, Int32(characters.count))
129 
130     for i in 0..<movie.charactersTypeCount {
131       XCTAssertEqual(movie.charactersType(at: i), characterType[Int(i)])
132     }
133 
134     XCTAssertEqual(
135       movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
136       7)
137     XCTAssertEqual(
138       movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage,
139       swordDmg)
140     XCTAssertEqual(
141       movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead,
142       2)
143 
144     var objc: MovieT? = movie.unpack()
145     XCTAssertEqual(
146       movie.charactersTypeCount,
147       Int32(objc?.characters.count ?? 0))
148     XCTAssertEqual(
149       movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
150       (objc?.characters[0]?.value as? BookReader)?.booksRead)
151     fb.clear()
152     let newMovie = Movie.pack(&fb, obj: &objc)
153     fb.finish(offset: newMovie)
154 
155     var _buffer = fb.buffer
156     let packedMovie: Movie = getRoot(byteBuffer: &_buffer)
157 
158     XCTAssertEqual(
159       packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
160       movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead)
161     XCTAssertEqual(
162       packedMovie.characters(at: 1, type: Attacker.self)?.swordAttackDamage,
163       movie.characters(at: 1, type: Attacker.self)?.swordAttackDamage)
164     XCTAssertEqual(
165       packedMovie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead,
166       movie.characters(at: 2, type: BookReader_Mutable.self)?.booksRead)
167   }
168 
testStringUnionnull169   func testStringUnion() {
170     let string = "Awesome \\\\t\t\nstring!"
171     var fb = FlatBufferBuilder()
172     let stringOffset = fb.create(string: string)
173     let characterType: [Character] = [.bookfan, .other]
174 
175     let characters = [
176       fb.create(struct: BookReader(booksRead: 7)),
177       stringOffset,
178     ]
179     let types = fb.createVector(characterType)
180     let characterVector = fb.createVector(ofOffsets: characters)
181 
182     let end = Movie.createMovie(
183       &fb,
184       mainCharacterType: .other,
185       mainCharacterOffset: Offset(offset: stringOffset.o),
186       charactersTypeVectorOffset: types,
187       charactersVectorOffset: characterVector)
188     Movie.finish(&fb, end: end)
189 
190     var buffer = fb.sizedBuffer
191     var movie: Movie = getRoot(byteBuffer: &buffer)
192     XCTAssertEqual(movie.mainCharacter(type: String.self), string)
193     XCTAssertEqual(
194       movie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
195       7)
196     XCTAssertEqual(movie.characters(at: 1, type: String.self), string)
197 
198     var objc: MovieT? = movie.unpack()
199     XCTAssertEqual(objc?.mainCharacter?.value as? String, string)
200     XCTAssertEqual((objc?.characters[0]?.value as? BookReader)?.booksRead, 7)
201     XCTAssertEqual(objc?.characters[1]?.value as? String, string)
202     fb.clear()
203     let newMovie = Movie.pack(&fb, obj: &objc)
204     fb.finish(offset: newMovie)
205 
206     var _buffer = fb.buffer
207     let packedMovie: Movie = getRoot(byteBuffer: &_buffer)
208     XCTAssertEqual(packedMovie.mainCharacter(type: String.self), string)
209     XCTAssertEqual(
210       packedMovie.characters(at: 0, type: BookReader_Mutable.self)?.booksRead,
211       7)
212     XCTAssertEqual(packedMovie.characters(at: 1, type: String.self), string)
213   }
214 
testEncodingnull215   func testEncoding() {
216     let string = "Awesome \\\\t\t\nstring!"
217     var fb = FlatBufferBuilder()
218 
219     let stringOffset = fb.create(string: string)
220 
221     let swordDmg: Int32 = 8
222     let attackStart = Attacker.startAttacker(&fb)
223     Attacker.add(swordAttackDamage: swordDmg, &fb)
224     let attack = Attacker.endAttacker(&fb, start: attackStart)
225 
226     let characterType: [Character] = [.belle, .mulan, .bookfan, .other]
227 
228     let characters = [
229       fb.create(struct: BookReader(booksRead: 7)),
230       attack,
231       fb.create(struct: BookReader(booksRead: 2)),
232       stringOffset,
233     ]
234     let types = fb.createVector(characterType)
235     let characterVector = fb.createVector(ofOffsets: characters)
236     let end = Movie.createMovie(
237       &fb,
238       charactersTypeVectorOffset: types,
239       charactersVectorOffset: characterVector)
240     Movie.finish(&fb, end: end)
241 
242     var sizedBuffer = fb.sizedBuffer
243     do {
244       let reader: Movie = try getCheckedRoot(byteBuffer: &sizedBuffer)
245       let encoder = JSONEncoder()
246       encoder.keyEncodingStrategy = .convertToSnakeCase
247       _ = try encoder.encode(reader)
248     } catch {
249       XCTFail(error.localizedDescription)
250     }
251   }
252 
253   var jsonData: String {
254     "{\"characters_type\":[\"Belle\",\"MuLan\",\"BookFan\",\"Other\"],\"characters\":[{\"books_read\":7},{\"sword_attack_damage\":8},{\"books_read\":2},\"Awesome \\\\\\\\t\\t\\nstring!\"]}"
255   }
256 }
257 
258 public enum ColorsNameSpace {
259 
260   enum RGB: Int32, Enum {
261     typealias T = Int32
262     static var byteSize: Int { MemoryLayout<Int32>.size }
263     var value: Int32 { rawValue }
264     case red = 0, green = 1, blue = 2
265   }
266 
267   struct Monster: FlatBufferObject {
268     var __buffer: ByteBuffer! { _accessor.bb }
269 
270     private var _accessor: Table
getRootAsMonsternull271     static func getRootAsMonster(bb: ByteBuffer) -> Monster { Monster(Table(
272       bb: bb,
273       position: Int32(bb.read(def: UOffset.self, position: bb.reader)) +
274         Int32(bb.reader))) }
275 
276     init(_ t: Table) { _accessor = t }
277     init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
278 
279     public var colorsCount: Int32 {
280       let o = _accessor.offset(4); return o == 0 ? 0 : _accessor
281         .vector(count: o) }
colorsnull282     public func colors(at index: Int32) -> ColorsNameSpace
283       .RGB?
284     { let o = _accessor.offset(4); return o == 0 ? ColorsNameSpace
285       .RGB(rawValue: 0)! : ColorsNameSpace.RGB(rawValue: _accessor.directRead(
286         of: Int32.self,
287         offset: _accessor.vector(at: o) + index * 4)) }
startMonsternull288     static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb
289       .startTable(with: 1) }
addnull290     static func add(colors: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(
291       offset: colors,
292       at: 4)  }
293     static func endMonster(
294       _ fbb: inout FlatBufferBuilder,
295       start: UOffset)
296       -> Offset
297     { let end = Offset(offset: fbb.endTable(at: start)); return end
298     }
299   }
300 }
301 
302 
303 enum Equipment: Byte { case none, Weapon }
304 
305 enum Color3: Int8 { case red = 0, green, blue }
306 
307 struct FinalMonster {
308 
309   @inlinable
310   static func createMonster(
311     builder: inout FlatBufferBuilder,
312     position: Vec,
313     hp: Int16,
314     name: Offset,
315     inventory: Offset,
316     color: Color3,
317     weapons: Offset,
318     equipment: Equipment = .none,
319     equippedOffset: Offset,
320     path: Offset) -> Offset
321   {
322     let start = builder.startTable(with: 11)
323     builder.create(struct: position, position: 4)
324     builder.add(element: hp, def: 100, at: 8)
325     builder.add(offset: name, at: 10)
326     builder.add(offset: inventory, at: 14)
327     builder.add(element: color.rawValue, def: Color3.green.rawValue, at: 16)
328     builder.add(offset: weapons, at: 18)
329     builder.add(
330       element: equipment.rawValue,
331       def: Equipment.none.rawValue,
332       at: 20)
333     builder.add(offset: equippedOffset, at: 22)
334     builder.add(offset: path, at: 24)
335     return Offset(offset: builder.endTable(at: start))
336   }
337 }
338 
339 struct LocalMonster {
340 
341   private var __t: Table
342 
343   init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o) }
344   init(_ t: Table) { __t = t }
345 
weaponnull346   func weapon(at index: Int32) -> Weapon? { let o = __t
347     .offset(4); return o == 0 ? nil : Weapon.assign(
348       __t.indirect(__t.vector(at: o) + (index * 4)),
349       __t.bb) }
350 
equiped<T: FlatBufferObject>null351   func equiped<T: FlatBufferObject>() -> T? {
352     let o = __t.offset(8); return o == 0 ? nil : __t.union(o)
353   }
354 
getRootAsMonsternull355   static func getRootAsMonster(bb: ByteBuffer) -> LocalMonster {
356     LocalMonster(Table(
357       bb: bb,
358       position: Int32(bb.read(def: UOffset.self, position: 0))))
359   }
360 
361   @inlinable
362   static func createMonster(
363     builder: inout FlatBufferBuilder,
364     offset: Offset,
365     equipment: Equipment = .none,
366     equippedOffset: UOffset) -> Offset
367   {
368     let start = builder.startTable(with: 3)
369     builder.add(element: equippedOffset, def: 0, at: 8)
370     builder.add(offset: offset, at: 4)
371     builder.add(
372       element: equipment.rawValue,
373       def: Equipment.none.rawValue,
374       at: 6)
375     return Offset(offset: builder.endTable(at: start))
376   }
377 }
378 
379 struct Weapon: FlatBufferObject {
380 
381   var __buffer: ByteBuffer! { __t.bb }
382 
383   static let offsets: (name: VOffset, dmg: VOffset) = (4, 6)
384   private var __t: Table
385 
386   init(_ t: Table) { __t = t }
387   init(_ fb: ByteBuffer, o: Int32) { __t = Table(bb: fb, position: o)}
388 
389   var dmg: Int16 { let o = __t.offset(6); return o == 0 ? 0 : __t.readBuffer(
390     of: Int16.self,
391     at: o) }
392   var nameVector: [UInt8]? { __t.getVector(at: 4) }
393   var name: String? {
394     let o = __t.offset(4); return o == 0 ? nil : __t.string(at: o) }
395 
assignnull396   static func assign(_ i: Int32, _ bb: ByteBuffer) -> Weapon { Weapon(Table(
397     bb: bb,
398     position: i)) }
399 
400   @inlinable
401   static func createWeapon(
402     builder: inout FlatBufferBuilder,
403     offset: Offset,
404     dmg: Int16) -> Offset
405   {
406     let _start = builder.startTable(with: 2)
407     Weapon.add(builder: &builder, name: offset)
408     Weapon.add(builder: &builder, dmg: dmg)
409     return Weapon.end(builder: &builder, startOffset: _start)
410   }
411 
412   @inlinable
413   static func end(
414     builder: inout FlatBufferBuilder,
415     startOffset: UOffset) -> Offset
416   {
417     Offset(offset: builder.endTable(at: startOffset))
418   }
419 
420   @inlinable
addnull421   static func add(builder: inout FlatBufferBuilder, name: Offset) {
422     builder.add(offset: name, at: Weapon.offsets.name)
423   }
424 
425   @inlinable
addnull426   static func add(builder: inout FlatBufferBuilder, dmg: Int16) {
427     builder.add(element: dmg, def: 0, at: Weapon.offsets.dmg)
428   }
429 }
430