Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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 | using System.IO; |
| 18 | using System.Text; |
| 19 | using MyGame.Example; |
| 20 | |
| 21 | namespace FlatBuffers.Test |
| 22 | { |
| 23 | [FlatBuffersTestClass] |
| 24 | public class FlatBuffersExampleTests |
| 25 | { |
| 26 | public void RunTests() |
| 27 | { |
| 28 | CanCreateNewFlatBufferFromScratch(); |
| 29 | CanReadCppGeneratedWireFile(); |
| 30 | TestEnums(); |
| 31 | } |
| 32 | |
| 33 | [FlatBuffersTestMethod] |
| 34 | public void CanCreateNewFlatBufferFromScratch() |
| 35 | { |
| 36 | CanCreateNewFlatBufferFromScratch(true); |
| 37 | CanCreateNewFlatBufferFromScratch(false); |
| 38 | } |
| 39 | |
| 40 | private void CanCreateNewFlatBufferFromScratch(bool sizePrefix) |
| 41 | { |
| 42 | // Second, let's create a FlatBuffer from scratch in C#, and test it also. |
| 43 | // We use an initial size of 1 to exercise the reallocation algorithm, |
| 44 | // normally a size larger than the typical FlatBuffer you generate would be |
| 45 | // better for performance. |
| 46 | var fbb = new FlatBufferBuilder(1); |
| 47 | |
| 48 | StringOffset[] names = { fbb.CreateString("Frodo"), fbb.CreateString("Barney"), fbb.CreateString("Wilma") }; |
| 49 | Offset<Monster>[] off = new Offset<Monster>[3]; |
| 50 | Monster.StartMonster(fbb); |
| 51 | Monster.AddName(fbb, names[0]); |
| 52 | off[0] = Monster.EndMonster(fbb); |
| 53 | Monster.StartMonster(fbb); |
| 54 | Monster.AddName(fbb, names[1]); |
| 55 | off[1] = Monster.EndMonster(fbb); |
| 56 | Monster.StartMonster(fbb); |
| 57 | Monster.AddName(fbb, names[2]); |
| 58 | off[2] = Monster.EndMonster(fbb); |
| 59 | var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off); |
| 60 | |
| 61 | // We set up the same values as monsterdata.json: |
| 62 | |
| 63 | var str = fbb.CreateString("MyMonster"); |
| 64 | var test1 = fbb.CreateString("test1"); |
| 65 | var test2 = fbb.CreateString("test2"); |
| 66 | |
| 67 | |
| 68 | Monster.StartInventoryVector(fbb, 5); |
| 69 | for (int i = 4; i >= 0; i--) |
| 70 | { |
| 71 | fbb.AddByte((byte)i); |
| 72 | } |
| 73 | var inv = fbb.EndVector(); |
| 74 | |
| 75 | var fred = fbb.CreateString("Fred"); |
| 76 | Monster.StartMonster(fbb); |
| 77 | Monster.AddName(fbb, fred); |
| 78 | var mon2 = Monster.EndMonster(fbb); |
| 79 | |
| 80 | Monster.StartTest4Vector(fbb, 2); |
| 81 | MyGame.Example.Test.CreateTest(fbb, (short)10, (sbyte)20); |
| 82 | MyGame.Example.Test.CreateTest(fbb, (short)30, (sbyte)40); |
| 83 | var test4 = fbb.EndVector(); |
| 84 | |
| 85 | Monster.StartTestarrayofstringVector(fbb, 2); |
| 86 | fbb.AddOffset(test2.Value); |
| 87 | fbb.AddOffset(test1.Value); |
| 88 | var testArrayOfString = fbb.EndVector(); |
| 89 | |
| 90 | Monster.StartMonster(fbb); |
| 91 | Monster.AddPos(fbb, Vec3.CreateVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, |
| 92 | Color.Green, (short)5, (sbyte)6)); |
| 93 | Monster.AddHp(fbb, (short)80); |
| 94 | Monster.AddName(fbb, str); |
| 95 | Monster.AddInventory(fbb, inv); |
| 96 | Monster.AddTestType(fbb, Any.Monster); |
| 97 | Monster.AddTest(fbb, mon2.Value); |
| 98 | Monster.AddTest4(fbb, test4); |
| 99 | Monster.AddTestarrayofstring(fbb, testArrayOfString); |
| 100 | Monster.AddTestbool(fbb, true); |
| 101 | Monster.AddTestarrayoftables(fbb, sortMons); |
| 102 | var mon = Monster.EndMonster(fbb); |
| 103 | |
| 104 | if (sizePrefix) |
| 105 | { |
| 106 | Monster.FinishSizePrefixedMonsterBuffer(fbb, mon); |
| 107 | } |
| 108 | else |
| 109 | { |
| 110 | Monster.FinishMonsterBuffer(fbb, mon); |
| 111 | } |
| 112 | |
| 113 | // Dump to output directory so we can inspect later, if needed |
| 114 | #if ENABLE_SPAN_T |
| 115 | var data = fbb.DataBuffer.ToSizedArray(); |
| 116 | string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon"; |
| 117 | File.WriteAllBytes(filename, data); |
| 118 | #else |
| 119 | using (var ms = fbb.DataBuffer.ToMemoryStream(fbb.DataBuffer.Position, fbb.Offset)) |
| 120 | { |
| 121 | var data = ms.ToArray(); |
| 122 | string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon"; |
| 123 | File.WriteAllBytes(filename, data); |
| 124 | } |
| 125 | #endif |
| 126 | |
| 127 | // Remove the size prefix if necessary for further testing |
| 128 | ByteBuffer dataBuffer = fbb.DataBuffer; |
| 129 | if (sizePrefix) |
| 130 | { |
| 131 | Assert.AreEqual(ByteBufferUtil.GetSizePrefix(dataBuffer) + FlatBufferConstants.SizePrefixLength, |
| 132 | dataBuffer.Length - dataBuffer.Position); |
| 133 | dataBuffer = ByteBufferUtil.RemoveSizePrefix(dataBuffer); |
| 134 | } |
| 135 | |
| 136 | // Now assert the buffer |
| 137 | TestBuffer(dataBuffer); |
| 138 | |
| 139 | //Attempt to mutate Monster fields and check whether the buffer has been mutated properly |
| 140 | // revert to original values after testing |
| 141 | Monster monster = Monster.GetRootAsMonster(dataBuffer); |
| 142 | |
| 143 | |
| 144 | // mana is optional and does not exist in the buffer so the mutation should fail |
| 145 | // the mana field should retain its default value |
| 146 | Assert.AreEqual(monster.MutateMana((short)10), false); |
| 147 | Assert.AreEqual(monster.Mana, (short)150); |
| 148 | |
| 149 | // Accessing a vector of sorted by the key tables |
| 150 | Assert.AreEqual(monster.Testarrayoftables(0).Value.Name, "Barney"); |
| 151 | Assert.AreEqual(monster.Testarrayoftables(1).Value.Name, "Frodo"); |
| 152 | Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma"); |
| 153 | |
| 154 | // Example of searching for a table by the key |
| 155 | Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null); |
| 156 | Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null); |
| 157 | Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null); |
| 158 | |
| 159 | // testType is an existing field and mutating it should succeed |
| 160 | Assert.AreEqual(monster.TestType, Any.Monster); |
| 161 | Assert.AreEqual(monster.MutateTestType(Any.NONE), true); |
| 162 | Assert.AreEqual(monster.TestType, Any.NONE); |
| 163 | Assert.AreEqual(monster.MutateTestType(Any.Monster), true); |
| 164 | Assert.AreEqual(monster.TestType, Any.Monster); |
| 165 | |
| 166 | //mutate the inventory vector |
| 167 | Assert.AreEqual(monster.MutateInventory(0, 1), true); |
| 168 | Assert.AreEqual(monster.MutateInventory(1, 2), true); |
| 169 | Assert.AreEqual(monster.MutateInventory(2, 3), true); |
| 170 | Assert.AreEqual(monster.MutateInventory(3, 4), true); |
| 171 | Assert.AreEqual(monster.MutateInventory(4, 5), true); |
| 172 | |
| 173 | for (int i = 0; i < monster.InventoryLength; i++) |
| 174 | { |
| 175 | Assert.AreEqual(monster.Inventory(i), i + 1); |
| 176 | } |
| 177 | |
| 178 | //reverse mutation |
| 179 | Assert.AreEqual(monster.MutateInventory(0, 0), true); |
| 180 | Assert.AreEqual(monster.MutateInventory(1, 1), true); |
| 181 | Assert.AreEqual(monster.MutateInventory(2, 2), true); |
| 182 | Assert.AreEqual(monster.MutateInventory(3, 3), true); |
| 183 | Assert.AreEqual(monster.MutateInventory(4, 4), true); |
| 184 | |
| 185 | // get a struct field and edit one of its fields |
| 186 | Vec3 pos = (Vec3)monster.Pos; |
| 187 | Assert.AreEqual(pos.X, 1.0f); |
| 188 | pos.MutateX(55.0f); |
| 189 | Assert.AreEqual(pos.X, 55.0f); |
| 190 | pos.MutateX(1.0f); |
| 191 | Assert.AreEqual(pos.X, 1.0f); |
| 192 | |
| 193 | TestBuffer(dataBuffer); |
| 194 | } |
| 195 | |
| 196 | private void TestBuffer(ByteBuffer bb) |
| 197 | { |
| 198 | Monster monster = Monster.GetRootAsMonster(bb); |
| 199 | |
| 200 | Assert.AreEqual(80, monster.Hp); |
| 201 | Assert.AreEqual(150, monster.Mana); |
| 202 | Assert.AreEqual("MyMonster", monster.Name); |
| 203 | |
| 204 | var pos = monster.Pos.Value; |
| 205 | Assert.AreEqual(1.0f, pos.X); |
| 206 | Assert.AreEqual(2.0f, pos.Y); |
| 207 | Assert.AreEqual(3.0f, pos.Z); |
| 208 | |
| 209 | Assert.AreEqual(3.0f, pos.Test1); |
| 210 | Assert.AreEqual(Color.Green, pos.Test2); |
| 211 | var t = (MyGame.Example.Test)pos.Test3; |
| 212 | Assert.AreEqual((short)5, t.A); |
| 213 | Assert.AreEqual((sbyte)6, t.B); |
| 214 | |
| 215 | Assert.AreEqual(Any.Monster, monster.TestType); |
| 216 | |
| 217 | var monster2 = monster.Test<Monster>().Value; |
| 218 | Assert.AreEqual("Fred", monster2.Name); |
| 219 | |
| 220 | |
| 221 | Assert.AreEqual(5, monster.InventoryLength); |
| 222 | var invsum = 0; |
| 223 | for (var i = 0; i < monster.InventoryLength; i++) |
| 224 | { |
| 225 | invsum += monster.Inventory(i); |
| 226 | } |
| 227 | Assert.AreEqual(10, invsum); |
| 228 | |
| 229 | // Get the inventory as an array and subtract the |
| 230 | // sum to get it back to 0 |
| 231 | var inventoryArray = monster.GetInventoryArray(); |
| 232 | Assert.AreEqual(5, inventoryArray.Length); |
| 233 | foreach(var inv in inventoryArray) |
| 234 | { |
| 235 | invsum -= inv; |
| 236 | } |
| 237 | Assert.AreEqual(0, invsum); |
| 238 | |
| 239 | var test0 = monster.Test4(0).Value; |
| 240 | var test1 = monster.Test4(1).Value; |
| 241 | Assert.AreEqual(2, monster.Test4Length); |
| 242 | |
| 243 | Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B); |
| 244 | |
| 245 | Assert.AreEqual(2, monster.TestarrayofstringLength); |
| 246 | Assert.AreEqual("test1", monster.Testarrayofstring(0)); |
| 247 | Assert.AreEqual("test2", monster.Testarrayofstring(1)); |
| 248 | |
| 249 | Assert.AreEqual(true, monster.Testbool); |
| 250 | |
| 251 | #if ENABLE_SPAN_T |
| 252 | var nameBytes = monster.GetNameBytes(); |
| 253 | Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.ToArray(), 0, nameBytes.Length)); |
| 254 | |
| 255 | if (0 == monster.TestarrayofboolsLength) |
| 256 | { |
| 257 | Assert.IsFalse(monster.GetTestarrayofboolsBytes().Length != 0); |
| 258 | } |
| 259 | else |
| 260 | { |
| 261 | Assert.IsTrue(monster.GetTestarrayofboolsBytes().Length != 0); |
| 262 | } |
| 263 | #else |
| 264 | var nameBytes = monster.GetNameBytes().Value; |
| 265 | Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count)); |
| 266 | |
| 267 | if (0 == monster.TestarrayofboolsLength) |
| 268 | { |
| 269 | Assert.IsFalse(monster.GetTestarrayofboolsBytes().HasValue); |
| 270 | } |
| 271 | else |
| 272 | { |
| 273 | Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue); |
| 274 | } |
| 275 | #endif |
| 276 | } |
| 277 | |
| 278 | [FlatBuffersTestMethod] |
| 279 | public void CanReadCppGeneratedWireFile() |
| 280 | { |
| 281 | var data = File.ReadAllBytes(@"Resources/monsterdata_test.mon"); |
| 282 | var bb = new ByteBuffer(data); |
| 283 | TestBuffer(bb); |
| 284 | } |
| 285 | |
| 286 | [FlatBuffersTestMethod] |
| 287 | public void TestEnums() |
| 288 | { |
| 289 | Assert.AreEqual("Red", Color.Red.ToString()); |
| 290 | Assert.AreEqual("Blue", Color.Blue.ToString()); |
| 291 | Assert.AreEqual("NONE", Any.NONE.ToString()); |
| 292 | Assert.AreEqual("Monster", Any.Monster.ToString()); |
| 293 | } |
| 294 | |
| 295 | [FlatBuffersTestMethod] |
| 296 | public void TestNestedFlatBuffer() |
| 297 | { |
| 298 | const string nestedMonsterName = "NestedMonsterName"; |
| 299 | const short nestedMonsterHp = 600; |
| 300 | const short nestedMonsterMana = 1024; |
| 301 | // Create nested buffer as a Monster type |
| 302 | var fbb1 = new FlatBufferBuilder(16); |
| 303 | var str1 = fbb1.CreateString(nestedMonsterName); |
| 304 | Monster.StartMonster(fbb1); |
| 305 | Monster.AddName(fbb1, str1); |
| 306 | Monster.AddHp(fbb1, nestedMonsterHp); |
| 307 | Monster.AddMana(fbb1, nestedMonsterMana); |
| 308 | var monster1 = Monster.EndMonster(fbb1); |
| 309 | Monster.FinishMonsterBuffer(fbb1, monster1); |
| 310 | var fbb1Bytes = fbb1.SizedByteArray(); |
| 311 | fbb1 = null; |
| 312 | |
| 313 | // Create a Monster which has the first buffer as a nested buffer |
| 314 | var fbb2 = new FlatBufferBuilder(16); |
| 315 | var str2 = fbb2.CreateString("My Monster"); |
| 316 | var nestedBuffer = Monster.CreateTestnestedflatbufferVector(fbb2, fbb1Bytes); |
| 317 | Monster.StartMonster(fbb2); |
| 318 | Monster.AddName(fbb2, str2); |
| 319 | Monster.AddHp(fbb2, 50); |
| 320 | Monster.AddMana(fbb2, 32); |
| 321 | Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer); |
| 322 | var monster = Monster.EndMonster(fbb2); |
| 323 | Monster.FinishMonsterBuffer(fbb2, monster); |
| 324 | |
| 325 | // Now test the data extracted from the nested buffer |
| 326 | var mons = Monster.GetRootAsMonster(fbb2.DataBuffer); |
| 327 | var nestedMonster = mons.GetTestnestedflatbufferAsMonster().Value; |
| 328 | |
| 329 | Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana); |
| 330 | Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp); |
| 331 | Assert.AreEqual(nestedMonsterName, nestedMonster.Name); |
| 332 | } |
| 333 | |
| 334 | [FlatBuffersTestMethod] |
| 335 | public void TestFixedLenghtArrays() |
| 336 | { |
| 337 | FlatBufferBuilder builder = new FlatBufferBuilder(100); |
| 338 | |
| 339 | float a; |
| 340 | int[] b = new int[15]; |
| 341 | sbyte c; |
| 342 | int[,] d_a = new int[2, 2]; |
| 343 | TestEnum[] d_b = new TestEnum[2]; |
| 344 | TestEnum[,] d_c = new TestEnum[2, 2]; |
| 345 | |
| 346 | a = 0.5f; |
| 347 | for (int i = 0; i < 15; i++) b[i] = i; |
| 348 | c = 1; |
| 349 | d_a[0, 0] = 1; |
| 350 | d_a[0, 1] = 2; |
| 351 | d_a[1, 0] = 3; |
| 352 | d_a[1, 1] = 4; |
| 353 | d_b[0] = TestEnum.B; |
| 354 | d_b[1] = TestEnum.C; |
| 355 | d_c[0, 0] = TestEnum.A; |
| 356 | d_c[0, 1] = TestEnum.B; |
| 357 | d_c[1, 0] = TestEnum.C; |
| 358 | d_c[1, 1] = TestEnum.B; |
| 359 | |
| 360 | Offset<ArrayStruct> arrayOffset = ArrayStruct.CreateArrayStruct( |
| 361 | builder, a, b, c, d_a, d_b, d_c); |
| 362 | |
| 363 | // Create a table with the ArrayStruct. |
| 364 | ArrayTable.StartArrayTable(builder); |
| 365 | ArrayTable.AddA(builder, arrayOffset); |
| 366 | Offset<ArrayTable> tableOffset = ArrayTable.EndArrayTable(builder); |
| 367 | |
| 368 | ArrayTable.FinishArrayTableBuffer(builder, tableOffset); |
| 369 | |
| 370 | ArrayTable table = ArrayTable.GetRootAsArrayTable(builder.DataBuffer); |
| 371 | |
| 372 | Assert.AreEqual(table.A?.A, 0.5f); |
| 373 | for (int i = 0; i < 15; i++) Assert.AreEqual(table.A?.B(i), i); |
| 374 | Assert.AreEqual(table.A?.C, (sbyte)1); |
| 375 | Assert.AreEqual(table.A?.D(0).A(0), 1); |
| 376 | Assert.AreEqual(table.A?.D(0).A(1), 2); |
| 377 | Assert.AreEqual(table.A?.D(1).A(0), 3); |
| 378 | Assert.AreEqual(table.A?.D(1).A(1), 4); |
| 379 | Assert.AreEqual(table.A?.D(0).B, TestEnum.B); |
| 380 | Assert.AreEqual(table.A?.D(1).B, TestEnum.C); |
| 381 | Assert.AreEqual(table.A?.D(0).C(0), TestEnum.A); |
| 382 | Assert.AreEqual(table.A?.D(0).C(1), TestEnum.B); |
| 383 | Assert.AreEqual(table.A?.D(1).C(0), TestEnum.C); |
| 384 | Assert.AreEqual(table.A?.D(1).C(1), TestEnum.B); |
| 385 | } |
| 386 | } |
| 387 | } |