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