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 { RunTests()26 public void RunTests() 27 { 28 CanCreateNewFlatBufferFromScratch(); 29 CanReadCppGeneratedWireFile(); 30 TestEnums(); 31 } 32 33 [FlatBuffersTestMethod] CanCreateNewFlatBufferFromScratch()34 public void CanCreateNewFlatBufferFromScratch() 35 { 36 CanCreateNewFlatBufferFromScratch(true); 37 CanCreateNewFlatBufferFromScratch(false); 38 } 39 CanCreateNewFlatBufferFromScratch(bool sizePrefix)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 TestBuffer(ByteBuffer bb)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] CanReadCppGeneratedWireFile()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] TestEnums()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] TestNestedFlatBuffer()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 } 335