aboutsummaryrefslogtreecommitdiff
path: root/flatcc/test/monster_test/monster_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'flatcc/test/monster_test/monster_test.c')
-rw-r--r--flatcc/test/monster_test/monster_test.c2919
1 files changed, 2919 insertions, 0 deletions
diff --git a/flatcc/test/monster_test/monster_test.c b/flatcc/test/monster_test/monster_test.c
new file mode 100644
index 0000000..f3150d8
--- /dev/null
+++ b/flatcc/test/monster_test/monster_test.c
@@ -0,0 +1,2919 @@
+#include <stdio.h>
+
+#include "monster_test_builder.h"
+#include "monster_test_verifier.h"
+
+#include "flatcc/support/hexdump.h"
+#include "flatcc/support/elapsed.h"
+#include "flatcc/portable/pparsefp.h"
+#include "../../config/config.h"
+
+/*
+ * Convenience macro to deal with long namespace names,
+ * and to make code reusable with other namespaces.
+ *
+ * Note: we could also use
+ *
+ * #define ns(x) MyGame_Example_ ## x
+ *
+ * but it wouldn't doesn't handled nested ns calls.
+ *
+ * For historic reason some of this test does not use the ns macro
+ * and some avoid nesting ns calls by placing parenthesis differently
+ * although this isn't required with this wrapper macro.
+ */
+#undef ns
+#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Example, x)
+
+#undef nsf
+#define nsf(x) FLATBUFFERS_WRAP_NAMESPACE(Fantasy, x)
+
+/*
+ * Wrap the common namespace (flatbuffers_). Many operations in the
+ * common namespace such as `flatbuffers_string_create` are also mapped
+ * to member fields such as `MyGame_Example_Monster_name_create` and
+ * this macro provides a consistent interface to namespaces with
+ * `nsc(string_create)` similar to `ns(Monster_name_create)`.
+ */
+#undef nsc
+#define nsc(x) FLATBUFFERS_WRAP_NAMESPACE(flatbuffers, x)
+
+/* A helper to simplify creating buffers vectors from C-arrays. */
+#define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
+
+static const char zero_pad[100];
+
+int verify_empty_monster(void *buffer)
+{
+ /* Proper id given. */
+ ns(Monster_table_t) monster = ns(Monster_as_root_with_identifier)(buffer, ns(Monster_file_identifier));
+ /* Invalid id. */
+ ns(Monster_table_t) monster2 = ns(Monster_as_root_with_identifier(buffer, "1234"));
+ /* `with_id` can also mean ignore id when given a null argument. */
+ ns(Monster_table_t) monster3 = ns(Monster_as_root_with_identifier(buffer, 0));
+ /* Excessive text in identifier is ignored. */
+ ns(Monster_table_t) monster4 = ns(Monster_as_root_with_identifier(buffer, "MONSX"));
+ /* Default id should match proper id. */
+ ns(Monster_table_t) monster5 = ns(Monster_as_root(buffer));
+
+ if (!monster) {
+ printf("Monster not available\n");
+ return -1;
+ }
+ if (monster2) {
+ printf("Monster should not accept invalid identifier\n");
+ return -1;
+ }
+ if (monster3 != monster) {
+ printf("Monster should ignore identifier when given a null id\n");
+ return -1;
+ }
+ if (monster4 != monster) {
+ printf("Monster should accept a string as valid identifier");
+ return -1;
+ }
+ if (monster5 != monster) {
+ printf("Monster with default id should be accepted");
+ return -1;
+ }
+ if (ns(Monster_hp(monster)) != 100) {
+ printf("Health points are not as expected\n");
+ return -1;
+ }
+ if (ns(Monster_hp_is_present(monster))) {
+ printf("Health Points should default\n");
+ return -1;
+ }
+ if (ns(Monster_pos_is_present(monster))) {
+ printf("Position should be present\n");
+ return -1;
+ }
+ if (ns(Monster_pos(monster)) != 0) {
+ printf("Position shouldn't be available\n");
+ return -1;
+ }
+ return 0;
+}
+
+int test_enums(flatcc_builder_t *B)
+{
+ (void)B;
+
+ if (ns(neg_enum_neg1) != -12) {
+ printf("neg_enum_neg1 should be -12, was %d\n", ns(neg_enum_neg1));
+ return -1;
+ }
+ if (ns(neg_enum_neg2) != -11) {
+ printf("neg_enum_neg1 should be -11, was %d\n", ns(neg_enum_neg2));
+ return -1;
+ }
+ if (ns(int_enum_int1) != 2) {
+ printf("int_enum_int1 should be 2\n");
+ return -1;
+ }
+ if (ns(int_enum_int2) != 42) {
+ printf("int_enum_int2 should be 42\n");
+ return -1;
+ }
+ if (ns(hex_enum_hexneg) != -2) {
+ printf("enum hexneg should be -2\n");
+ return -1;
+ }
+ if (ns(hex_enum_hex1) != 3) {
+ printf("hex_enum_hex1 should be 3\n");
+ return -1;
+ }
+ if (ns(hex_enum_hex2) != INT32_C(0x7eafbeaf)) {
+ printf("hex_enum_hex2 should be 0x7eafbeaf\n");
+ return -1;
+ }
+ return 0;
+}
+
+int test_type_aliases(flatcc_builder_t *B)
+{
+ int ret = 0;
+ void *buffer = 0;
+ size_t size;
+ ns(TypeAliases_table_t) ta;
+ flatbuffers_uint8_vec_ref_t v8_ref;
+ flatbuffers_double_vec_ref_t vf64_ref;
+
+ flatcc_builder_reset(B);
+
+ v8_ref = flatbuffers_uint8_vec_create(B, 0, 0);
+ vf64_ref = flatbuffers_double_vec_create(B, 0, 0);
+ ns(TypeAliases_create_as_root(B,
+ INT8_MIN, UINT8_MAX, INT16_MIN, UINT16_MAX,
+ INT32_MIN, UINT32_MAX, INT64_MIN, UINT64_MAX, 2.3f, 2.3, v8_ref, vf64_ref));
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ if ((ret = ns(TypeAliases_verify_as_root(buffer, size)))) {
+
+ hexdump("TypeAliases buffer", buffer, size, stderr);
+ printf("could not verify TypeAliases table, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+ ta = ns(TypeAliases_as_root(buffer));
+
+ if (ns(TypeAliases_i8(ta)) != INT8_MIN) goto failed;
+ if (ns(TypeAliases_i16(ta)) != INT16_MIN) goto failed;
+ if (ns(TypeAliases_i32(ta)) != INT32_MIN) goto failed;
+ if (ns(TypeAliases_i64(ta)) != INT64_MIN) goto failed;
+ if (ns(TypeAliases_u8(ta)) != UINT8_MAX) goto failed;
+ if (ns(TypeAliases_u16(ta)) != UINT16_MAX) goto failed;
+ if (ns(TypeAliases_u32(ta)) != UINT32_MAX) goto failed;
+ if (ns(TypeAliases_u64(ta)) != UINT64_MAX) goto failed;
+ if (!parse_float_is_equal(ns(TypeAliases_f32(ta)), 2.3f)) goto failed;
+ if (!parse_double_is_equal(ns(TypeAliases_f64(ta)), 2.3)) goto failed;
+ if (sizeof(ns(TypeAliases_i8(ta))) != 1) goto failed;
+ if (sizeof(ns(TypeAliases_i16(ta))) != 2) goto failed;
+ if (sizeof(ns(TypeAliases_i32(ta))) != 4) goto failed;
+ if (sizeof(ns(TypeAliases_i64(ta))) != 8) goto failed;
+ if (sizeof(ns(TypeAliases_u8(ta))) != 1) goto failed;
+ if (sizeof(ns(TypeAliases_u16(ta))) != 2) goto failed;
+ if (sizeof(ns(TypeAliases_u32(ta))) != 4) goto failed;
+ if (sizeof(ns(TypeAliases_u64(ta))) != 8) goto failed;
+ if (sizeof(ns(TypeAliases_f32(ta))) != 4) goto failed;
+ if (sizeof(ns(TypeAliases_f64(ta))) != 8) goto failed;
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+
+failed:
+ ret = -1;
+ printf("Scalar type alias has unexpected value or size\n");
+ goto done;
+}
+
+int test_empty_monster(flatcc_builder_t *B)
+{
+ int ret;
+ ns(Monster_ref_t) root;
+ void *buffer;
+ size_t size;
+
+ flatcc_builder_reset(B);
+
+ flatbuffers_buffer_start(B, ns(Monster_file_identifier));
+ ns(Monster_start(B));
+ /* Cannot make monster empty as name is required. */
+ ns(Monster_name_create_str(B, "MyMonster"));
+ root = ns(Monster_end(B));
+ flatbuffers_buffer_end(B, root);
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ hexdump("empty monster table", buffer, size, stderr);
+ if ((ret = verify_empty_monster(buffer))) {
+ goto done;
+ }
+
+ if ((ret = ns(Monster_verify_as_root_with_identifier(buffer, size, ns(Monster_file_identifier))))) {
+ printf("could not verify empty monster, got %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+
+ /*
+ * Note: this will assert if the verifier is set to assert during
+ * debugging. Also not that a buffer size - 1 is not necessarily
+ * invalid, but because we pack vtables tight at the end, we expect
+ * failure in this case.
+ */
+ if (flatcc_verify_ok == ns(Monster_verify_as_root(
+ buffer, size - 1))) {
+ printf("Monster verify failed to detect short buffer\n");
+ return -1;
+ }
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_typed_empty_monster(flatcc_builder_t *B)
+{
+ int ret = -1;
+ ns(Monster_ref_t) root;
+ void *buffer;
+ size_t size;
+ flatbuffers_fid_t fid = { 0 };
+
+ flatcc_builder_reset(B);
+
+ flatbuffers_buffer_start(B, ns(Monster_type_identifier));
+ ns(Monster_start(B));
+ /* Cannot make monster empty as name is required. */
+ ns(Monster_name_create_str(B, "MyMonster"));
+ root = ns(Monster_end(B));
+ flatbuffers_buffer_end(B, root);
+
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ hexdump("empty typed monster table", buffer, size, stderr);
+
+ if (flatbuffers_get_type_hash(buffer) != flatbuffers_type_hash_from_name("MyGame.Example.Monster")) {
+
+ printf("Monster does not have the expected type, got %lx\n", (unsigned long)flatbuffers_get_type_hash(buffer));
+ goto done;
+ }
+
+ if (!flatbuffers_has_type_hash(buffer, ns(Monster_type_hash))) {
+ printf("Monster does not have the expected type\n");
+ goto done;
+ }
+ if (!flatbuffers_has_type_hash(buffer, 0x330ef481)) {
+ printf("Monster does not have the expected type\n");
+ goto done;
+ }
+
+ if (!verify_empty_monster(buffer)) {
+ printf("typed empty monster should not verify with default identifier\n");
+ goto done;
+ }
+
+ if ((ret = ns(Monster_verify_as_root_with_identifier(buffer, size, ns(Monster_type_identifier))))) {
+ printf("could not verify typed empty monster, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ if ((ret = ns(Monster_verify_as_typed_root(buffer, size)))) {
+ printf("could not verify typed empty monster, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ if ((ret = ns(Monster_verify_as_root_with_type_hash(buffer, size, ns(Monster_type_hash))))) {
+ printf("could not verify empty monster with type hash, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ if ((ret = ns(Monster_verify_as_root_with_type_hash(buffer, size, flatbuffers_type_hash_from_name("MyGame.Example.Monster"))))) {
+ printf("could not verify empty monster with explicit type hash, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ flatbuffers_identifier_from_type_hash(0x330ef481, fid);
+ if ((ret = ns(Monster_verify_as_root_with_identifier(buffer, size, fid)))) {
+ printf("could not verify typed empty monster, got %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ if (!ns(Monster_verify_as_root(buffer, size))) {
+ printf("should not have verified with the original identifier since we use types\n");
+ goto done;
+ }
+ ret = 0;
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int verify_monster(void *buffer)
+{
+ ns(Monster_table_t) monster, mon, mon2;
+ ns(Monster_vec_t) monsters;
+ ns(Any_union_type_t) test_type;
+ ns(Any_union_t) test_union;
+ /* This is an encoded struct pointer. */
+ ns(Vec3_struct_t) vec;
+ const char *name;
+ /* This is a more precise type as there is a length field prefix. */
+ nsc(string_t) name2;
+ /* This is a native struct type. */
+ ns(Vec3_t) v;
+ ns(Test_vec_t) testvec;
+ ns(Test_t) testvec_data[] = {
+ {0x10, 0x20}, {0x30, 0x40}, {0x50, 0x60}, {0x70, (int8_t)0x80}, {0x191, (int8_t)0x91}
+ };
+ ns(Test_struct_t) test;
+ nsc(string_vec_t) strings;
+ nsc(string_t) s;
+ nsc(bool_vec_t) bools;
+ ns(Stat_table_t) stat;
+ int booldata[] = { 0, 1, 1, 0 };
+ const uint8_t *inv;
+ size_t i;
+
+ if (!nsc(has_identifier(buffer, 0))) {
+ printf("wrong monster identifier (when ignoring)\n");
+ return -1;
+ }
+ if (!nsc(has_identifier(buffer, "MONS"))) {
+ printf("wrong monster identifier (when explicit)\n");
+ return -1;
+ }
+ if (!nsc(has_identifier(buffer, "MONSTER"))) {
+ printf("extra characters in identifier should be ignored\n");
+ return -1;
+ }
+ if (nsc(has_identifier(buffer, "MON1"))) {
+ printf("accepted wrong monster identifier (when explicit)\n");
+ return -1;
+ }
+ if (!nsc(has_identifier(buffer, ns(Monster_file_identifier)))) {
+ printf("wrong monster identifier (via defined identifier)\n");
+ return -1;
+ }
+
+ if (!(monster = ns(Monster_as_root(buffer)))) {
+ printf("Monster not available\n");
+ return -1;
+ }
+ if (ns(Monster_hp(monster)) != 80) {
+ printf("Health points are not as expected\n");
+ return -1;
+ }
+ if (!(vec = ns(Monster_pos(monster)))) {
+ printf("Position is absent\n");
+ return -1;
+ }
+ if ((size_t)vec & 15) {
+ printf("Force align of Vec3 struct not correct\n");
+ }
+ /* -3.2f is actually -3.20000005 and not -3.2 due to representation loss.
+ * For 32-bit GCC compilers, -3.2f might be another value, so use lower
+ * precision portable comparison. */
+ if (!parse_float_is_equal(ns(Vec3_z(vec)), -3.2f)) {
+ printf("Position failing on z coordinate\n");
+ return -1;
+ }
+ if (nsc(is_native_pe())) {
+ if (!parse_float_is_equal(vec->x, 1.0f) ||
+ !parse_float_is_equal(vec->y, 2.0f) ||
+ !parse_float_is_equal(vec->z, -3.2f)) {
+ printf("Position is incorrect\n");
+ return -1;
+ }
+ }
+ /*
+ * NOTE: copy_from_pe and friends are provided in the builder
+ * interface, not the read only interface, but for advanced uses
+ * these may also be used for read operations.
+ * Also note that if we want the target struct fully null padded
+ * the struct must be zeroed first. The _clear operation is one way
+ * to achieve this - but it is not required for normal read access.
+ * See common_builder for more details. These operations can
+ * actually be very useful in their own right, disregarding any
+ * other flatbuffer logic when dealing with struct endian
+ * conversions in other protocols.
+ */
+ ns(Vec3_clear(&v)); /* Not strictly needed here. */
+ ns(Vec3_copy_from_pe(&v, vec));
+ if (!parse_float_is_equal(v.x, 1.0f) ||
+ !parse_float_is_equal(v.y, 2.0f) ||
+ !parse_float_is_equal(v.z, -3.2f)) {
+ printf("Position is incorrect after copy\n");
+ return -1;
+ }
+ if (vec->test1 != 0 || vec->test1 != 0 ||
+ memcmp(&vec->test3, zero_pad, sizeof(vec->test3)) != 0) {
+ printf("Zero default not correct for struct\n");
+ return -1;
+ }
+ name = ns(Monster_name(monster));
+ if (!name || strcmp(name, "MyMonster")) {
+ printf("Name is not correct\n");
+ return -1;
+ }
+ name2 = ns(Monster_name(monster));
+ if (nsc(string_len(name)) != 9 || nsc(string_len(name2)) != 9) {
+ printf("Name length is not correct\n");
+ return -1;
+ }
+ if (ns(Monster_color(monster)) != ns(Color_Green)) {
+ printf("Monster isn't a green monster\n");
+ return -1;
+ }
+ if (strcmp(ns(Color_name)(ns(Color_Green)), "Green")) {
+ printf("Enum name map does not have a green solution\n");
+ return -1;
+ }
+ /*
+ * This is bit tricky because Color is a bit flag, so we can have
+ * combinations that are expected, but that we do not know. The
+ * known value logic does not accomodate for that.
+ */
+ if (!ns(Color_is_known_value(ns(Color_Green)))) {
+ printf("Color enum does not recognize the value of the Green flag\n");
+ return -1;
+ }
+ if (!ns(Color_is_known_value(1))) {
+ printf("Color enum does not recognize the value of the Red flag\n");
+ return -1;
+ }
+ if (ns(Color_is_known_value(4))) {
+ printf("Color enum recognizes a value it shouldn't\n");
+ return -1;
+ }
+ if (!ns(Color_is_known_value(8))) {
+ printf("Color enum does not recognize the value of the Blue flag\n");
+ return -1;
+ }
+ if (ns(Color_is_known_value(9))) {
+ printf("Color enum recognizes a value it shouldn't\n");
+ return -1;
+ }
+ if (!ns(Any_is_known_type(ns(Any_Monster)))) {
+ printf("Any type does not accept Monster\n");
+ return -1;
+ }
+ if (ns(Any_is_known_type(42))) {
+ printf("Any type recognizes unexpected type\n");
+ return -1;
+ }
+ inv = ns(Monster_inventory(monster));
+ if ((nsc(uint8_vec_len(inv))) != 10) {
+ printf("Inventory length unexpected\n");
+ return -1;
+ }
+ for (i = 0; i < nsc(uint8_vec_len(inv)); ++i) {
+ if (nsc(uint8_vec_at(inv, i)) != i) {
+ printf("inventory item #%d is wrong\n", (int)i);
+ return -1;
+ }
+ }
+ if (ns(Monster_mana(monster) != 150)) {
+ printf("Mana not default\n");
+ return -1;
+ }
+ if (ns(Monster_mana_is_present(monster))) {
+ printf("Mana should default\n");
+ return -1;
+ }
+ if (!ns(Monster_hp_is_present(monster))) {
+ printf("Health points should be present\n");
+ return -1;
+ }
+ if (!ns(Monster_pos_is_present(monster))) {
+ printf("Position should be present\n");
+ return -1;
+ }
+ testvec = ns(Monster_test4(monster));
+ if (ns(Test_vec_len(testvec)) != 5) {
+ printf("Test4 vector is not the right length.\n");
+ return -1;
+ }
+ /*
+ * This particular test requires that the in-memory
+ * array layout matches the array layout in the buffer.
+ */
+ if (flatbuffers_is_native_pe()) {
+ for (i = 0; i < 5; ++i) {
+ test = ns(Test_vec_at(testvec, i));
+ if (testvec_data[i].a != ns(Test_a(test))) {
+ printf("Test4 vec failed at index %d, member a\n", (int)i);
+ return -1;
+ }
+ if (testvec_data[i].b != ns(Test_b(test))) {
+ printf("Test4 vec failed at index %d, member a\n", (int)i);
+ return -1;
+ }
+ }
+ } else {
+ printf("SKIPPING DIRECT VECTOR ACCESS WITH NON-NATIVE ENDIAN PROTOCOL\n");
+ }
+ monsters = ns(Monster_testarrayoftables(monster));
+ if (ns(Monster_vec_len(monsters)) != 8) {
+ printf("unexpected monster vector length\n");
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 5));
+ assert(mon);
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "TwoFace")) {
+ printf("monster 5 isn't TwoFace");
+ return -1;
+ }
+ mon2 = ns(Monster_vec_at(monsters, 1));
+ if (mon2 != mon) {
+ printf("DAG test failed, monster[5] != monster[1] as pointer\n");
+ return -1;
+ }
+ name = ns(Monster_name(mon2));
+ if (strcmp(name, "TwoFace")) {
+ printf("monster 1 isn't Joker, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 2));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "Joker")) {
+ printf("monster 2 isn't Joker, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 0));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "Gulliver")) {
+ printf("monster 0 isn't Gulliver, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 3));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "TwoFace")) {
+ printf("monster 3 isn't TwoFace, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 4));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "Joker")) {
+ printf("monster 4 isn't Joker, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 6));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "Gulliver")) {
+ printf("monster 6 isn't Gulliver, it is: %s\n", name);
+ return -1;
+ }
+ mon = ns(Monster_vec_at(monsters, 7));
+ name = ns(Monster_name(mon));
+ if (strcmp(name, "Joker")) {
+ printf("monster 7 isn't Gulliver, it is: %s\n", name);
+ return -1;
+ }
+ strings = ns(Monster_testarrayofstring(monster));
+ if (nsc(string_vec_len(strings) != 3)) {
+ printf("Monster array of strings has wrong length\n");
+ return -1;
+ }
+ if (strcmp(nsc(string_vec_at(strings, 0)), "Hello")) {
+ printf("string elem 0 is wrong\n");
+ return -1;
+ }
+ s = nsc(string_vec_at(strings, 1));
+ if (nsc(string_len(s)) != 2) {
+ printf("string 1 has wrong length");
+ return -1;
+ }
+ if (memcmp(s, ",\0", 2)) {
+ printf("string elem 1 has wrong content\n");
+ return -1;
+ }
+ if (strcmp(nsc(string_vec_at(strings, 2)), "world!")) {
+ printf("string elem 2 is wrong\n");
+ return -1;
+ }
+ if (!ns(Monster_testarrayofbools_is_present(monster))) {
+ printf("array of bools is missing\n");
+ return -1;
+ }
+ bools = ns(Monster_testarrayofbools(monster));
+ if (nsc(bool_vec_len(bools) != 4)) {
+ printf("bools have wrong vector length\n");
+ return -1;
+ }
+ if (sizeof(bools[0]) != 1) {
+ printf("bools have wrong element size\n");
+ return -1;
+ }
+ for (i = 0; i < 4; ++i) {
+ if (nsc(bool_vec_at(bools, i) != booldata[i])) {
+ printf("bools vector elem %d is wrong\n", (int)i);
+ return -1;
+ }
+ }
+ test_type = ns(Monster_test_type(monster));
+ if (test_type != ns(Any_Monster)) {
+ printf("the monster test type is not Any_Monster\n");
+ return -1;
+ }
+ mon = ns(Monster_test(monster));
+ if (strcmp(ns(Monster_name(mon)), "TwoFace")) {
+ printf("the test monster is not TwoFace\n");
+ return -1;
+ }
+ mon = ns(Monster_enemy(monster));
+ if (strcmp(ns(Monster_name(mon)), "the enemy")) {
+ printf("the monster is not the enemy\n");
+ return -1;
+ }
+ if (ns(Monster_test_type(mon)) != ns(Any_NONE)) {
+ printf("the enemy test type is not Any_NONE\n");
+ return -1;
+ }
+ test_union = ns(Monster_test_union(monster));
+ if (test_union.type != test_type) {
+ printf("the monster test union type is not Any_Monster\n");
+ return -1;
+ }
+ if (test_union.value != ns(Monster_test(monster))) {
+ printf("the union monster has gone awol\n");
+ return -1;
+ }
+ monsters = ns(Monster_testarrayoftables(mon));
+ i = ns(Monster_vec_len(monsters));
+ mon = ns(Monster_vec_at(monsters, i - 1));
+ if (ns(Monster_test_type)(mon) != ns(Any_Monster)) {
+ printf("The monster variant added with value, type methods is not working\n");
+ return -1;
+ }
+ mon = ns(Monster_test(mon));
+ if (strcmp(ns(Monster_name(mon)), "TwoFace")) {
+ printf("The monster variant added with value method is incorrect\n");
+ return -1;
+ }
+ if (ns(Monster_testbool(monster))) {
+ printf("testbool should not\n");
+ return -1;
+ }
+ if (!ns(Monster_testempty_is_present(monster))) {
+ printf("The empty table isn't present\n");
+ return -1;
+ }
+ stat = ns(Monster_testempty(monster));
+ if (ns(Stat_id_is_present(stat))
+ || ns(Stat_val_is_present(stat))
+ || ns(Stat_count_is_present(stat))) {
+ printf("empty table isn't empty\n");
+ return -1;
+ }
+ return 0;
+}
+
+int gen_monster(flatcc_builder_t *B, int with_size)
+{
+ uint8_t inv[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ ns(Vec3_t) *vec;
+ ns(Test_t) *test, x;
+ ns(Monster_ref_t) mon, mon2, monsters[2];
+ ns(Monster_ref_t) *aoft;
+ nsc(string_ref_t) name;
+ nsc(string_ref_t) strings[3];
+ nsc(bool_t)bools[] = { 0, 1, 1, 0 };
+ flatcc_builder_reset(B);
+
+
+
+ /*
+ * Some FlatBuffer language interfaces require a string and other
+ * non-embeddable objects to be created before the table storing it
+ * is being created. This is not necessary (but possible) here
+ * because the flatcc_builder maintains an internal stack.
+ */
+ if (with_size) {
+ ns(Monster_start_as_root_with_size(B));
+ } else {
+ ns(Monster_start_as_root(B));
+ }
+
+ ns(Monster_hp_add(B, 80));
+ vec = ns(Monster_pos_start(B));
+ vec->x = 1, vec->y = 2, vec->z = -3.2f;
+ /* _end call converts to protocol endian format. */
+ ns(Monster_pos_end(B));
+ /*
+ * NOTE: Monster_name_add requires a reference to an
+ * already created string - adding a string directly
+ * will compile with a warning but fail badly. Instead
+ * create the string first, or do it in-place with
+ * the helper function `Monster_name_create_str`, or
+ * with one of several other options.
+ *
+ * Wrong: ns(Monster_name_add(B, "MyMonster"));
+ */
+ ns(Monster_name_create_str(B, "MyMonster"));
+
+ ns(Monster_color_add)(B, ns(Color_Green));
+
+ ns(Monster_inventory_create(B, inv, c_vec_len(inv)));
+
+ /* The vector is built in native endian format. */
+ ns(Monster_test4_start(B));
+ test = ns(Monster_test4_extend(B, 1));
+ test->a = 0x10;
+ test->b = 0x20;
+ test = ns(Monster_test4_extend(B, 2));
+ test->a = 0x30;
+ test->b = 0x40;
+ test[1].a = 0x50;
+ test[1].b = 0x60;
+ ns(Monster_test4_push_create(B, 0x70, (int8_t)0x80));
+ /*
+ * Zero padding within struct
+ * - not needed when receiving a pointer like `test` in the above.
+ */
+ ns(Test_clear(&x));
+ x.a = 0x190; /* This is a short. */
+ x.b = (int8_t)0x91; /* This is a byte. */
+ /* And x also has a hidden trailing padding byte. */
+ ns(Monster_test4_push(B, &x));
+ ns(Monster_test4_push(B, &x));
+ /* We can use either field mapped push or push on the type. */
+ ns(Test_vec_push(B, &x));
+ /*
+ * `_reserved_len` is similar to the `_vec_len` function in the
+ * reader interface but `_vec_len` would not work here.
+ */
+ assert(ns(Monster_test4_reserved_len(B)) == 7);
+ ns(Monster_test4_truncate(B, 2));
+ assert(ns(Monster_test4_reserved_len(B)) == 5);
+
+ /* It is not valid to dereference old pointers unless we call edit first. */
+ test = ns(Monster_test4_edit(B));
+ test[4].a += 1; /* 0x191 */
+
+ /* Each vector element is converted to protocol endian format at end. */
+ ns(Monster_test4_end(B));
+
+ /* Test creating object before containing vector. */
+ ns(Monster_start(B));
+ name = nsc(string_create(B, "TwoFace", 7));
+ ns(Monster_name_add(B, name));
+ mon = ns(Monster_end(B));
+ /*
+ * Here we create several monsters with only a name - this also
+ * tests reuse of vtables.
+ */
+ ns(Monster_testarrayoftables_start(B));
+ aoft = ns(Monster_testarrayoftables_extend(B, 2));
+ /*
+ * It is usually not ideal to update reference vectors directly and
+ * there must not be any unassigned elements (null) when the array
+ * ends. Normally a push_start ... push_end, or a push_create
+ * operation is preferable.
+ */
+ aoft[0] = mon;
+ /*
+ * But we can do things not otherwise possible - like constructing a
+ * DAG. Note that reference values (unlike pointers) are stable as
+ * long as the buffer is open for write, also past this vector.
+ */
+ aoft[1] = mon;
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_strn(B, "Joker", 30));
+ mon2 = *ns(Monster_testarrayoftables_push_end(B));
+ aoft = ns(Monster_testarrayoftables_extend(B, 3));
+ aoft[0] = mon;
+ aoft[1] = mon2;
+ ns(Monster_testarrayoftables_truncate(B, 1));
+ assert(ns(Monster_testarrayoftables_reserved_len(B)) == 5);
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_strn(B, "Gulliver at the Big Endians", 8));
+ /* We cannot call reserved_len while a monster is still open, */
+ monsters[0] = *ns(Monster_testarrayoftables_push_end(B));
+ /* but here the vector is on top of the stack again. */
+ assert(ns(Monster_testarrayoftables_reserved_len(B)) == 6);
+ /* Swap monsters[0] and monsters[5] */
+ aoft = ns(Monster_testarrayoftables_edit(B));
+ mon2 = aoft[5];
+ monsters[1] = aoft[2];
+ aoft[5] = mon;
+ aoft[0] = mon2;
+ ns(Monster_testarrayoftables_append(B, monsters, 2));
+ /*
+ * The end call converts the reference array into an endian encoded
+ * offset vector.
+ */
+ ns(Monster_testarrayoftables_end(B));
+
+ strings[0] = nsc(string_create_str(B, "Hello"));
+ /* Test embedded null character.
+ * Note _strn is at most n, or up to 0 termination:
+ * wrong: strings[1] = nsc(string_create_strn(B, ",\0", 2));
+ */
+ strings[1] = nsc(string_create(B, ",\0", 2));
+ strings[2] = nsc(string_create_str(B, "world!"));
+ ns(Monster_testarrayofstring_create(B, strings, 3));
+
+ assert(c_vec_len(bools) == 4);
+ ns(Monster_testarrayofbools_start(B));
+ ns(Monster_testarrayofbools_append(B, bools, 1));
+ ns(Monster_testarrayofbools_append(B, bools + 1, 3));
+ ns(Monster_testarrayofbools_end(B));
+
+ /*
+ * This is using a constructor argument list where a union
+ * is a single argument, unlike the C++ interface.
+ * A union is given a type and a table reference.
+ *
+ * We are not verifying the result as this is only to stress
+ * the type system of the builder - except: the last array
+ * element is tested to ensure add_value is getting through.
+ */
+ ns(Monster_test_add)(B, ns(Any_as_Monster(mon)));
+
+ ns(Monster_enemy_start(B));
+ ns(Monster_name_create_str(B, "the enemy"));
+
+ /* Create array of monsters to test various union constructors. */
+ ns(Monster_testarrayoftables_start(B));
+
+ ns(Monster_vec_push_start(B));
+ ns(Monster_test_add)(B, ns(Any_as_Monster(mon)));
+ /* Name is required. */
+ ns(Monster_name_create_str(B, "any name"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_test_Monster_add(B, mon));
+ ns(Monster_name_create_str(B, "any name"));
+ ns(Monster_vec_push_end(B));
+ /*
+ * `push_start`: We can use the field specific method, or the type specific method
+ * that the field maps to.
+ */
+ ns(Monster_testarrayoftables_push_start(B));
+ /*
+ * This is mostly for internal use in create methods so the type
+ * can be added last and pack better in the table.
+ * `add_value` still takes union_ref because it is a NOP if
+ * the union type is NONE.
+ */
+ ns(Monster_test_add_value(B, ns(Any_as_Monster(mon))));
+ ns(Monster_name_create_str(B, "any name"));
+ ns(Monster_test_add_type(B, ns(Any_Monster)));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_end(B));
+
+ ns(Monster_enemy_end(B));
+
+ ns(Monster_testbool_add(B, 0));
+
+ ns(Monster_testempty_start(B));
+ ns(Monster_testempty_end(B));
+
+ ns(Monster_end_as_root(B));
+ return 0;
+}
+
+int test_monster(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ int ret;
+
+ gen_monster(B, 0);
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ hexdump("monster table", buffer, size, stderr);
+ if ((ret = ns(Monster_verify_as_root(buffer, size)))) {
+ printf("Monster buffer failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+ ret = verify_monster(buffer);
+
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_monster_with_size(flatcc_builder_t *B)
+{
+ void *buffer, *frame;
+ size_t size, size2, esize;
+ int ret;
+
+ gen_monster(B, 1);
+
+ frame = flatcc_builder_finalize_aligned_buffer(B, &size);
+ hexdump("monster table with size", frame, size, stderr);
+ if (((size_t)frame & 15)) {
+ printf("Platform did not provide 16 byte aligned allocation and needs special attention.");
+ printf("buffer address: %x\n", (flatbuffers_uoffset_t)(size_t)frame);
+ return -1;
+ }
+
+ buffer = flatbuffers_read_size_prefix(frame, &size2);
+ esize = size - sizeof(flatbuffers_uoffset_t);
+ if (size2 != esize) {
+ printf("Size prefix has unexpected size, got %i, expected %i\n", (int)size2, (int)esize);
+ return -1;
+ }
+ if ((ret = ns(Monster_verify_as_root(buffer, size2)))) {
+ printf("Monster buffer with size prefix failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+ ret = verify_monster(buffer);
+
+ flatcc_builder_aligned_free(frame);
+ return ret;
+}
+
+int test_cloned_monster(flatcc_builder_t *B)
+{
+ void *buffer;
+ void *cloned_buffer;
+ size_t size;
+ int ret;
+ flatcc_refmap_t refmap, *refmap_old;
+
+ flatcc_refmap_init(&refmap);
+ gen_monster(B, 0);
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ hexdump("monster table", buffer, size, stderr);
+ if ((ret = ns(Monster_verify_as_root(buffer, size)))) {
+ printf("Monster buffer failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+ if (verify_monster(buffer)) {
+ return -1;
+ }
+ flatcc_builder_reset(B);
+
+ /*
+ * Clone works without setting a refmap - but then shared references
+ * get expanded - and then the verify monster check fails on a DAG
+ * test.
+ */
+ refmap_old = flatcc_builder_set_refmap(B, &refmap);
+ if (!ns(Monster_clone_as_root(B, ns(Monster_as_root(buffer))))) {
+ printf("Cloned Monster didn't actually clone.");
+ return -1;
+ };
+ /*
+ * Restoring old refmap (or zeroing) is optional if we cleared the
+ * buffer in this scope, but we don't so we must detach and clean up
+ * the refmap manually. refmap_old is likely just null, but this
+ * way we do not interfere with caller.
+ */
+ flatcc_builder_set_refmap(B, refmap_old);
+ cloned_buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ hexdump("cloned monster table", cloned_buffer, size, stderr);
+ if ((ret = ns(Monster_verify_as_root(cloned_buffer, size)))) {
+ printf("Cloned Monster buffer failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+ if (verify_monster(cloned_buffer)) {
+ printf("Cloned Monster did not have the expected content.");
+ return -1;
+ }
+
+ flatcc_refmap_clear(&refmap);
+ flatcc_builder_aligned_free(buffer);
+ flatcc_builder_aligned_free(cloned_buffer);
+ return ret;
+}
+
+int test_string(flatcc_builder_t *B)
+{
+ ns(Monster_table_t) mon;
+ void *buffer;
+ char *s;
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_start(B));
+ s = ns(Monster_name_extend(B, 3));
+ s[0] = '1';
+ s[1] = '2';
+ s[2] = '3';
+ ns(Monster_name_append_str(B, "4"));
+ assert(ns(Monster_name_reserved_len(B)) == 4);
+ ns(Monster_name_append_strn(B, "5678", 30));
+ assert(ns(Monster_name_reserved_len(B)) == 8);
+ ns(Monster_name_append(B, "90", 2));
+ assert(ns(Monster_name_reserved_len(B)) == 10);
+ ns(Monster_name_truncate(B, 3));
+ assert(ns(Monster_name_reserved_len(B)) == 7);
+ s = ns(Monster_name_edit(B));
+ s[4] = '.';
+ ns(Monster_name_end(B));
+ ns(Monster_end_as_root(B));
+ /* Only with small buffers and the default emitter. */
+ buffer = flatcc_builder_get_direct_buffer(B, 0);
+ assert(buffer);
+ mon = ns(Monster_as_root(buffer));
+ if (strcmp(ns(Monster_name(mon)), "1234.67")) {
+ printf("string test failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+int test_sort_find(flatcc_builder_t *B)
+{
+ size_t pos;
+ ns(Monster_table_t) mon;
+ ns(Monster_vec_t) monsters;
+ ns(Monster_mutable_vec_t) mutable_monsters;
+ void *buffer;
+ size_t size;
+ int ret = -1;
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+
+ ns(Monster_testarrayoftables_start(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "TwoFace"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Joker"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Gulliver"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Alice"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Gulliver"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_end(B));
+
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ hexdump("unsorted monster buffer", buffer, size, stderr);
+ mon = ns(Monster_as_root(buffer));
+ monsters = ns(Monster_testarrayoftables(mon));
+ assert(monsters);
+ mutable_monsters = (ns(Monster_mutable_vec_t))monsters;
+ ns(Monster_vec_sort_by_name(mutable_monsters));
+
+ hexdump("sorted monster buffer", buffer, size, stderr);
+
+ if (ns(Monster_vec_len(monsters)) != 5) {
+ printf("Sorted monster vector has wrong length\n");
+ goto done;
+ }
+ if (strcmp(ns(Monster_name(ns(Monster_vec_at(monsters, 0)))), "Alice")) {
+ printf("sort isn't working at elem 0\n");
+ goto done;
+ }
+ if (strcmp(ns(Monster_name(ns(Monster_vec_at(monsters, 1)))), "Gulliver")) {
+ printf("sort isn't working at elem 1\n");
+ goto done;
+ }
+ if (strcmp(ns(Monster_name(ns(Monster_vec_at(monsters, 2)))), "Gulliver")) {
+ printf("sort isn't working at elem 2\n");
+ goto done;
+ }
+ if (strcmp(ns(Monster_name(ns(Monster_vec_at(monsters, 3)))), "Joker")) {
+ printf("sort isn't working at elem 3\n");
+ goto done;
+ }
+ if (strcmp(ns(Monster_name(ns(Monster_vec_at(monsters, 4)))), "TwoFace")) {
+ printf("sort isn't working at elem 4\n");
+ goto done;
+ }
+ /*
+ * The heap sort isn't stable, but it should keep all elements
+ * unique. Note that we could still have identical objects if we
+ * actually stored the same object twice in DAG structure.
+ */
+ if (ns(Monster_vec_at(monsters, 1)) == ns(Monster_vec_at(monsters, 2))) {
+ printf("Two identical sort keys should not be identical objects (in this case)\n");
+ goto done;
+ }
+
+ if (3 != ns(Monster_vec_find(monsters, "Joker"))) {
+ printf("find by default key did not find the Joker\n");
+ goto done;
+ }
+ if (3 != ns(Monster_vec_find_n(monsters, "Joker2", 5))) {
+ printf("find by default key did not find the Joker with n\n");
+ goto done;
+ }
+ /*
+ * We can have multiple keys on a table or struct by naming the sort
+ * and find operations.
+ */
+ if (3 != ns(Monster_vec_find_by_name(monsters, "Joker"))) {
+ printf("find did not find the Joker\n");
+ goto done;
+ }
+ if (3 != ns(Monster_vec_find_n_by_name(monsters, "Joker3", 5))) {
+ printf("find did not find the Joker with n\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_find_by_name(monsters, "Jingle"))) {
+ printf("not found not working\n");
+ goto done;
+ }
+ if (0 != ns(Monster_vec_find_by_name(monsters, "Alice"))) {
+ printf("Alice not found\n");
+ goto done;
+ }
+ /*
+ * The search, unlike sort, is stable and should return the first
+ * index of repeated keys.
+ */
+ if (1 != (pos = ns(Monster_vec_find_by_name(monsters, "Gulliver")))) {
+ printf("Gulliver not found\n");
+ printf("got %d\n", (int)pos);
+ goto done;
+ }
+ if (4 != (pos = ns(Monster_vec_find_by_name(monsters, "TwoFace")))) {
+ printf("TwoFace not found\n");
+ printf("got %d\n", (int)pos);
+ goto done;
+ }
+
+ /*
+ * Just make sure the default key has a sort method - it is the same
+ * as sort_by_name for the monster schema.
+ */
+ ns(Monster_vec_sort(mutable_monsters));
+ ret = 0;
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+static size_t count_monsters(ns(Monster_vec_t) monsters, const char *name)
+{
+ size_t i;
+ size_t count = 0;
+
+ for (i = ns(Monster_vec_scan)(monsters, name);
+ i != nsc(not_found);
+ i = ns(Monster_vec_scan_ex)(monsters, i + 1, nsc(end), name)) {
+ ++count;
+ }
+
+ return count;
+}
+
+int test_scan(flatcc_builder_t *B)
+{
+ size_t pos;
+ ns(Monster_table_t) mon;
+ ns(Monster_vec_t) monsters;
+ nsc(uint8_vec_t) inv;
+ nsc(string_vec_t) strings;
+ void *buffer;
+ size_t size;
+ uint8_t invdata[] = { 6, 7, 1, 3, 4, 3, 2 };
+ int ret = -1;
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_inventory_create(B, invdata, c_vec_len(invdata)));
+
+ ns(Monster_testarrayofstring_start(B));
+ ns(Monster_testarrayofstring_end(B));
+
+ ns(Monster_testarrayoftables_start(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "TwoFace"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Joker"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Gulliver"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Alice"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_push_start(B));
+ ns(Monster_name_create_str(B, "Gulliver"));
+ ns(Monster_testarrayoftables_push_end(B));
+
+ ns(Monster_testarrayoftables_end(B));
+
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ mon = ns(Monster_as_root(buffer));
+ monsters = ns(Monster_testarrayoftables(mon));
+ assert(monsters);
+ inv = ns(Monster_inventory(mon));
+ assert(inv);
+ strings = ns(Monster_testarrayofstring(mon));
+ assert(strings);
+
+ if (1 != ns(Monster_vec_scan(monsters, "Joker"))) {
+ printf("scan_by did not find the Joker\n");
+ goto done;
+ }
+ if (1 != ns(Monster_vec_rscan(monsters, "Joker"))) {
+ printf("rscan_by did not find the Joker\n");
+ goto done;
+ }
+ if (1 != ns(Monster_vec_scan_n(monsters, "Joker3", 5))) {
+ printf("scan_by did not find the Joker with n\n");
+ goto done;
+ }
+ if (1 != ns(Monster_vec_rscan_n(monsters, "Joker3", 5))) {
+ printf("scan_by did not find the Joker with n\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 2, nsc(end), "Joker"))) {
+ printf("scan_from found Joker past first occurence\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan(monsters, "Jingle"))) {
+ printf("not found not working\n");
+ goto done;
+ }
+ if (0 != ns(Monster_vec_scan(monsters, "TwoFace"))) {
+ printf("TwoFace not found\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_scan_by_name(monsters, "Gulliver"))) {
+ printf("Gulliver not found\n");
+ goto done;
+ }
+ if (4 != ns(Monster_vec_rscan_by_name(monsters, "Gulliver"))) {
+ printf("Gulliver not found\n");
+ goto done;
+ }
+ if (4 != ns(Monster_vec_rscan_n_by_name(monsters, "Gulliver42", 8))) {
+ printf("Gulliver not found with n\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_rscan_ex_n_by_name(monsters, 1, 3, "Gulliver42", 8))) {
+ printf("Gulliver not found with n\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_scan_ex_by_name(monsters, 2, nsc(end), "Gulliver"))) {
+ printf("Gulliver not found starting from Gulliver\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_scan_ex_n_by_name(monsters, 2, nsc(end), "Gulliver42", 8))) {
+ printf("Gulliver not found starting from Gulliver\n");
+ goto done;
+ }
+ if (4 != ns(Monster_vec_scan_ex_by_name(monsters, 3, nsc(end), "Gulliver"))) {
+ printf("Another Gulliver not found\n");
+ goto done;
+ }
+
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 1, 3, "Jingle"))) {
+ printf("not found in subrange not working\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 1, 3, "TwoFace"))) {
+ printf("subrange doesn't limit low bound\n");
+ goto done;
+ }
+ if (1 != ns(Monster_vec_scan_ex(monsters, 1, 3, "Joker"))) {
+ printf("scan in subrange did not find Joker\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_scan_ex_by_name(monsters, 1, 3, "Gulliver"))) {
+ printf("scan in subrange did not find Gulliver\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex_by_name(monsters, 1, 3, "Alice"))) {
+ printf("subrange doesn't limit upper bound in scan\n");
+ goto done;
+ }
+
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, 1, 3, "Jingle"))) {
+ printf("not found in subrange not working with rscan\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, 1, 3, "TwoFace"))) {
+ printf("subrange doesn't limit lower bound in rscan\n");
+ goto done;
+ }
+ if (1 != ns(Monster_vec_rscan_ex(monsters, 1, 3, "Joker"))) {
+ printf("rscan in subrange did not find Joker\n");
+ goto done;
+ }
+ if (2 != ns(Monster_vec_rscan_ex_by_name(monsters, 1, 3, "Gulliver"))) {
+ printf("rscan in subrange did not find Gulliver\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex_by_name(monsters, 1, 3, "Alice"))) {
+ printf("subrange doesn't limit upper bound in rscan\n");
+ goto done;
+ }
+
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 0, 0, "TwoFace"))) {
+ printf("TwoFace is found in empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 0, 0, "Joker"))) {
+ printf("Joker is found in empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, 1, 1, "Joker"))) {
+ printf("Joker is found in another empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_scan_ex(monsters, ns(Monster_vec_len(monsters)), nsc(end), "TwoFace"))) {
+ printf("TwoFace is found in empty range in the end\n");
+ goto done;
+ }
+
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, 0, 0, "TwoFace"))) {
+ printf("TwoFace is found in empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, 0, 0, "Joker"))) {
+ printf("Joker is found in empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, 1, 1, "Joker"))) {
+ printf("Joker is found in another empty range\n");
+ goto done;
+ }
+ if (nsc(not_found) != ns(Monster_vec_rscan_ex(monsters, ns(Monster_vec_len(monsters)), nsc(end), "TwoFace"))) {
+ printf("TwoFace is found in empty range in the end\n");
+ goto done;
+ }
+
+ if (1 != count_monsters(monsters, "Joker")) {
+ printf("number of Jokers is not 1\n");
+ goto done;
+ }
+ if (0 != count_monsters(monsters, "Jingle")) {
+ printf("number of Jingles is not 0\n");
+ goto done;
+ }
+ if (1 != count_monsters(monsters, "TwoFace")) {
+ printf("number of TwoFace is not 1\n");
+ goto done;
+ }
+ if (2 != count_monsters(monsters, "Gulliver")) {
+ printf("number of Gullivers is not 2\n");
+ goto done;
+ }
+
+
+ if (0 != (pos = nsc(uint8_vec_scan(inv, 6)))) {
+ printf("scan not working on first item of inventory\n");
+ goto done;
+ }
+ if (2 != (pos = nsc(uint8_vec_scan(inv, 1)))) {
+ printf("scan not working on middle item of inventory\n");
+ goto done;
+ }
+ if (nsc(not_found) != (pos = nsc(uint8_vec_scan_ex(inv, 3, nsc(end), 1)))) {
+ printf("scan_ex(item+1) not working on middle item of inventory\n");
+ goto done;
+ }
+ if (nsc(not_found) != (pos = nsc(uint8_vec_scan(inv, 5)))) {
+ printf("scan not working for repeating item of inventory\n");
+ goto done;
+ }
+ if (6 != (pos = nsc(uint8_vec_scan(inv, 2)))) {
+ printf("scan not working on last item of inventory\n");
+ goto done;
+ }
+ if (3 != (pos = nsc(uint8_vec_scan(inv, 3)))) {
+ printf("scan not working for repeating item of inventory\n");
+ goto done;
+ }
+ if (3 != (pos = nsc(uint8_vec_scan_ex(inv, 3, nsc(end), 3)))) {
+ printf("scan_ex(item) not working for repeating item of inventory\n");
+ goto done;
+ }
+ if (5 != (pos = nsc(uint8_vec_scan_ex(inv, 4, nsc(end), 3)))) {
+ printf("scan_ex(item+1) not working for repeating item of inventory\n");
+ goto done;
+ }
+ if (5 != (pos = nsc(uint8_vec_rscan(inv, 3)))) {
+ printf("rscan not working for repeating item of inventory\n");
+ goto done;
+ }
+ if (3 != (pos = nsc(uint8_vec_rscan_ex(inv, 1, 4, 3)))) {
+ printf("rscan_ex not working for repeating item of inventory\n");
+ goto done;
+ }
+
+ /* Test that all scan functions are generated for string arrays */
+ nsc(string_vec_scan(strings, "Hello"));
+ nsc(string_vec_scan_ex(strings, 0, nsc(end), "Hello"));
+ nsc(string_vec_scan_n(strings, "Hello", 4));
+ nsc(string_vec_scan_ex_n(strings, 0, nsc(end), "Hello", 4));
+ nsc(string_vec_rscan(strings, "Hello"));
+ nsc(string_vec_rscan_ex(strings, 0, nsc(end), "Hello"));
+ nsc(string_vec_rscan_n(strings, "Hello", 4));
+ nsc(string_vec_rscan_ex_n(strings, 0, nsc(end), "Hello", 4));
+
+#if FLATCC_ALLOW_SCAN_FOR_ALL_FIELDS
+ /* Check for presence of scan for non-key fields */
+ ns(Monster_vec_scan_by_hp(monsters, 13));
+ ns(Monster_vec_scan_ex_by_hp(monsters, 1, nsc(end), 42));
+ ns(Monster_vec_rscan_by_hp(monsters, 1));
+ ns(Monster_vec_rscan_ex_by_hp(monsters, 0, 2, 42));
+#endif
+
+ ret = 0;
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_basic_sort(flatcc_builder_t *B)
+{
+ ns(Monster_table_t) mon;
+ nsc(uint8_vec_t) inv;
+ nsc(uint8_mutable_vec_t) minv;
+
+ void *buffer;
+ size_t size;
+ uint8_t invdata[] = { 6, 7, 1, 3, 4, 3, 2 };
+ uint8_t sortedinvdata[] = { 1, 2, 3, 3, 4, 6, 7 };
+ uint8_t v, i;
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_inventory_create(B, invdata, c_vec_len(invdata)));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+
+ mon = ns(Monster_as_root(buffer));
+ inv = ns(Monster_inventory(mon));
+ minv = (nsc(uint8_mutable_vec_t))inv;
+ nsc(uint8_vec_sort(minv));
+ assert(nsc(uint8_vec_len(inv) == c_vec_len(invdata)));
+ for (i = 0; i < nsc(uint8_vec_len(inv)); ++i) {
+ v = nsc(uint8_vec_at(inv, i));
+ if (v != sortedinvdata[i]) {
+ printf("inventory not sorted\n");
+ return -1;
+ }
+ if (nsc(uint8_vec_find(inv, v) != (i == 3 ? 2 : i))) {
+ printf("find not working on inventory\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int test_clone_slice(flatcc_builder_t *B)
+{
+ ns(Monster_table_t) mon, mon2;
+ nsc(string_vec_t) strings;
+ nsc(bool_vec_t) bools;
+ nsc(string_t) name;
+ ns(Monster_ref_t) monster_ref;
+ ns(Test_t) *t;
+ ns(Test_struct_t) test4;
+ ns(Test_struct_t) elem4;
+ void *buffer, *buf2;
+ size_t size;
+ int ret = -1;
+ uint8_t booldata[] = { 0, 1, 0, 0, 1, 0, 0 };
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "The Source"));
+ ns(Monster_testarrayofbools_create(B, booldata, c_vec_len(booldata)));
+
+ ns(Monster_test4_start(B));
+ t = ns(Monster_test4_extend(B, 2));
+ t[0].a = 22;
+ t[1].a = 44;
+ ns(Monster_test4_end(B));
+ ns(Monster_pos_start(B))->x = -42.3f;
+
+ ns(Monster_end_as_root(B));
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ hexdump("clone slice source buffer", buffer, size, stderr);
+
+ mon = ns(Monster_as_root(buffer));
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+
+ name = ns(Monster_name(mon));
+ assert(name);
+ bools = ns(Monster_testarrayofbools(mon));
+ assert(bools);
+ test4 = ns(Monster_test4(mon));
+ assert(test4);
+
+ ns(Monster_name_clone(B, name));
+ ns(Monster_testarrayofstring_start(B));
+ ns(Monster_testarrayofstring_push_clone(B, name));
+ ns(Monster_testarrayofstring_push_slice(B, name, 4, 20));
+ ns(Monster_testarrayofstring_push_slice(B, name, 0, 3));
+ ns(Monster_testarrayofstring_end(B));
+ ns(Monster_start(B));
+ ns(Monster_name_slice(B, name, 2, 20));
+ ns(Monster_testarrayofbools_clone(B, bools));
+
+ ns(Monster_test4_slice(B, test4, 1, 2));
+
+
+ monster_ref = ns(Monster_end(B));
+
+ ns(Monster_test_add(B, ns(Any_as_Monster(monster_ref))));
+ ns(Monster_testarrayofbools_slice(B, bools, 3, (size_t)-1));
+
+ ns(Monster_pos_clone(B, ns(Monster_pos(mon))));
+ ns(Monster_test4_clone(B, test4));
+
+ ns(Monster_end_as_root(B));
+
+ buf2 = flatcc_builder_get_direct_buffer(B, &size);
+ hexdump("target buffer of clone", buf2, size, stderr);
+ mon2 = ns(Monster_as_root(buf2));
+
+ if (strcmp(ns(Monster_name(mon2)), "The Source")) {
+ printf("The Source was not cloned\n");
+ goto done;
+ }
+
+ strings = ns(Monster_testarrayofstring(mon2));
+ if (strcmp(nsc(string_vec_at(strings, 0)), "The Source")) {
+ printf("Push clone failed The Source\n");
+ goto done;
+ }
+ if (nsc(string_len(nsc(string_vec_at(strings, 1)))) != 6) {
+ printf("Push slice failed Sourcee on length\n");
+ goto done;
+ }
+ if (strcmp(nsc(string_vec_at(strings, 1)), "Source")) {
+ printf("Push slice failed Source\n");
+ goto done;
+ }
+ if (nsc(string_len(nsc(string_vec_at(strings, 2)))) != 3) {
+ printf("Push slice failed The on length\n");
+ goto done;
+ }
+ if (strcmp(nsc(string_vec_at(strings, 2)), "The")) {
+ printf("Push slice failed The\n");
+ goto done;
+ }
+ mon = ns(Monster_test(mon2));
+ assert(mon);
+ if (strcmp(ns(Monster_name(mon)), "e Source")) {
+ printf("name_slice did not shorten The Source correctly");
+ goto done;
+ }
+ bools = ns(Monster_testarrayofbools(mon));
+ if (nsc(bool_vec_len(bools)) != 7) {
+ printf("clone bool has wrong length\n");
+ goto done;
+ }
+ if (memcmp(bools, booldata, 7)) {
+ printf("cloned bool has wrong content\n");
+ goto done;
+ }
+
+ bools = ns(Monster_testarrayofbools(mon2));
+ if (nsc(bool_vec_len(bools)) != 4) {
+ printf("slice bool has wrong length\n");
+ goto done;
+ }
+ if (memcmp(bools, booldata + 3, 4)) {
+ printf("sliced bool has wrong content\n");
+ goto done;
+ }
+ if (!parse_float_is_equal(ns(Monster_pos(mon2))->x, -42.3f)) {
+ printf("cloned pos struct failed\n");
+ goto done;
+ };
+ test4 = ns(Monster_test4(mon2));
+ if (ns(Test_vec_len(test4)) != 2) {
+ printf("struct vector test4 not cloned with correct length\n");
+ goto done;
+ }
+ elem4 = ns(Test_vec_at(test4, 0));
+ if (ns(Test_a(elem4)) != 22) {
+ printf("elem 0 of test4 not cloned\n");
+ goto done;
+ }
+ if (flatbuffers_is_native_pe() && ns(Test_vec_at(test4, 0))->a != 22) {
+ printf("elem 0 of test4 not cloned, direct access\n");
+ goto done;
+ }
+ elem4 = ns(Test_vec_at(test4, 1));
+ if (ns(Test_a(elem4)) != 44) {
+ printf("elem 1 of test4 not cloned\n");
+ goto done;
+ }
+ test4 = ns(Monster_test4(mon));
+ if (ns(Test_vec_len(test4)) != 1) {
+ printf("sliced struct vec not sliced\n");
+ goto done;
+ }
+ elem4 = ns(Test_vec_at(test4, 0));
+ if (ns(Test_a(elem4)) != 44) {
+ printf("sliced struct vec has wrong element\n");
+ goto done;
+ }
+
+ /*
+ * There is no push clone of structs because it becomes messy when
+ * the vector has to be ended using end_pe or alternative do double
+ * conversion with unclear semantics.
+ */
+
+ ret = 0;
+
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_create_add_field(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ int ret = -1;
+ ns(Monster_table_t) mon;
+ ns(Stat_table_t) stat;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_testempty_create(B, nsc(string_create_str(B, "hello")), -100, 2));
+ ns(Monster_enemy_add(B, 0));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ mon = ns(Monster_as_root(buffer));
+ if (ns(Monster_enemy_is_present(mon))) {
+ printf("enemy should not be present when adding null\n");
+ goto done;
+ }
+ stat = ns(Monster_testempty(mon));
+ if (!(ns(Stat_val(stat)) == -100)) {
+ printf("Stat didn't happen\n");
+ goto done;
+ }
+ ret = 0;
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int verify_union_vector(void *buffer, size_t size)
+{
+ int ret = -1;
+ size_t n;
+ int color;
+
+ ns(Monster_table_t) mon;
+ ns(TestSimpleTableWithEnum_table_t) kermit;
+ flatbuffers_generic_vec_t anyvec;
+ ns(Any_vec_t) anyvec_type;
+ ns(Any_union_vec_t) anyvec_union;
+ ns(Any_union_t) anyelem;
+ ns(Alt_table_t) alt;
+
+ if ((ret = ns(Monster_verify_as_root(buffer, size)))) {
+ printf("Monster buffer with union vector failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ goto failed;
+ }
+
+ mon = ns(Monster_as_root(buffer));
+ if (ns(Monster_test_type(mon)) != ns(Any_Alt)) {
+ printf("test field does not have Alt type");
+ goto failed;
+ }
+ alt = ns(Monster_test(mon));
+ if (!alt || !ns(Alt_manyany_is_present(alt))) {
+ printf("manyany union vector should be present.\n");
+ goto failed;
+ }
+ anyvec_type = ns(Alt_manyany_type(alt));
+ anyvec = ns(Alt_manyany(alt));
+ n = ns(Any_vec_len(anyvec_type));
+ if (n != 1) {
+ printf("manyany union vector has wrong length.\n");
+ goto failed;
+ }
+ if (nsc(union_type_vec_at(anyvec_type, 0)) != ns(Any_TestSimpleTableWithEnum)) {
+ printf("manyany union vector has wrong element type.\n");
+ goto failed;
+ }
+ kermit = flatbuffers_generic_vec_at(anyvec, 0);
+ if (!kermit) {
+ printf("Kermit is lost.\n");
+ goto failed;
+ }
+ color = ns(TestSimpleTableWithEnum_color(kermit));
+ if (color != ns(Color_Green)) {
+ printf("Kermit has wrong color: %i.\n", (int)color);
+ goto failed;
+ }
+ anyvec_union = ns(Alt_manyany_union(alt));
+ if (ns(Any_union_vec_len(anyvec_union)) != 1) {
+ printf("manyany union vector has wrong length from a different perspective.\n");
+ goto failed;
+ }
+ anyelem = ns(Any_union_vec_at(anyvec_union, 0));
+ if (anyelem.type != nsc(union_type_vec_at(anyvec_type, 0))) {
+ printf("Kermit is now different.\n");
+ goto failed;
+ }
+ if (anyelem.value != kermit) {
+ printf("Kermit is incoherent.\n");
+ goto failed;
+ }
+ ret = 0;
+
+done:
+ return ret;
+
+failed:
+ ret = -1;
+ goto done;
+}
+
+int test_union_vector(flatcc_builder_t *B)
+{
+ void *buffer = 0, *cloned_buffer = 0;
+ size_t size;
+ int ret = -1;
+ flatcc_refmap_t refmap, *refmap_old;
+
+ ns(TestSimpleTableWithEnum_ref_t) kermit_ref;
+ ns(Any_union_vec_ref_t) anyvec_ref;
+
+
+ flatcc_refmap_init(&refmap);
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "Kermit"));
+
+ kermit_ref = ns(TestSimpleTableWithEnum_create(B,
+ ns(Color_Green), ns(Color_Green),
+ ns(Color_Green), ns(Color_Green)));
+ ns(Any_vec_start(B));
+ ns(Any_vec_push(B, ns(Any_as_TestSimpleTableWithEnum(kermit_ref))));
+ anyvec_ref = ns(Any_vec_end(B));
+ ns(Monster_test_Alt_start(B));
+ ns(Alt_manyany_add(B, anyvec_ref));
+ ns(Monster_test_Alt_end(B));
+
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ if (verify_union_vector(buffer, size)) {
+ printf("Union vector Monster didn't verify.\n");
+ goto failed;
+ }
+ flatcc_builder_reset(B);
+ refmap_old = flatcc_builder_set_refmap(B, &refmap);
+ if (!ns(Monster_clone_as_root(B, ns(Monster_as_root(buffer))))) {
+ printf("Cloned union vector Monster didn't actually clone.\n");
+ goto failed;
+ };
+ flatcc_builder_set_refmap(B, refmap_old);
+ cloned_buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ if (verify_union_vector(buffer, size)) {
+ printf("Cloned union vector Monster didn't verify.\n");
+ goto failed;
+ }
+
+ ret = 0;
+
+done:
+ flatcc_refmap_clear(&refmap);
+ flatcc_builder_aligned_free(buffer);
+ flatcc_builder_aligned_free(cloned_buffer);
+ return ret;
+
+failed:
+ ret = -1;
+ goto done;
+}
+
+int verify_fixed_length_array(const void *buffer, size_t size)
+{
+ const char *text;
+ ns(Monster_table_t) mon;
+ ns(Alt_table_t) alt;
+ ns(FooBar_struct_t) fa;
+ ns(FooBar_t) fa2;
+ ns(Test_struct_t) t0, t1;
+ int ret;
+
+ if ((ret = ns(Monster_verify_as_root(buffer, size)))) {
+ printf("Monster buffer with fixed length arrays failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+
+ mon = ns(Monster_as_root(buffer));
+ if (ns(Monster_test_type(mon)) != ns(Any_Alt)) {
+ printf("test field does not have Alt type");
+ return -1;
+ }
+
+ alt = ns(Monster_test(mon));
+ if (!alt || !ns(Alt_fixed_array_is_present(alt))) {
+ printf("fixed array should be present.\n");
+ return -1;
+ }
+
+ fa = ns(Alt_fixed_array(alt));
+
+ if (ns(FooBar_foo(fa, 0)) != 1.0f || ns(FooBar_bar(fa, 9) != 1000)) {
+ printf("Monster buffer with fixed length arrays has wrong content\n");
+ return -1;
+ }
+
+ if (ns(FooBar_foo_get(fa, 0)) != 1.0f || ns(FooBar_bar_get(fa, 9) != 1000)) {
+ printf("Monster buffer with fixed length arrays has wrong content\n");
+ return -1;
+ }
+ if (ns(FooBar_foo_get(fa, 16)) != 0.0f || ns(FooBar_bar_get(fa, 10) != 0)) {
+ printf("Monster buffer with fixed length arrays has bad bounds check\n");
+ return -1;
+ }
+ if (ns(FooBar_col_get(fa, 2)) != ns(Color_Red)) {
+ printf("Fixed length enum array content not correct\n");
+ return -1;
+ }
+ t0 = ns(FooBar_tests_get(fa, 0));
+ t1 = ns(FooBar_tests_get(fa, 1));
+ if (!t0 || !t1) {
+ printf("Monster buffer with fixed length struct arrays has missing element\n");
+ return -1;
+ }
+ if (ns(Test_a_get(t0)) != 0 || ns(Test_b_get(t0)) != 4) {
+ printf("Monster buffer with fixed length struct arrays has wrong first element member content\n");
+ return -1;
+ }
+ if (ns(Test_a_get(t1)) != 1 || ns(Test_b_get(t1)) != 2) {
+ printf("Monster buffer with fixed length struct arrays has wrong second element member content\n");
+ return -1;
+ }
+
+ /* Endian safe because char arrays are endian neutral. */
+ text = ns(FooBar_text_get_ptr(fa));
+ if (strncmp(text, "hello", ns(FooBar_text_get_len())) != 0) {
+ printf("Monster buffer with fixed length array field has wrong text\n");
+ return -1;
+ }
+
+ /*
+ * Note: use ns(FooBar_foo_get_ptr(fa) to get a raw pointer to the
+ * array is not endian safe. Since this is a struct array field,
+ * fa->foo would also provide the raw pointer.
+ */
+ if (flatbuffers_is_native_pe()) {
+ if (ns(FooBar_foo_get_ptr(fa))[1] != 2.0f) {
+ printf("Monster buffer with fixed length arrays get_ptr has wrong content\n");
+ return -1;
+ }
+ }
+
+ ns(FooBar_copy_from_pe(&fa2, fa));
+ if (fa2.foo[0] != 1.0f || fa2.foo[1] != 2.0f || fa2.foo[15] != 16.0f ||
+ fa2.bar[0] != 100 || fa2.bar[9] != 1000) {
+ printf("Monster buffer with copied fixed length arrays has wrong content\n");
+ return -1;
+ }
+ if (fa2.foo[2] != 0.0f || fa2.foo[14] != 0.0f || fa2.bar[1] != 0 || fa2.bar[8] != 0) {
+ printf("Monster buffer with copied fixed length arrays has not been zero padded\n");
+ return -1;
+ }
+
+ /*
+ * In-place conversion - a nop on little endian platforms.
+ * Cast needed to remove const
+ */
+ ns(FooBar_from_pe)((ns(FooBar_t) *)fa);
+ if (fa->foo[0] != 1.0f || fa->foo[1] != 2.0f || fa->foo[15] != 16.0f ||
+ fa->bar[0] != 100 || fa->bar[9] != 1000) {
+ printf("Monster buffer with in-place converted fixed length arrays has wrong content\n");
+ return -1;
+ }
+ if (fa->foo[2] != 0.0f || fa->foo[14] != 0.0f || fa->bar[1] != 0 || fa->bar[8] != 0) {
+ printf("Monster buffer with in-place converted fixed length arrays has not been zero padded\n");
+ return -1;
+ }
+ return 0;
+}
+
+int test_fixed_length_array(flatcc_builder_t *B)
+{
+ void *buffer = 0;
+ size_t size;
+ int ret = -1;
+ float foo_input[16] = { 1.0f, 2.0f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16.0f };
+ int bar_input[10] = { 100, 0, 0, 0, 0, 0, 0, 0, 0, 1000 };
+ ns(Color_enum_t) col_input[3] = { 0, 0, ns(Color_Red) };
+ ns(Test_t) tests_input[2] = {{ 0, 4 }, { 1, 2 }};
+
+ ns(FooBar_t) *foobar;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "Monolith"));
+ ns(Monster_test_Alt_start(B));
+ foobar = ns(Alt_fixed_array_start(B));
+ foobar->foo[0] = 1.0f;
+ foobar->foo[1] = 2.0f;
+ foobar->foo[15] = 16.0f;
+ foobar->bar[0] = 100;
+ foobar->bar[9] = 1000;
+ foobar->col[2] = ns(Color_Red);
+ foobar->tests[0].b = 4;
+ foobar->tests[1].a = 1;
+ foobar->tests[1].b = 2;
+ strncpy(foobar->text, "hello, world", ns(FooBar_text_get_len()));
+ // or strncopy(foobar->text, "hello, world", sizeof(foobar->text));
+ ns(Alt_fixed_array_end(B));
+ ns(Monster_test_Alt_end(B));
+
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ ret = verify_fixed_length_array(buffer, size);
+ flatcc_builder_aligned_free(buffer);
+ if (ret) return -1;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "Monolith"));
+ ns(Monster_test_Alt_start(B));
+ foobar = ns(Alt_fixed_array_start(B));
+ ns(FooBar_assign)(foobar, foo_input, bar_input, col_input, tests_input, "hello");
+ ns(Alt_fixed_array_end(B));
+ ns(Monster_test_Alt_end(B));
+
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ ret = verify_fixed_length_array(buffer, size);
+ flatcc_builder_aligned_free(buffer);
+ if (ret) return -1;
+
+ return 0;
+}
+
+#define STR(s) nsc(string_create_str(B, s))
+
+int test_recursive_sort(flatcc_builder_t *B)
+{
+ nsc(string_ref_t) name;
+
+ void *buffer = 0;
+ size_t size = 0;
+ int ret = -1;
+ ns(Alt_table_t) alt;
+ ns(Any_union_t) any;
+ ns(Monster_table_t) monster;
+ ns(MultipleKeys_vec_t) mkvec;
+ ns(MultipleKeys_table_t) mk;
+ size_t index;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+
+ name = STR("Keyed Monster");
+ ns(Alt_start(B));
+ ns(Alt_multik_start(B));
+ ns(Alt_multik_push_create(B, STR("hi"), STR("there"), 42));
+ ns(Alt_multik_push_create(B, STR("hello"), STR("anyone"), 10));
+ ns(Alt_multik_push_create(B, STR("hello"), STR("anyone"), 4));
+ ns(Alt_multik_push_create(B, STR("good day"), STR("sir"), 1004));
+ ns(Alt_multik_end(B));
+ ns(Monster_test_add)(B, ns(Any_as_Alt(ns(Alt_end(B)))));
+ ns(Monster_name_add)(B, name);
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+ monster = ns(Monster_as_root)(buffer);
+ ns(Monster_sort)((ns(Monster_mutable_table_t))monster);
+ any = ns(Monster_test_union(monster));
+ if (any.type != ns(Any_Alt)) {
+ printf("Any type no Alt as expected\n");
+ goto done;
+ }
+ alt = any.value;
+ mkvec = ns(Alt_multik(alt));
+ index = ns(MultipleKeys_vec_len(mkvec));
+ if (index != 4) {
+ printf("unexpected multik vec len, got %d\n", (int)index);
+ goto done;
+ }
+ mk = ns(MultipleKeys_vec_at(mkvec, 0));
+ if (ns(MultipleKeys_foobar(mk) != 4)) {
+ printf("multik elem 0 not sorted, but it really should be\n");
+ }
+ mk = ns(MultipleKeys_vec_at(mkvec, 1));
+ if (ns(MultipleKeys_foobar(mk) != 10)) {
+ printf("multik elem 1 not sorted, but it really should be\n");
+ }
+ mk = ns(MultipleKeys_vec_at(mkvec, 2));
+ if (ns(MultipleKeys_foobar(mk) != 42)) {
+ printf("multik elem 2 not sorted, but it really should be\n");
+ }
+ mk = ns(MultipleKeys_vec_at(mkvec, 3));
+ if (ns(MultipleKeys_foobar(mk) != 1004)) {
+ printf("multik elem 3 not sorted, but it really should be\n");
+ }
+
+ hexdump("MultiKeyed buffer", buffer, size, stderr);
+ if ((ret = ns(Monster_verify_as_root(buffer, size)))) {
+ printf("Multikeyed Monster buffer failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ goto done;
+ }
+
+ ret = 0;
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_mixed_type_union(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ int ret = -1;
+ /* Builder */
+ nsf(Character_union_ref_t) ut;
+ nsf(Rapunzel_ref_t) cameo_ref;
+ nsf(Attacker_ref_t) attacker_ref;
+ nsf(BookReader_ref_t) br_ref;
+ nsf(BookReader_t *) pbr;
+ nsf(Movie_table_t) mov;
+
+ /* Reader */
+ nsf(Character_union_vec_t) characters;
+ nsf(Character_union_t) character;
+ nsf(Rapunzel_struct_t) rapunzel;
+ nsf(Attacker_table_t) attacker;
+ nsc(string_t) text;
+
+ flatcc_builder_reset(B);
+
+ nsf(Movie_start_as_root(B));
+ br_ref = nsf(BookReader_create(B, 10));
+ cameo_ref = nsf(Rapunzel_create(B, 22));
+ ut = nsf(Character_as_Rapunzel(cameo_ref));
+ nsf(Movie_main_character_Rapunzel_create(B, 19));
+ nsf(Movie_cameo_Rapunzel_add(B, cameo_ref));
+ attacker_ref = nsf(Attacker_create(B, 42));
+ nsf(Movie_antagonist_MuLan_add(B, attacker_ref));
+ nsf(Movie_side_kick_Other_create_str(B, "Nemo"));
+ nsf(Movie_characters_start(B));
+ nsf(Movie_characters_push(B, ut));
+ nsf(Movie_characters_MuLan_push(B, attacker_ref));
+ nsf(Movie_characters_MuLan_push_create(B, 1));
+ nsf(Character_vec_push(B, nsf(Character_as_Other(nsc(string_create_str(B, "other"))))));
+ nsf(Movie_characters_Belle_push(B, br_ref));
+ pbr = nsf(Movie_characters_Belle_push_start(B));
+ pbr->books_read = 3;
+ nsf(Movie_characters_Belle_push_end(B));
+ nsf(Movie_characters_Belle_push(B, nsf(BookReader_create(B, 1))));
+ nsf(Movie_characters_Belle_push_create(B, 2));
+ nsf(Movie_characters_Other_push(B, nsc(string_create_str(B, "another"))));
+ nsf(Movie_characters_Other_push_create_str(B, "yet another"));
+ nsf(Movie_characters_end(B));
+ nsf(Movie_end_as_root(B));
+
+ buffer = flatcc_builder_finalize_aligned_buffer(B, &size);
+
+ hexdump("Movie buffer", buffer, size, stderr);
+ if ((ret = nsf(Movie_verify_as_root(buffer, size)))) {
+ printf("Movie buffer with mixed type union and union vector failed to verify, got: %s\n", flatcc_verify_error_string(ret));
+ return -1;
+ }
+ ret = -1;
+
+ mov = nsf(Movie_as_root(buffer));
+ if (!nsf(Movie_main_character_is_present(mov))) {
+ printf("Main_charactery union should be present.\n");
+ goto done;
+ }
+ if (!nsf(Movie_characters_is_present(mov))) {
+ printf("Characters union vector should be present.\n");
+ goto done;
+ }
+ character = nsf(Movie_main_character_union(mov));
+ if (character.type != nsf(Character_Rapunzel)) {
+ printf("Unexpected main character.\n");
+ goto done;
+ };
+ /*
+ * Tables and structs can cast by void pointer assignment while
+ * strings require an explicit cast.
+ */
+ rapunzel = character.value;
+ if (!rapunzel) {
+ printf("Rapunzel has gone AWOL\n");
+ }
+ if (nsf(Rapunzel_hair_length(rapunzel)) > 19) {
+ printf("Rapunzel's hair has grown unexpectedly\n");
+ goto done;
+ }
+ if (nsf(Rapunzel_hair_length(rapunzel)) < 19) {
+ printf("Rapunzel's hair has been trimmed unexpectedly\n");
+ goto done;
+ }
+ if (nsf(Movie_cameo_type(mov)) != nsf(Character_Rapunzel)) {
+ printf("Rapunzel did was not selected for cameo appearance.\n");
+ goto done;
+ }
+ rapunzel = nsf(Movie_cameo(mov));
+ if (!rapunzel) {
+ printf("Rapunzel did not show up for cameo appearance.\n");
+ goto done;
+ }
+ if (nsf(Rapunzel_hair_length(rapunzel)) != 22) {
+ printf("Rapunzel didn't style her hair for cameo role.\n");
+ goto done;
+ }
+ if (nsf(Movie_antagonist_type(mov)) != nsf(Character_MuLan)) {
+ printf("Unexpected antagonist.\n");
+ goto done;
+ }
+ attacker = nsf(Movie_antagonist(mov));
+ if (!attacker || nsf(Attacker_sword_attack_damage(attacker)) != 42) {
+ printf("Unexpected sword attack damamage.\n");
+ goto done;
+ }
+ if (nsf(Movie_side_kick_type(mov)) != nsf(Character_Other)) {
+ printf("Unexpected side kick.\n");
+ goto done;
+ }
+ /*
+ * We need to cast because generic pointers refer to the start
+ * of the memory block which is the string length, not the first
+ * character in the string.
+ */
+ text = nsc(string_cast_from_generic(nsf(Movie_side_kick(mov))));
+ if (!text) {
+ printf("missing side kick string.\n");
+ goto done;
+ }
+ if (strcmp(text, "Nemo")) {
+ printf("unexpected side kick string: '%s'.\n", text);
+ goto done;
+ }
+ text = nsf(Movie_side_kick_as_string(mov));
+ if (!text) {
+ printf("missing side kick string.\n");
+ goto done;
+ }
+ if (strcmp(text, "Nemo")) {
+ printf("unexpected side kick string (take 2): '%s'.\n", text);
+ goto done;
+ }
+ character = nsf(Movie_side_kick_union(mov));
+ text = nsc(string_cast_from_union(character));
+ if (strcmp(text, "Nemo")) {
+ printf("unexpected side kick string (take 3): '%s'.\n", text);
+ goto done;
+ }
+ characters = nsf(Movie_characters_union(mov));
+ character = nsf(Character_union_vec_at(characters, 0));
+ if (character.type != nsf(Character_Rapunzel)) {
+ printf("The first character is not Rapunzel.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 1));
+ if (character.type != nsf(Character_MuLan)) {
+ printf("The second character is not MuLan.");
+ goto done;
+ };
+ attacker = character.value;
+ if (nsf(Attacker_sword_attack_damage(attacker) != 42)) {
+ printf("The second character has unexpected sword damage.");
+ goto done;
+ }
+ character = nsf(Character_union_vec_at(characters, 2));
+ if (character.type != nsf(Character_MuLan)) {
+ printf("The third character is not MuLan.");
+ goto done;
+ };
+ attacker = character.value;
+ if (nsf(Attacker_sword_attack_damage(attacker) != 1)) {
+ printf("The third character has unexpected sword damage.");
+ goto done;
+ }
+ if (nsc(union_type_vec_at(nsf(Movie_characters_type(mov)), 3)) != nsf(Character_Other)) {
+ printf("The fourth character was not of type 'Other'!\n");
+ goto done;
+ }
+ text = nsf(Character_union_vec_at_as_string(characters, 3));
+ if (!text || strcmp(text, "other")) {
+ printf("The fourth character was not described as 'other'.\n");
+ goto done;
+ }
+ character = nsf(Character_union_vec_at(characters, 3));
+ if (character.type != nsf(Character_Other)) {
+ printf("The fourth character is not of type 'Other' (take two).");
+ goto done;
+ };
+ text = nsc(string_cast_from_union(character));
+ if (!text || strcmp(text, "other")) {
+ printf("The fourth character was not described as 'other' (take two).\n");
+ goto done;
+ }
+ character = nsf(Character_union_vec_at(characters, 4));
+ if (character.type != nsf(Character_Belle)) {
+ printf("The fifth character is not Belle.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 5));
+ if (character.type != nsf(Character_Belle)) {
+ printf("The sixth character is not Belle.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 6));
+ if (character.type != nsf(Character_Belle)) {
+ printf("The seventh character is not Belle.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 7));
+ if (character.type != nsf(Character_Belle)) {
+ printf("The eighth character is not Belle.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 8));
+ if (character.type != nsf(Character_Other)) {
+ printf("The ninth character is not of type 'Other'.");
+ goto done;
+ };
+ character = nsf(Character_union_vec_at(characters, 9));
+ if (character.type != nsf(Character_Other)) {
+ printf("The ninth character is not of type 'Other'.");
+ goto done;
+ };
+ if (nsf(Character_union_vec_len(characters) != 10)) {
+ printf("The 11'th character should not exist.");
+ goto done;
+ };
+
+ ret = 0;
+done:
+ flatcc_builder_aligned_free(buffer);
+ return ret;
+}
+
+int test_add_set_defaults(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ ns(Monster_table_t) mon;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_hp_add(B, 100));
+ ns(Monster_mana_add(B, 100));
+ ns(Monster_color_add(B, ns(Color_Blue)));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+ mon = ns(Monster_as_root(buffer));
+ if (ns(Monster_hp_is_present(mon))) {
+ printf("default should not be present for hp field\n");
+ return -1;
+ }
+ if (!ns(Monster_mana_is_present(mon))) {
+ printf("non-default should be present for mana field\n");
+ return -1;
+ }
+ if (ns(Monster_color_is_present(mon))) {
+ printf("default should not be present for color field\n");
+ return -1;
+ }
+
+ flatcc_builder_reset(B);
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_hp_force_add(B, 100));
+ ns(Monster_mana_force_add(B, 100));
+ ns(Monster_color_force_add(B, ns(Color_Blue)));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+ mon = ns(Monster_as_root(buffer));
+ if (!ns(Monster_hp_is_present(mon))) {
+ printf("default should be present for hp field when forced\n");
+ return -1;
+ }
+ if (!ns(Monster_mana_is_present(mon))) {
+ printf("non-default should be present for mana field, also when forced\n");
+ return -1;
+ }
+ if (!ns(Monster_color_is_present(mon))) {
+ printf("default should be present for color field when forced\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int test_nested_buffer(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ ns(Monster_table_t) mon, nested;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ /*
+ * Note:
+ * ns(Monster_testnestedflatbuffer_start(B));
+ * would start a raw ubyte array so we use start_as_root.
+ */
+ ns(Monster_testnestedflatbuffer_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyNestedMonster"));
+ ns(Monster_testnestedflatbuffer_end_as_root(B));
+ ns(Monster_hp_add(B, 10));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+ hexdump("nested flatbuffer", buffer, size, stderr);
+
+ mon = ns(Monster_as_root(buffer));
+ if (strcmp(ns(Monster_name(mon)), "MyMonster")) {
+ printf("got the wrong root monster\n");
+ return -1;
+ }
+ /*
+ * Note:
+ * nested = ns(Monster_testnestedflatbuffer(mon));
+ * would return a raw ubyte vector not a monster.
+ */
+ nested = ns(Monster_testnestedflatbuffer_as_root(mon));
+
+ if (ns(Monster_hp(mon)) != 10) {
+ printf("health points wrong at root monster\n");
+ return -1;
+ }
+
+ assert(ns(Monster_name(nested)));
+ if (strcmp(ns(Monster_name(nested)), "MyNestedMonster")) {
+ printf("got the wrong nested monster\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int test_nested_buffer_first(flatcc_builder_t *B)
+{
+ void *buffer;
+ size_t size;
+ ns(Monster_table_t) mon, nested;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ /*
+ * Note:
+ * ns(Monster_testnestedflatbuffer_start(B));
+ * would start a raw ubyte array so we use start_as_root.
+ *
+ * Here we create the nested buffer first, and the parent
+ * string after so the emitter sees the nested buffer first.
+ */
+ ns(Monster_testnestedflatbuffer_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyNestedMonster"));
+ ns(Monster_testnestedflatbuffer_end_as_root(B));
+ ns(Monster_hp_add(B, 10));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+ hexdump("nested flatbuffer", buffer, size, stderr);
+
+ mon = ns(Monster_as_root(buffer));
+ if (strcmp(ns(Monster_name(mon)), "MyMonster")) {
+ printf("got the wrong root monster\n");
+ return -1;
+ }
+ /*
+ * Note:
+ * nested = ns(Monster_testnestedflatbuffer(mon));
+ * would return a raw ubyte vector not a monster.
+ */
+ nested = ns(Monster_testnestedflatbuffer_as_root(mon));
+
+ if (ns(Monster_hp(mon)) != 10) {
+ printf("health points wrong at root monster\n");
+ return -1;
+ }
+
+ assert(ns(Monster_name(nested)));
+ if (strcmp(ns(Monster_name(nested)), "MyNestedMonster")) {
+ printf("got the wrong nested monster\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int test_nested_buffer_using_nest(flatcc_builder_t *B)
+{
+ void *buffer;
+ uint8_t nested_buffer[1024];
+ size_t size, nested_size;
+ ns(Monster_table_t) mon, nested;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_name_create_str(B, "MyNestedMonster"));
+ ns(Monster_mana_add(B, 42));
+ ns(Monster_end_as_root(B));
+
+ nested_size = flatcc_builder_get_buffer_size(B);
+ if (!flatcc_builder_copy_buffer(B, nested_buffer, sizeof(nested_buffer))) {
+ printf("nested buffer copy failed\n");
+ return -1;
+ }
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_testnestedflatbuffer_nest(B, nested_buffer, nested_size, 0));
+ ns(Monster_hp_add(B, 10));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_end_as_root(B));
+
+ buffer = flatcc_builder_get_direct_buffer(B, &size);
+ hexdump("nested flatbuffer [using _nest()]", buffer, size, stderr);
+
+ mon = ns(Monster_as_root(buffer));
+ if (strcmp(ns(Monster_name(mon)), "MyMonster")) {
+ printf("got the wrong root monster\n");
+ return -1;
+ }
+ /*
+ * Note:
+ * nested = ns(Monster_testnestedflatbuffer(mon));
+ * would return a raw ubyte vector not a monster.
+ */
+ nested = ns(Monster_testnestedflatbuffer_as_root(mon));
+
+ if (ns(Monster_hp(mon)) != 10) {
+ printf("health points wrong at root monster\n");
+ return -1;
+ }
+
+ assert(ns(Monster_name(nested)));
+ if (strcmp(ns(Monster_name(nested)), "MyNestedMonster")) {
+ printf("got the wrong nested monster\n");
+ return -1;
+ }
+
+ if (ns(Monster_mana(nested)) != 42) {
+ printf("mana points wrong in nested monster\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int verify_include(void *buffer)
+{
+ (void)buffer;
+
+ if (MyGame_OtherNameSpace_FromInclude_Foo != 17) {
+ printf("Unexpected enum value `Foo` from included schema\n");
+ return -1;
+ }
+
+ if (MyGame_OtherNameSpace_FromInclude_IncludeVal != 0) {
+ printf("Unexpected enum value `IncludeVal` from included schema\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int test_struct_buffer(flatcc_builder_t *B)
+{
+ uint8_t buffer[100];
+
+ size_t size;
+ ns(Vec3_t) *v;
+ ns(Vec3_struct_t) vec3;
+
+ flatcc_builder_reset(B);
+ ns(Vec3_create_as_root(B, 1, 2, 3, 4.2, ns(Color_Blue), 2730, -17));
+ size = flatcc_builder_get_buffer_size(B);
+ assert(size == 48);
+ printf("dbg: struct buffer size: %d\n", (int)size);
+ assert(flatcc_emitter_get_buffer_size(flatcc_builder_get_emit_context(B)) == size);
+ if (!flatcc_builder_copy_buffer(B, buffer, 100)) {
+ printf("Copy failed\n");
+ return -1;
+ }
+ hexdump("Vec3 struct buffer", buffer, size, stderr);
+ if (!nsc(has_identifier(buffer, "MONS"))) {
+ printf("wrong Vec3 identifier (explicit)\n");
+ return -1;
+ }
+ if (nsc(has_identifier(buffer, "mons"))) {
+ printf("accepted wrong Vec3 identifier (explicit)\n");
+ return -1;
+ }
+ if (!nsc(has_identifier(buffer, ns(Vec3_identifier)))) {
+ printf("wrong Vec3 identifier (via define)\n");
+ return -1;
+ }
+ vec3 = ns(Vec3_as_root(buffer));
+ /* Convert buffer to native in place - a nop on native platform. */
+ v = (ns(Vec3_t) *)vec3;
+ ns(Vec3_from_pe(v));
+ if (!parse_float_is_equal(v->x, 1.0f) || !parse_float_is_equal(v->y, 2.0f) || !parse_float_is_equal(v->z, 3.0f)
+ || !parse_double_is_equal(v->test1, 4.2) || v->test2 != ns(Color_Blue)
+ || v->test3.a != 2730 || v->test3.b != -17
+ ) {
+ printf("struct buffer not valid\n");
+ return -1;
+ }
+ assert(ns(Color_Red) == 1 << 0);
+ assert(ns(Color_Green) == 1 << 1);
+ assert(ns(Color_Blue) == 1 << 3);
+ assert(sizeof(ns(Color_Blue) == 1));
+ return 0;
+}
+
+int test_typed_struct_buffer(flatcc_builder_t *B)
+{
+ uint8_t buffer[100];
+
+ size_t size;
+ ns(Vec3_t) *v;
+ ns(Vec3_struct_t) vec3;
+
+ flatcc_builder_reset(B);
+ ns(Vec3_create_as_typed_root(B, 1, 2, 3, 4.2, ns(Color_Blue), 2730, -17));
+ size = flatcc_builder_get_buffer_size(B);
+ assert(size == 48);
+ printf("dbg: struct buffer size: %d\n", (int)size);
+ assert(flatcc_emitter_get_buffer_size(flatcc_builder_get_emit_context(B)) == size);
+ if (!flatcc_builder_copy_buffer(B, buffer, 100)) {
+ printf("Copy failed\n");
+ return -1;
+ }
+ hexdump("typed Vec3 struct buffer", buffer, size, stderr);
+ if (!nsc(has_identifier(buffer, "\xd2\x3e\xf5\xa8"))) {
+ printf("wrong Vec3 identifier (explicit)\n");
+ return -1;
+ }
+ if (nsc(has_identifier(buffer, "mons"))) {
+ printf("accepted wrong Vec3 identifier (explicit)\n");
+ return -1;
+ }
+ if (!nsc(has_identifier(buffer, ns(Vec3_type_identifier)))) {
+ printf("wrong Vec3 identifier (via define)\n");
+ return -1;
+ }
+ if (!ns(Vec3_as_root_with_type_hash(buffer, ns(Vec3_type_hash)))) {
+ printf("wrong Vec3 type identifier (via define)\n");
+ return -1;
+ }
+ if (flatcc_verify_ok != ns(Vec3_verify_as_root_with_type_hash(buffer, size, ns(Vec3_type_hash)))) {
+ printf("verify failed with Vec3 type hash\n");
+ return -1;
+ }
+ vec3 = ns(Vec3_as_typed_root(buffer));
+ if (!vec3) {
+ printf("typed Vec3 could not be read\n");
+ return -1;
+ }
+ if (flatcc_verify_ok != ns(Vec3_verify_as_typed_root(buffer, size))) {
+ printf("verify failed with Vec3 as typed root\n");
+ return -1;
+ }
+ /* Convert buffer to native in place - a nop on native platform. */
+ v = (ns(Vec3_t) *)vec3;
+ ns(Vec3_from_pe(v));
+ if (!parse_float_is_equal(v->x, 1.0f) || !parse_float_is_equal(v->y, 2.0f) || !parse_float_is_equal(v->z, 3.0f)
+ || !parse_double_is_equal(v->test1, 4.2) || v->test2 != ns(Color_Blue)
+ || v->test3.a != 2730 || v->test3.b != -17
+ ) {
+ printf("struct buffer not valid\n");
+ return -1;
+ }
+ assert(ns(Color_Red) == 1 << 0);
+ assert(ns(Color_Green) == 1 << 1);
+ assert(ns(Color_Blue) == 1 << 3);
+ assert(sizeof(ns(Color_Blue) == 1));
+ return 0;
+}
+
+
+/* A stable test snapshot for reference. */
+int gen_monster_benchmark(flatcc_builder_t *B)
+{
+ uint8_t inv[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ ns(Vec3_t) *vec;
+ ns(Test_t) *test, x;
+
+ flatcc_builder_reset(B);
+
+ ns(Monster_start_as_root(B));
+ ns(Monster_hp_add(B, 80));
+ vec = ns(Monster_pos_start(B));
+ vec->x = 1, vec->y = 2, vec->z = -3.2f;
+ ns(Monster_pos_end(B));
+ ns(Monster_name_create_str(B, "MyMonster"));
+ ns(Monster_inventory_create(B, inv, c_vec_len(inv)));
+ ns(Monster_test4_start(B));
+ test = ns(Monster_test4_extend(B, 1));
+ test->a = 0x10;
+ test->b = 0x20;
+ test = ns(Monster_test4_extend(B, 2));
+ test->a = 0x30;
+ test->b = 0x40;
+ test[1].a = 0x50;
+ test[1].b = 0x60;
+ ns(Monster_test4_push_create(B, 0x70, (int8_t)0x80));
+ x.a = 0x191; /* This is a short. */
+ x.b = (int8_t)0x91; /* This is a byte. */
+ ns(Monster_test4_push(B, &x));
+ ns(Monster_test4_end(B));
+ ns(Monster_end_as_root(B));
+
+ return 0;
+}
+
+int time_monster(flatcc_builder_t *B)
+{
+ double t1, t2;
+ const int rep = 1000000;
+ size_t size;
+ int i;
+
+ printf("start timing ...\n");
+ t1 = elapsed_realtime();
+ for (i = 0; i < rep; ++i) {
+ gen_monster_benchmark(B);
+ }
+ size = flatcc_builder_get_buffer_size(B);
+ t2 = elapsed_realtime();
+ show_benchmark("encode monster buffer", t1, t2, size, rep, "million");
+ return 0;
+}
+
+int gen_struct_buffer_benchmark(flatcc_builder_t *B)
+{
+ void *buffer;
+ ns(Vec3_t) *v;
+ ns(Vec3_struct_t) vec3;
+
+ flatcc_builder_reset(B);
+
+ ns(Vec3_create_as_root(B, 1, 2, 3, 4.2, ns(Color_Blue), 2730, -17));
+
+ buffer = flatcc_builder_get_direct_buffer(B, 0);
+ if (!buffer) {
+ return -1;
+ }
+ vec3 = ns(Vec3_as_root_with_identifier(buffer, 0));
+ /* Convert buffer to native in place - a nop on native platform. */
+ v = (ns(Vec3_t) *)vec3;
+ ns(Vec3_from_pe(v));
+ if (v->x != 1.0f || v->y != 2.0f || v->z != 3.0f
+ || v->test1 != 4.2 || v->test2 != ns(Color_Blue)
+ || v->test3.a != 2730 || v->test3.b != -17
+ ) {
+ return -1;
+ }
+ return 0;
+}
+
+int time_struct_buffer(flatcc_builder_t *B)
+{
+ double t1, t2;
+ const int rep = 1000000;
+ size_t size;
+ int i;
+ int ret = 0;
+
+ printf("start timing ...\n");
+ t1 = elapsed_realtime();
+ for (i = 0; i < rep; ++i) {
+ ret |= gen_struct_buffer_benchmark(B);
+ }
+ t2 = elapsed_realtime();
+ size = flatcc_builder_get_buffer_size(B);
+ if (ret) {
+ printf("struct not valid\n");
+ }
+ show_benchmark("encode, decode and access Vec struct buffers", t1, t2, size, rep, "million");
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ flatcc_builder_t builder, *B;
+
+ (void)argc;
+ (void)argv;
+
+ B = &builder;
+ flatcc_builder_init(B);
+
+#ifdef NDEBUG
+ printf("running optimized monster test\n");
+#else
+ printf("running debug monster test\n");
+#endif
+#if 1
+ if (test_enums(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_empty_monster(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_monster(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_monster_with_size(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_string(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_struct_buffer(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_typed_empty_monster(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_typed_struct_buffer(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_clone_slice(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_add_set_defaults(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_create_add_field(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_union_vector(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_basic_sort(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_sort_find(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_scan(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_nested_buffer(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_nested_buffer_first(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_nested_buffer_using_nest(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_cloned_monster(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (verify_include(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_type_aliases(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_mixed_type_union(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_recursive_sort(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+#if 1
+ if (test_fixed_length_array(B)) {
+ printf("TEST FAILED\n");
+ return -1;
+ }
+#endif
+
+#ifdef FLATBUFFERS_BENCHMARK
+ time_monster(B);
+ time_struct_buffer(B);
+#endif
+ flatcc_builder_clear(B);
+ return 0;
+}