• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 FlatbuffersVerifierTests: XCTestCase {
21 
22   lazy var validStorage: ByteBuffer.Storage = ByteBuffer.Storage(
23     count: Int(FlatBufferMaxSize) - 1,
24     alignment: 1)
25   lazy var errorStorage: ByteBuffer.Storage = ByteBuffer.Storage(
26     count: Int(FlatBufferMaxSize) + 1,
27     alignment: 1)
28 
29   var buffer: ByteBuffer!
30 
31   var validFlatbuffersObject: ByteBuffer!
32   var invalidFlatbuffersObject: ByteBuffer!
33   var invalidFlatbuffersObject2: ByteBuffer!
34   var invalidFlatbuffersObject3: ByteBuffer!
35 
setUpnull36   override func setUp() {
37     // swiftformat:disable all
38     buffer = ByteBuffer(initialSize: 32)
39     add(buffer: &buffer, v: 4, p: 16)
40     add(buffer: &buffer, v: 4, p: 20)
41 
42     validFlatbuffersObject = ByteBuffer(bytes: [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
43 
44     invalidFlatbuffersObject = ByteBuffer(bytes: [0, 48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
45 
46     // Array failure within a the inventory array
47     invalidFlatbuffersObject2 = ByteBuffer(bytes: [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 0x00, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0])
48 
49     // Array failure within a the strings array
50     invalidFlatbuffersObject3 = ByteBuffer(bytes: [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 0x00, 111, 0, 0, 0])
51     // swiftformat:enable all
52   }
53 
testVeriferInitPassingnull54   func testVeriferInitPassing() {
55     var buffer = ByteBuffer(initialSize: 0)
56     buffer._storage = validStorage
57     XCTAssertNoThrow(try Verifier(buffer: &buffer))
58   }
59 
testVeriferInitFailingnull60   func testVeriferInitFailing() {
61     var buffer = ByteBuffer(initialSize: 0)
62     buffer._storage = errorStorage
63     XCTAssertThrowsError(try Verifier(buffer: &buffer))
64   }
65 
testFailingIDnull66   func testFailingID() {
67     let dutData : [UInt8] = [1,2,3,4,5,6,7]
68     var buff  = ByteBuffer(bytes: dutData)
69     do {
70       let _: Monster = try getCheckedRoot(byteBuffer: &buff, fileId: "ABCD")
71       XCTFail("This should always fail")
72     } catch {
73       XCTAssertEqual(error as? FlatbuffersErrors, .bufferDoesntContainID)
74     }
75   }
76 
testVerifierCheckAlignmentnull77   func testVerifierCheckAlignment() {
78     let verifier = try! Verifier(buffer: &buffer)
79     do {
80       try verifier.isAligned(position: 20, type: Int.self)
81     } catch {
82       XCTAssertEqual(
83         error as? FlatbuffersErrors,
84         .missAlignedPointer(position: 20, type: "Int"))
85     }
86     XCTAssertNoThrow(try verifier.isAligned(position: 16, type: Int.self))
87 
88     let newVerifer = try! Verifier(buffer: &buffer, checkAlignment: false)
89     XCTAssertNoThrow(try newVerifer.isAligned(position: 16, type: Int.self))
90   }
91 
testRangeInBuffernull92   func testRangeInBuffer() {
93     var verifier = try! Verifier(buffer: &buffer)
94     let size = MemoryLayout<Int64>.size
95     XCTAssertNoThrow(try verifier.rangeInBuffer(position: 24, size: size))
96     XCTAssertThrowsError(try verifier.rangeInBuffer(position: 26, size: size))
97     XCTAssertThrowsError(try verifier.rangeInBuffer(position: 26, size: size))
98     XCTAssertThrowsError(try verifier.rangeInBuffer(position: 30, size: size))
99     XCTAssertThrowsError(try verifier.rangeInBuffer(position: 32, size: size))
100     XCTAssertThrowsError(try verifier.rangeInBuffer(position: 34, size: size))
101 
102     verifier = try! Verifier(
103       buffer: &buffer,
104       options: .init(maxDepth: 0, maxTableCount: 0, maxApparentSize: 4))
105     do {
106       try verifier.rangeInBuffer(position: 24, size: size)
107     } catch {
108       XCTAssertEqual(
109         error as! FlatbuffersErrors,
110         .apparentSizeTooLarge)
111     }
112   }
113 
testPositionInBuffernull114   func testPositionInBuffer() {
115     let verifier = try! Verifier(buffer: &buffer)
116     XCTAssertNoThrow(try verifier.inBuffer(position: 0, of: Int64.self))
117     XCTAssertNoThrow(try verifier.inBuffer(position: 24, of: Int64.self))
118     XCTAssertThrowsError(try verifier.inBuffer(position: -9, of: Int64.self))
119     XCTAssertThrowsError(try verifier.inBuffer(position: 25, of: Int64.self))
120     XCTAssertThrowsError(try verifier.inBuffer(position: 26, of: Int32.self))
121     XCTAssertThrowsError(try verifier.inBuffer(position: 26, of: Int64.self))
122     XCTAssertThrowsError(try verifier.inBuffer(position: 30, of: Int64.self))
123     XCTAssertThrowsError(try verifier.inBuffer(position: 32, of: Int64.self))
124     XCTAssertThrowsError(try verifier.inBuffer(position: 34, of: Int64.self))
125   }
126 
testVisitTablenull127   func testVisitTable() {
128     var verifier = try! Verifier(buffer: &validFlatbuffersObject)
129     XCTAssertNoThrow(try verifier.visitTable(at: 48))
130     verifier.reset()
131   }
132 
testTableVerifiernull133   func testTableVerifier() {
134     var verifier = try! Verifier(buffer: &validFlatbuffersObject)
135 
136     var tableVerifer = try! verifier.visitTable(at: 48)
137     XCTAssertEqual(verifier.depth, 1)
138     XCTAssertEqual(verifier.tableCount, 1)
139 
140     XCTAssertNoThrow(try tableVerifer.visit(
141       field: 4,
142       fieldName: "Vec",
143       required: false,
144       type: Vec3.self))
145     XCTAssertNoThrow(try tableVerifer.visit(
146       field: 8,
147       fieldName: "hp",
148       required: false,
149       type: Int16.self))
150 
151     XCTAssertNoThrow(try tableVerifer.visit(
152       field: 10,
153       fieldName: "name",
154       required: true,
155       type: ForwardOffset<String>.self))
156 
157     XCTAssertNoThrow(try tableVerifer.visit(
158       field: 14,
159       fieldName: "inventory",
160       required: false,
161       type: ForwardOffset<Vector<UInt8, UInt8>>.self))
162 
163     XCTAssertNoThrow(try tableVerifer.visit(
164       field: 22,
165       fieldName: "test4",
166       required: false,
167       type: ForwardOffset<Vector<MyGame_Example_Test, MyGame_Example_Test>>
168         .self))
169 
170     XCTAssertNoThrow(try tableVerifer.visit(
171       field: 24,
172       fieldName: "Vector of strings",
173       required: false,
174       type: ForwardOffset<Vector<ForwardOffset<String>, String>>.self))
175 
176     do {
177       try tableVerifer.visit(
178         field: 13,
179         fieldName: "notvalid",
180         required: false,
181         type: Int16.self)
182     } catch {
183       XCTAssertEqual(
184         error as! FlatbuffersErrors,
185         .missAlignedPointer(position: 25, type: "UInt16"))
186     }
187 
188     do {
189       try tableVerifer.visit(
190         unionKey: 18,
191         unionField: 20,
192         unionKeyName: "testType",
193         fieldName: "test",
194         required: false,
195         completion: { (verifier, key: MyGame_Example_Any_, pos) in
196           switch key {
197           case .none_:
198             break
199           case .monster:
200             try ForwardOffset<MyGame_Example_Monster>.verify(
201               &verifier,
202               at: pos,
203               of: MyGame_Example_Monster.self)
204 
205           case .testsimpletablewithenum:
206             break
207           case .mygameExample2Monster:
208             break
209           }
210         })
211     } catch {
212       XCTAssertEqual(
213         error as! FlatbuffersErrors,
214         .missAlignedPointer(position: 25, type: "UInt16"))
215     }
216     tableVerifer.finish()
217     XCTAssertEqual(verifier.depth, 0)
218   }
219 
testVerifyUnionVectorsnull220   func testVerifyUnionVectors() {
221     // swiftformat:disable all
222     var byteBuffer = ByteBuffer(bytes: [20, 0, 0, 0, 77, 79, 86, 73, 12, 0, 12, 0, 0, 0, 0, 0, 8, 0, 4, 0, 12, 0, 0, 0, 8, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 3, 0, 0, 0, 3, 1, 4, 0, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0])
223     // swiftformat:enable all
224     XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &byteBuffer) as Movie)
225   }
226 
testErrorWrongFileIdnull227   func testErrorWrongFileId() {
228     // swiftformat:disable all
229     var byteBuffer = ByteBuffer(bytes: [20, 0, 0, 0, 77, 79, 86, 73, 12, 0, 12, 0, 0, 0, 0, 0, 8, 0, 4, 0, 12, 0, 0, 0, 8, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 3, 0, 0, 0, 3, 1, 4, 0, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0])
230     // swiftformat:enable all
231     XCTAssertThrowsError(try getCheckedRoot(
232       byteBuffer: &byteBuffer,
233       fileId: "FLEX") as Movie)
234   }
235 
testVerifyPrefixedBuffernull236   func testVerifyPrefixedBuffer() {
237     // swiftformat:disable all
238     var byteBuffer = ByteBuffer(bytes: [0, 0, 0, 1, 20, 0, 0, 0, 77, 79, 86, 73, 12, 0, 12, 0, 0, 0, 0, 0, 8, 0, 4, 0, 12, 0, 0, 0, 8, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0, 32, 0, 0, 0, 12, 0, 0, 0, 3, 0, 0, 0, 3, 1, 4, 0, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 6, 0, 8, 0, 4, 0, 6, 0, 0, 0, 8, 0, 0, 0])
239     // swiftformat:enable all
240     XCTAssertThrowsError(
241       try getCheckedPrefixedSizeRoot(byteBuffer: &byteBuffer) as Movie)
242   }
243 
testFullVerifiernull244   func testFullVerifier() {
245     XCTAssertNoThrow(
246       try getCheckedRoot(
247         byteBuffer: &validFlatbuffersObject) as MyGame_Example_Monster)
248   }
249 
testFullVerifierWithFileIdnull250   func testFullVerifierWithFileId() {
251     XCTAssertNoThrow(
252       try getCheckedRoot(
253         byteBuffer: &validFlatbuffersObject,
254         fileId: MyGame_Example_Monster.id) as MyGame_Example_Monster)
255   }
256 
testInvalidBuffernull257   func testInvalidBuffer() {
258     XCTAssertThrowsError(
259       try getCheckedRoot(
260         byteBuffer: &invalidFlatbuffersObject) as MyGame_Example_Monster)
261   }
262 
testInvalidBuffer2null263   func testInvalidBuffer2() {
264     XCTAssertThrowsError(
265       try getCheckedRoot(
266         byteBuffer: &invalidFlatbuffersObject2) as MyGame_Example_Monster)
267   }
268 
testInvalidBuffer3null269   func testInvalidBuffer3() {
270     XCTAssertThrowsError(
271       try getCheckedRoot(
272         byteBuffer: &invalidFlatbuffersObject3) as MyGame_Example_Monster)
273   }
274 
testValidUnionBuffernull275   func testValidUnionBuffer() {
276     let string = "Awesome \\\\t\t\nstring!"
277     var fb = FlatBufferBuilder()
278     let stringOffset = fb.create(string: string)
279     let characterType: [Character] = [.bookfan, .other]
280 
281     let characters = [
282       fb.create(struct: BookReader(booksRead: 7)),
283       stringOffset,
284     ]
285     let types = fb.createVector(characterType)
286     let characterVector = fb.createVector(ofOffsets: characters)
287 
288     let end = Movie.createMovie(
289       &fb,
290       mainCharacterType: .other,
291       mainCharacterOffset: Offset(offset: stringOffset.o),
292       charactersTypeVectorOffset: types,
293       charactersVectorOffset: characterVector)
294     Movie.finish(&fb, end: end)
295     var buf = fb.sizedBuffer
296     XCTAssertNoThrow(try getCheckedRoot(byteBuffer: &buf) as Movie)
297   }
298 
testNestedTablesnull299   func testNestedTables() throws {
300     var builder = FlatBufferBuilder()
301     let name = builder.create(string: "Monster")
302 
303     let enemy = MyGame_Example_Monster.createMonster(
304       &builder,
305       nameOffset: name)
306     let currentName = builder.create(string: "Main name")
307     let monster = MyGame_Example_Monster.createMonster(
308       &builder,
309       nameOffset: currentName,
310       enemyOffset: enemy)
311     builder.finish(offset: monster)
312 
313     var sizedBuffer = builder.sizedBuffer
314     var verifier = try! Verifier(buffer: &sizedBuffer)
315     var tableVerifer = try! verifier.visitTable(
316       at: try getOffset(at: 0, within: verifier))
317     XCTAssertEqual(verifier.depth, 1)
318     XCTAssertEqual(verifier.tableCount, 1)
319 
320     let position = try tableVerifer.dereference(28)!
321 
322     var nestedTable = try verifier.visitTable(
323       at: try getOffset(at: position, within: verifier))
324 
325     XCTAssertEqual(verifier.depth, 2)
326     XCTAssertEqual(verifier.tableCount, 2)
327     nestedTable.finish()
328     XCTAssertEqual(verifier.depth, 1)
329     XCTAssertEqual(verifier.tableCount, 2)
330     tableVerifer.finish()
331     XCTAssertEqual(verifier.depth, 0)
332     XCTAssertEqual(verifier.tableCount, 2)
333   }
334 
addnull335   func add(buffer: inout ByteBuffer, v: Int32, p: Int) {
336     buffer.write(value: v, index: p)
337   }
338 
339   private func getOffset(
340     at value: Int,
341     within verifier: Verifier) throws -> Int
342   {
343     let offset: UOffset = try verifier.getValue(at: value)
344     return Int(clamping: (Int(offset) &+ 0).magnitude)
345   }
346 }
347