2019-02-20 02:22:25 +07:00
|
|
|
/*
|
2014-01-27 16:52:49 -08:00
|
|
|
* Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
2022-04-19 13:06:50 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
2018-10-12 00:37:47 +07:00
|
|
|
#include <cmath>
|
2022-11-08 18:36:35 +01:00
|
|
|
#include <limits>
|
2022-08-08 21:22:57 -07:00
|
|
|
#include <memory>
|
2021-05-21 11:09:24 -07:00
|
|
|
#include <string>
|
2019-11-07 12:22:54 -08:00
|
|
|
|
2023-05-31 19:31:47 +00:00
|
|
|
#if defined(__ANDROID__)
|
2023-05-31 11:52:05 -07:00
|
|
|
#define INCLUDE_64_BIT_TESTS 0
|
|
|
|
|
#else
|
|
|
|
|
#define INCLUDE_64_BIT_TESTS 1
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-12-19 11:49:50 -08:00
|
|
|
#if __has_include("third_party/absl/container/flat_hash_set.h")
|
|
|
|
|
#define HAS_ABSL_CONTAINERS 1
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_ABSL_CONTAINERS
|
|
|
|
|
#include "third_party/absl/container/flat_hash_set.h"
|
|
|
|
|
#endif
|
2022-09-21 20:05:05 +02:00
|
|
|
#include "alignment_test.h"
|
2026-03-12 02:11:06 +00:00
|
|
|
#include "cross_namespace_pack_test_generated.h"
|
2025-12-19 14:32:51 -08:00
|
|
|
#include "default_vectors_strings_test.h"
|
2022-11-18 11:04:46 -08:00
|
|
|
#include "evolution_test.h"
|
2014-01-27 16:52:49 -08:00
|
|
|
#include "flatbuffers/flatbuffers.h"
|
|
|
|
|
#include "flatbuffers/idl.h"
|
2017-08-24 17:44:03 -07:00
|
|
|
#include "flatbuffers/minireflect.h"
|
2023-05-04 16:12:45 -07:00
|
|
|
#include "flatbuffers/reflection_generated.h"
|
2017-12-21 10:54:28 -08:00
|
|
|
#include "flatbuffers/registry.h"
|
|
|
|
|
#include "flatbuffers/util.h"
|
2022-08-28 16:54:58 -07:00
|
|
|
#include "fuzz_test.h"
|
|
|
|
|
#include "json_test.h"
|
2022-11-18 11:04:46 -08:00
|
|
|
#include "key_field_test.h"
|
2022-08-28 16:54:58 -07:00
|
|
|
#include "monster_test.h"
|
2014-01-27 16:52:49 -08:00
|
|
|
#include "monster_test_generated.h"
|
2022-08-30 03:48:10 +08:00
|
|
|
#include "native_inline_table_test_generated.h"
|
2022-11-18 11:04:46 -08:00
|
|
|
#include "optional_scalars_test.h"
|
2022-08-28 16:54:58 -07:00
|
|
|
#include "parser_test.h"
|
|
|
|
|
#include "proto_test.h"
|
|
|
|
|
#include "reflection_test.h"
|
2023-05-31 11:52:05 -07:00
|
|
|
#include "tests/union_vector/union_vector_generated.h"
|
2023-05-15 12:22:38 +08:00
|
|
|
#include "union_underlying_type_test_generated.h"
|
2019-06-18 00:15:13 +02:00
|
|
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
2025-09-23 21:19:33 -07:00
|
|
|
#include "tests/arrays_test_generated.h"
|
2023-05-31 11:52:05 -07:00
|
|
|
#endif
|
|
|
|
|
#if INCLUDE_64_BIT_TESTS
|
|
|
|
|
#include "tests/64bit/offset64_test.h"
|
2019-06-18 00:15:13 +02:00
|
|
|
#endif
|
2022-08-28 16:54:58 -07:00
|
|
|
#include "flexbuffers_test.h"
|
|
|
|
|
#include "is_quiet_nan.h"
|
2020-03-02 10:15:23 -08:00
|
|
|
#include "monster_test_bfbs_generated.h" // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
|
2021-05-15 12:54:08 -07:00
|
|
|
#include "native_type_test_generated.h"
|
|
|
|
|
#include "test_assert.h"
|
2022-08-28 16:54:58 -07:00
|
|
|
#include "util_test.h"
|
2025-12-07 14:05:54 -05:00
|
|
|
#include "vector_table_naked_ptr_test.h"
|
2016-02-01 18:00:30 -08:00
|
|
|
|
2022-08-17 01:48:41 +08:00
|
|
|
void FlatBufferBuilderTest();
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
namespace flatbuffers {
|
|
|
|
|
namespace tests {
|
2022-08-17 01:48:41 +08:00
|
|
|
namespace {
|
|
|
|
|
|
2021-11-19 17:01:48 -08:00
|
|
|
// clang-format off
|
2019-07-09 01:22:56 +07:00
|
|
|
// Check that char* and uint8_t* are interoperable types.
|
|
|
|
|
// The reinterpret_cast<> between the pointers are used to simplify data loading.
|
|
|
|
|
static_assert(flatbuffers::is_same<uint8_t, char>::value ||
|
|
|
|
|
flatbuffers::is_same<uint8_t, unsigned char>::value,
|
|
|
|
|
"unexpected uint8_t type");
|
|
|
|
|
|
|
|
|
|
#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
|
|
|
|
|
// Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
|
|
|
|
|
static_assert(std::numeric_limits<float>::is_iec559 &&
|
|
|
|
|
std::numeric_limits<double>::is_iec559,
|
|
|
|
|
"IEC-559 (IEEE-754) standard required");
|
|
|
|
|
#endif
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
using namespace MyGame::Example;
|
2018-10-12 00:37:47 +07:00
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
void TriviallyCopyableTest() {
|
2023-05-09 09:16:30 -07:00
|
|
|
// clang-format off
|
2022-08-28 16:54:58 -07:00
|
|
|
#if __GNUG__ && __GNUC__ < 5 && \
|
|
|
|
|
!(defined(__clang__) && __clang_major__ >= 16)
|
2023-11-18 00:19:03 -08:00
|
|
|
TEST_EQ(__is_trivially_copyable(Vec3), true);
|
2022-08-28 16:54:58 -07:00
|
|
|
#else
|
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
|
TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
// clang-format on
|
2018-10-12 00:37:47 +07:00
|
|
|
}
|
|
|
|
|
|
2022-10-18 21:37:06 +02:00
|
|
|
// Guard against -Wunused-function on platforms without file tests.
|
|
|
|
|
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
2025-09-23 21:19:33 -07:00
|
|
|
void GenerateTableTextTest(const std::string& tests_data_path) {
|
2019-04-05 11:51:29 -07:00
|
|
|
std::string schemafile;
|
|
|
|
|
std::string jsonfile;
|
|
|
|
|
bool ok =
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
|
2019-04-05 11:51:29 -07:00
|
|
|
false, &schemafile) &&
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::LoadFile((tests_data_path + "monsterdata_test.json").c_str(),
|
2019-04-05 11:51:29 -07:00
|
|
|
false, &jsonfile);
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
auto include_test_path =
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* include_directories[] = {tests_data_path.c_str(),
|
|
|
|
|
include_test_path.c_str(), nullptr};
|
2019-04-05 11:51:29 -07:00
|
|
|
flatbuffers::IDLOptions opt;
|
|
|
|
|
opt.indent_step = -1;
|
|
|
|
|
flatbuffers::Parser parser(opt);
|
|
|
|
|
ok = parser.Parse(schemafile.c_str(), include_directories) &&
|
|
|
|
|
parser.Parse(jsonfile.c_str(), include_directories);
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
// Test root table
|
2025-09-23 21:19:33 -07:00
|
|
|
const Monster* monster = GetMonster(parser.builder_.GetBufferPointer());
|
2021-01-08 02:24:59 +07:00
|
|
|
const auto abilities = monster->testarrayofsortedstruct();
|
|
|
|
|
TEST_EQ(abilities->size(), 3);
|
|
|
|
|
TEST_EQ(abilities->Get(0)->id(), 0);
|
|
|
|
|
TEST_EQ(abilities->Get(0)->distance(), 45);
|
|
|
|
|
TEST_EQ(abilities->Get(1)->id(), 1);
|
|
|
|
|
TEST_EQ(abilities->Get(1)->distance(), 21);
|
|
|
|
|
TEST_EQ(abilities->Get(2)->id(), 5);
|
|
|
|
|
TEST_EQ(abilities->Get(2)->distance(), 12);
|
|
|
|
|
|
2019-04-05 11:51:29 -07:00
|
|
|
std::string jsongen;
|
2025-09-23 21:19:33 -07:00
|
|
|
auto result =
|
|
|
|
|
GenTextFromTable(parser, monster, "MyGame.Example.Monster", &jsongen);
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(result);
|
2019-04-05 11:51:29 -07:00
|
|
|
// Test sub table
|
2025-09-23 21:19:33 -07:00
|
|
|
const Vec3* pos = monster->pos();
|
2019-04-05 11:51:29 -07:00
|
|
|
jsongen.clear();
|
2023-05-11 18:08:42 -07:00
|
|
|
result = GenTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(result);
|
2019-04-05 11:51:29 -07:00
|
|
|
TEST_EQ_STR(
|
|
|
|
|
jsongen.c_str(),
|
|
|
|
|
"{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
|
2025-09-23 21:19:33 -07:00
|
|
|
const Test& test3 = pos->test3();
|
2019-04-05 11:51:29 -07:00
|
|
|
jsongen.clear();
|
2025-09-23 21:19:33 -07:00
|
|
|
result = GenTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(result);
|
2019-04-05 11:51:29 -07:00
|
|
|
TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
|
2025-09-23 21:19:33 -07:00
|
|
|
const Test* test4 = monster->test4()->Get(0);
|
2019-04-05 11:51:29 -07:00
|
|
|
jsongen.clear();
|
2025-09-23 21:19:33 -07:00
|
|
|
result = GenTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(result);
|
2019-04-05 11:51:29 -07:00
|
|
|
TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
void MultiFileNameClashTest(const std::string& tests_data_path) {
|
2021-05-14 21:56:52 +01:00
|
|
|
const auto name_clash_path =
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::ConCatPathFileName(tests_data_path, "name_clash_test");
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* include_directories[] = {name_clash_path.c_str()};
|
2021-05-14 21:56:52 +01:00
|
|
|
|
|
|
|
|
// Load valid 2 file Flatbuffer schema
|
|
|
|
|
const auto valid_path =
|
|
|
|
|
flatbuffers::ConCatPathFileName(name_clash_path, "valid_test1.fbs");
|
|
|
|
|
std::string valid_schema;
|
|
|
|
|
TEST_ASSERT(flatbuffers::LoadFile(valid_path.c_str(), false, &valid_schema));
|
|
|
|
|
// Clashing table and union names in different namespaces must be parsable
|
|
|
|
|
TEST_ASSERT(
|
|
|
|
|
flatbuffers::Parser().Parse(valid_schema.c_str(), include_directories));
|
|
|
|
|
|
|
|
|
|
flatbuffers::Parser p;
|
|
|
|
|
TEST_ASSERT(p.Parse(valid_schema.c_str(), include_directories));
|
|
|
|
|
|
|
|
|
|
// Load invalid 2 file Flatbuffer schema
|
|
|
|
|
const auto invalid_path =
|
|
|
|
|
flatbuffers::ConCatPathFileName(name_clash_path, "invalid_test1.fbs");
|
|
|
|
|
std::string invalid_schema;
|
|
|
|
|
TEST_ASSERT(
|
|
|
|
|
flatbuffers::LoadFile(invalid_path.c_str(), false, &invalid_schema));
|
|
|
|
|
// Clashing table and union names in same namespace must fail to parse
|
|
|
|
|
TEST_EQ(
|
|
|
|
|
flatbuffers::Parser().Parse(invalid_schema.c_str(), include_directories),
|
|
|
|
|
false);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
void InvalidNestedFlatbufferTest(const std::string& tests_data_path) {
|
2019-03-04 22:35:10 +03:00
|
|
|
// First, load and parse FlatBuffer schema (.fbs)
|
|
|
|
|
std::string schemafile;
|
2022-08-28 16:54:58 -07:00
|
|
|
TEST_EQ(flatbuffers::LoadFile((tests_data_path + "monster_test.fbs").c_str(),
|
2019-03-04 22:35:10 +03:00
|
|
|
false, &schemafile),
|
|
|
|
|
true);
|
|
|
|
|
auto include_test_path =
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* include_directories[] = {tests_data_path.c_str(),
|
|
|
|
|
include_test_path.c_str(), nullptr};
|
2019-03-04 22:35:10 +03:00
|
|
|
flatbuffers::Parser parser1;
|
|
|
|
|
TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
|
|
|
|
|
|
|
|
|
|
// "color" inside nested flatbuffer contains invalid enum value
|
|
|
|
|
TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
|
|
|
|
|
"\"Leela\", color: \"nonexistent\"}}"),
|
|
|
|
|
false);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
void UnionVectorTest(const std::string& tests_data_path) {
|
2019-03-04 14:56:07 -08:00
|
|
|
// load FlatBuffer fbs schema and json.
|
|
|
|
|
std::string schemafile, jsonfile;
|
|
|
|
|
TEST_EQ(flatbuffers::LoadFile(
|
2022-08-28 16:54:58 -07:00
|
|
|
(tests_data_path + "union_vector/union_vector.fbs").c_str(),
|
|
|
|
|
false, &schemafile),
|
2019-03-04 14:56:07 -08:00
|
|
|
true);
|
2017-01-24 11:52:36 -08:00
|
|
|
TEST_EQ(flatbuffers::LoadFile(
|
2022-08-28 16:54:58 -07:00
|
|
|
(tests_data_path + "union_vector/union_vector.json").c_str(),
|
2019-03-04 14:56:07 -08:00
|
|
|
false, &jsonfile),
|
2017-12-21 10:54:28 -08:00
|
|
|
true);
|
2017-01-24 11:52:36 -08:00
|
|
|
|
|
|
|
|
// parse schema.
|
|
|
|
|
flatbuffers::IDLOptions idl_opts;
|
2019-03-04 14:56:07 -08:00
|
|
|
idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
|
2017-01-24 11:52:36 -08:00
|
|
|
flatbuffers::Parser parser(idl_opts);
|
2017-05-15 16:57:39 -07:00
|
|
|
TEST_EQ(parser.Parse(schemafile.c_str()), true);
|
2017-01-24 11:52:36 -08:00
|
|
|
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
|
|
|
|
|
// union types.
|
|
|
|
|
std::vector<uint8_t> types;
|
|
|
|
|
types.push_back(static_cast<uint8_t>(Character_Belle));
|
|
|
|
|
types.push_back(static_cast<uint8_t>(Character_MuLan));
|
2017-04-10 15:56:51 -07:00
|
|
|
types.push_back(static_cast<uint8_t>(Character_BookFan));
|
|
|
|
|
types.push_back(static_cast<uint8_t>(Character_Other));
|
|
|
|
|
types.push_back(static_cast<uint8_t>(Character_Unused));
|
2017-01-24 11:52:36 -08:00
|
|
|
|
|
|
|
|
// union values.
|
|
|
|
|
std::vector<flatbuffers::Offset<void>> characters;
|
2017-04-10 15:56:51 -07:00
|
|
|
characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
|
|
|
|
|
characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
|
|
|
|
|
characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
|
|
|
|
|
characters.push_back(fbb.CreateString("Other").Union());
|
|
|
|
|
characters.push_back(fbb.CreateString("Unused").Union());
|
2017-01-24 11:52:36 -08:00
|
|
|
|
|
|
|
|
// create Movie.
|
|
|
|
|
const auto movie_offset =
|
2017-12-21 10:54:28 -08:00
|
|
|
CreateMovie(fbb, Character_Rapunzel,
|
2017-04-10 15:56:51 -07:00
|
|
|
fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
|
2017-12-21 10:54:28 -08:00
|
|
|
fbb.CreateVector(types), fbb.CreateVector(characters));
|
2017-01-24 11:52:36 -08:00
|
|
|
FinishMovieBuffer(fbb, movie_offset);
|
|
|
|
|
|
2019-09-16 17:48:54 -07:00
|
|
|
flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
|
2017-01-24 11:52:36 -08:00
|
|
|
TEST_EQ(VerifyMovieBuffer(verifier), true);
|
|
|
|
|
|
2019-09-16 17:48:54 -07:00
|
|
|
auto flat_movie = GetMovie(fbb.GetBufferPointer());
|
2017-04-10 15:56:51 -07:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
auto TestMovie = [](const Movie* movie) {
|
2017-04-10 15:56:51 -07:00
|
|
|
TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
|
|
|
|
|
|
|
|
|
|
auto cts = movie->characters_type();
|
|
|
|
|
TEST_EQ(movie->characters_type()->size(), 5);
|
|
|
|
|
TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
|
|
|
|
|
TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
|
|
|
|
|
TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
|
|
|
|
|
TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
|
|
|
|
|
TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
|
|
|
|
|
|
|
|
|
|
auto rapunzel = movie->main_character_as_Rapunzel();
|
2019-01-18 00:49:27 +07:00
|
|
|
TEST_NOTNULL(rapunzel);
|
2017-04-10 15:56:51 -07:00
|
|
|
TEST_EQ(rapunzel->hair_length(), 6);
|
|
|
|
|
|
|
|
|
|
auto cs = movie->characters();
|
|
|
|
|
TEST_EQ(cs->size(), 5);
|
|
|
|
|
auto belle = cs->GetAs<BookReader>(0);
|
|
|
|
|
TEST_EQ(belle->books_read(), 7);
|
|
|
|
|
auto mu_lan = cs->GetAs<Attacker>(1);
|
|
|
|
|
TEST_EQ(mu_lan->sword_attack_damage(), 5);
|
|
|
|
|
auto book_fan = cs->GetAs<BookReader>(2);
|
|
|
|
|
TEST_EQ(book_fan->books_read(), 2);
|
|
|
|
|
auto other = cs->GetAsString(3);
|
|
|
|
|
TEST_EQ_STR(other->c_str(), "Other");
|
|
|
|
|
auto unused = cs->GetAsString(4);
|
|
|
|
|
TEST_EQ_STR(unused->c_str(), "Unused");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TestMovie(flat_movie);
|
|
|
|
|
|
2019-03-04 14:56:07 -08:00
|
|
|
// Also test the JSON we loaded above.
|
|
|
|
|
TEST_EQ(parser.Parse(jsonfile.c_str()), true);
|
|
|
|
|
auto jbuf = parser.builder_.GetBufferPointer();
|
|
|
|
|
flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
|
|
|
|
|
TEST_EQ(VerifyMovieBuffer(jverifier), true);
|
|
|
|
|
TestMovie(GetMovie(jbuf));
|
|
|
|
|
|
2017-04-10 15:56:51 -07:00
|
|
|
auto movie_object = flat_movie->UnPack();
|
|
|
|
|
TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
|
|
|
|
|
TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
|
|
|
|
|
TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
|
|
|
|
|
TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
|
|
|
|
|
TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
|
|
|
|
|
TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
|
|
|
|
|
|
|
|
|
|
fbb.Clear();
|
|
|
|
|
fbb.Finish(Movie::Pack(fbb, movie_object));
|
|
|
|
|
|
2017-08-11 12:24:33 -07:00
|
|
|
delete movie_object;
|
|
|
|
|
|
2017-04-10 15:56:51 -07:00
|
|
|
auto repacked_movie = GetMovie(fbb.GetBufferPointer());
|
|
|
|
|
|
|
|
|
|
TestMovie(repacked_movie);
|
2017-08-24 17:44:03 -07:00
|
|
|
|
2019-09-16 14:43:35 -07:00
|
|
|
// Generate text using mini-reflection.
|
2017-12-21 10:54:28 -08:00
|
|
|
auto s =
|
|
|
|
|
flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
|
|
|
|
|
TEST_EQ_STR(
|
|
|
|
|
s.c_str(),
|
|
|
|
|
"{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
|
|
|
|
|
"characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
|
|
|
|
|
"characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
|
|
|
|
|
"{ books_read: 2 }, \"Other\", \"Unused\" ] }");
|
2018-09-24 18:29:49 +02:00
|
|
|
|
|
|
|
|
flatbuffers::ToStringVisitor visitor("\n", true, " ");
|
|
|
|
|
IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
|
2019-11-07 12:22:54 -08:00
|
|
|
TEST_EQ_STR(visitor.s.c_str(),
|
|
|
|
|
"{\n"
|
|
|
|
|
" \"main_character_type\": \"Rapunzel\",\n"
|
|
|
|
|
" \"main_character\": {\n"
|
|
|
|
|
" \"hair_length\": 6\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" \"characters_type\": [\n"
|
|
|
|
|
" \"Belle\",\n"
|
|
|
|
|
" \"MuLan\",\n"
|
|
|
|
|
" \"BookFan\",\n"
|
|
|
|
|
" \"Other\",\n"
|
|
|
|
|
" \"Unused\"\n"
|
|
|
|
|
" ],\n"
|
|
|
|
|
" \"characters\": [\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" \"books_read\": 7\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" \"sword_attack_damage\": 5\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" \"books_read\": 2\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" \"Other\",\n"
|
|
|
|
|
" \"Unused\"\n"
|
|
|
|
|
" ]\n"
|
|
|
|
|
"}");
|
2019-03-04 14:56:07 -08:00
|
|
|
|
2019-09-16 14:43:35 -07:00
|
|
|
// Generate text using parsed schema.
|
|
|
|
|
std::string jsongen;
|
2023-05-11 18:08:42 -07:00
|
|
|
auto result = GenText(parser, fbb.GetBufferPointer(), &jsongen);
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(result);
|
2019-11-07 12:22:54 -08:00
|
|
|
TEST_EQ_STR(jsongen.c_str(),
|
|
|
|
|
"{\n"
|
|
|
|
|
" main_character_type: \"Rapunzel\",\n"
|
|
|
|
|
" main_character: {\n"
|
|
|
|
|
" hair_length: 6\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" characters_type: [\n"
|
|
|
|
|
" \"Belle\",\n"
|
|
|
|
|
" \"MuLan\",\n"
|
|
|
|
|
" \"BookFan\",\n"
|
|
|
|
|
" \"Other\",\n"
|
|
|
|
|
" \"Unused\"\n"
|
|
|
|
|
" ],\n"
|
|
|
|
|
" characters: [\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" books_read: 7\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" sword_attack_damage: 5\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" {\n"
|
|
|
|
|
" books_read: 2\n"
|
|
|
|
|
" },\n"
|
|
|
|
|
" \"Other\",\n"
|
|
|
|
|
" \"Unused\"\n"
|
|
|
|
|
" ]\n"
|
|
|
|
|
"}\n");
|
2019-09-16 14:43:35 -07:00
|
|
|
|
2019-09-16 17:48:54 -07:00
|
|
|
// Simple test with reflection.
|
|
|
|
|
parser.Serialize();
|
|
|
|
|
auto schema = reflection::GetSchema(parser.builder_.GetBufferPointer());
|
|
|
|
|
auto ok = flatbuffers::Verify(*schema, *schema->root_table(),
|
|
|
|
|
fbb.GetBufferPointer(), fbb.GetSize());
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
|
2019-03-04 14:56:07 -08:00
|
|
|
flatbuffers::Parser parser2(idl_opts);
|
|
|
|
|
TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
|
|
|
|
|
"union Any { Bool }"
|
|
|
|
|
"table Root { a:Any; }"
|
2019-11-07 12:22:54 -08:00
|
|
|
"root_type Root;"),
|
|
|
|
|
true);
|
2019-03-04 14:56:07 -08:00
|
|
|
TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
|
2017-01-24 11:52:36 -08:00
|
|
|
}
|
2022-10-18 21:37:06 +02:00
|
|
|
#endif
|
2017-01-24 11:52:36 -08:00
|
|
|
|
2017-11-16 14:19:31 -08:00
|
|
|
void EndianSwapTest() {
|
2017-12-21 10:54:28 -08:00
|
|
|
TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
|
2017-11-16 14:19:31 -08:00
|
|
|
TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
|
|
|
|
|
0x78563412);
|
|
|
|
|
TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
|
|
|
|
|
0xEFCDAB9078563412);
|
|
|
|
|
TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-18 22:42:26 +05:30
|
|
|
void UninitializedVectorTest() {
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
2018-07-16 15:51:01 -07:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
Test* buf = nullptr;
|
2019-11-07 12:22:54 -08:00
|
|
|
auto vector_offset =
|
|
|
|
|
builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
|
2018-06-18 22:42:26 +05:30
|
|
|
TEST_NOTNULL(buf);
|
|
|
|
|
buf[0] = Test(10, 20);
|
|
|
|
|
buf[1] = Test(30, 40);
|
2018-07-16 15:51:01 -07:00
|
|
|
|
2018-06-18 22:42:26 +05:30
|
|
|
auto required_name = builder.CreateString("myMonster");
|
|
|
|
|
auto monster_builder = MonsterBuilder(builder);
|
2019-11-07 12:22:54 -08:00
|
|
|
monster_builder.add_name(
|
|
|
|
|
required_name); // required field mandated for monster.
|
2018-06-18 22:42:26 +05:30
|
|
|
monster_builder.add_test4(vector_offset);
|
|
|
|
|
builder.Finish(monster_builder.Finish());
|
2018-07-16 15:51:01 -07:00
|
|
|
|
2018-06-18 22:42:26 +05:30
|
|
|
auto p = builder.GetBufferPointer();
|
|
|
|
|
auto uvt = flatbuffers::GetRoot<Monster>(p);
|
|
|
|
|
TEST_NOTNULL(uvt);
|
|
|
|
|
auto vec = uvt->test4();
|
|
|
|
|
TEST_NOTNULL(vec);
|
|
|
|
|
auto test_0 = vec->Get(0);
|
|
|
|
|
auto test_1 = vec->Get(1);
|
|
|
|
|
TEST_EQ(test_0->a(), 10);
|
|
|
|
|
TEST_EQ(test_0->b(), 20);
|
|
|
|
|
TEST_EQ(test_1->a(), 30);
|
|
|
|
|
TEST_EQ(test_1->b(), 40);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 01:53:59 +02:00
|
|
|
void EqualOperatorTest() {
|
|
|
|
|
MonsterT a;
|
|
|
|
|
MonsterT b;
|
2022-11-08 10:59:46 -08:00
|
|
|
// We have to reset the fields that are NaN to zero to allow the equality
|
|
|
|
|
// to evaluate to true.
|
|
|
|
|
TEST_EQ(std::isnan(a.nan_default), true);
|
|
|
|
|
TEST_EQ(std::isnan(b.nan_default), true);
|
|
|
|
|
a.nan_default = 0;
|
|
|
|
|
b.nan_default = 0;
|
2018-09-22 01:53:59 +02:00
|
|
|
TEST_EQ(b == a, true);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, false);
|
2018-09-22 01:53:59 +02:00
|
|
|
|
|
|
|
|
b.mana = 33;
|
|
|
|
|
TEST_EQ(b == a, false);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, true);
|
2018-09-22 01:53:59 +02:00
|
|
|
b.mana = 150;
|
|
|
|
|
TEST_EQ(b == a, true);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, false);
|
2018-09-22 01:53:59 +02:00
|
|
|
|
|
|
|
|
b.inventory.push_back(3);
|
|
|
|
|
TEST_EQ(b == a, false);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, true);
|
2018-09-22 01:53:59 +02:00
|
|
|
b.inventory.clear();
|
|
|
|
|
TEST_EQ(b == a, true);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, false);
|
2018-09-22 01:53:59 +02:00
|
|
|
|
2021-06-21 21:37:56 +03:00
|
|
|
a.enemy.reset(new MonsterT());
|
2022-11-08 10:59:46 -08:00
|
|
|
a.enemy->nan_default = 0;
|
2021-06-21 21:37:56 +03:00
|
|
|
TEST_EQ(b != a, true);
|
|
|
|
|
a.enemy->mana = 33;
|
|
|
|
|
TEST_EQ(b == a, false);
|
|
|
|
|
TEST_EQ(b != a, true);
|
|
|
|
|
|
|
|
|
|
b.enemy.reset(new MonsterT());
|
2022-11-08 10:59:46 -08:00
|
|
|
b.enemy->nan_default = 0;
|
2021-06-21 21:37:56 +03:00
|
|
|
TEST_EQ(b == a, false);
|
|
|
|
|
TEST_EQ(b != a, true);
|
|
|
|
|
b.enemy->mana = 33;
|
|
|
|
|
TEST_EQ(b == a, true);
|
|
|
|
|
TEST_EQ(b != a, false);
|
|
|
|
|
|
|
|
|
|
a.enemy.reset(nullptr);
|
|
|
|
|
TEST_EQ(b == a, false);
|
|
|
|
|
TEST_EQ(b != a, true);
|
|
|
|
|
b.enemy->mana = 150;
|
|
|
|
|
TEST_EQ(b == a, false);
|
|
|
|
|
TEST_EQ(b != a, true);
|
|
|
|
|
a.enemy.reset(new MonsterT());
|
2022-11-08 10:59:46 -08:00
|
|
|
a.enemy->nan_default = 0;
|
2021-06-21 21:37:56 +03:00
|
|
|
TEST_EQ(b == a, true);
|
|
|
|
|
TEST_EQ(b != a, false);
|
|
|
|
|
|
|
|
|
|
b.enemy.reset(nullptr);
|
|
|
|
|
|
2018-09-22 01:53:59 +02:00
|
|
|
b.test.type = Any_Monster;
|
|
|
|
|
TEST_EQ(b == a, false);
|
2019-03-25 20:04:51 +01:00
|
|
|
TEST_EQ(b != a, true);
|
2022-08-08 21:22:57 -07:00
|
|
|
|
|
|
|
|
// Test that vector of tables are compared by value and not by reference.
|
|
|
|
|
{
|
|
|
|
|
// Two tables are equal by default.
|
|
|
|
|
MonsterT a, b;
|
2022-11-08 10:59:46 -08:00
|
|
|
a.nan_default = 0;
|
|
|
|
|
b.nan_default = 0;
|
2022-08-08 21:22:57 -07:00
|
|
|
TEST_EQ(a == b, true);
|
|
|
|
|
|
|
|
|
|
// Adding only a table to one of the monster vectors should make it not
|
|
|
|
|
// equal (due to size mistmatch).
|
|
|
|
|
a.testarrayoftables.push_back(
|
|
|
|
|
flatbuffers::unique_ptr<MonsterT>(new MonsterT));
|
2022-11-08 10:59:46 -08:00
|
|
|
a.testarrayoftables.back()->nan_default = 0;
|
2022-08-08 21:22:57 -07:00
|
|
|
TEST_EQ(a == b, false);
|
|
|
|
|
|
|
|
|
|
// Adding an equalivant table to the other monster vector should make it
|
|
|
|
|
// equal again.
|
|
|
|
|
b.testarrayoftables.push_back(
|
|
|
|
|
flatbuffers::unique_ptr<MonsterT>(new MonsterT));
|
2022-11-08 10:59:46 -08:00
|
|
|
b.testarrayoftables.back()->nan_default = 0;
|
2022-08-08 21:22:57 -07:00
|
|
|
TEST_EQ(a == b, true);
|
|
|
|
|
|
|
|
|
|
// Create two new monsters that are different.
|
|
|
|
|
auto c = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
|
|
|
|
|
auto d = flatbuffers::unique_ptr<MonsterT>(new MonsterT);
|
2022-11-08 10:59:46 -08:00
|
|
|
c->nan_default = 0;
|
|
|
|
|
d->nan_default = 0;
|
2022-08-08 21:22:57 -07:00
|
|
|
c->hp = 1;
|
|
|
|
|
d->hp = 2;
|
|
|
|
|
TEST_EQ(c == d, false);
|
|
|
|
|
|
|
|
|
|
// Adding them to the original monsters should also make them different.
|
|
|
|
|
a.testarrayoftables.push_back(std::move(c));
|
|
|
|
|
b.testarrayoftables.push_back(std::move(d));
|
|
|
|
|
TEST_EQ(a == b, false);
|
|
|
|
|
|
|
|
|
|
// Remove the mismatching monsters to get back to equality
|
|
|
|
|
a.testarrayoftables.pop_back();
|
|
|
|
|
b.testarrayoftables.pop_back();
|
|
|
|
|
TEST_EQ(a == b, true);
|
|
|
|
|
|
|
|
|
|
// Check that nullptr are OK.
|
|
|
|
|
a.testarrayoftables.push_back(nullptr);
|
|
|
|
|
b.testarrayoftables.push_back(
|
|
|
|
|
flatbuffers::unique_ptr<MonsterT>(new MonsterT));
|
|
|
|
|
TEST_EQ(a == b, false);
|
|
|
|
|
}
|
2018-09-22 01:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-03 09:48:50 -08:00
|
|
|
void CreateSharedStringTest() {
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
const auto one1 = builder.CreateSharedString("one");
|
|
|
|
|
const auto two = builder.CreateSharedString("two");
|
|
|
|
|
const auto one2 = builder.CreateSharedString("one");
|
|
|
|
|
TEST_EQ(one1.o, one2.o);
|
|
|
|
|
const auto onetwo = builder.CreateSharedString("onetwo");
|
|
|
|
|
TEST_EQ(onetwo.o != one1.o, true);
|
|
|
|
|
TEST_EQ(onetwo.o != two.o, true);
|
|
|
|
|
|
|
|
|
|
// Support for embedded nulls
|
2025-09-23 21:19:33 -07:00
|
|
|
const char chars_b[] = {'a', '\0', 'b'};
|
|
|
|
|
const char chars_c[] = {'a', '\0', 'c'};
|
2018-12-03 09:48:50 -08:00
|
|
|
const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
|
|
|
|
|
const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
|
|
|
|
|
const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
|
2019-11-07 12:22:54 -08:00
|
|
|
TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
|
2018-12-03 09:48:50 -08:00
|
|
|
TEST_EQ(null_b1.o, null_b2.o);
|
|
|
|
|
|
|
|
|
|
// Put the strings into an array for round trip verification.
|
2022-02-09 22:16:46 -08:00
|
|
|
std::array<flatbuffers::Offset<flatbuffers::String>, 7> array = {
|
2025-09-23 21:19:33 -07:00
|
|
|
one1, two, one2, onetwo, null_b1, null_c, null_b2};
|
2019-11-07 12:22:54 -08:00
|
|
|
const auto vector_offset =
|
2022-02-09 22:16:46 -08:00
|
|
|
builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(array);
|
2018-12-03 09:48:50 -08:00
|
|
|
MonsterBuilder monster_builder(builder);
|
|
|
|
|
monster_builder.add_name(two);
|
|
|
|
|
monster_builder.add_testarrayofstring(vector_offset);
|
|
|
|
|
builder.Finish(monster_builder.Finish());
|
|
|
|
|
|
|
|
|
|
// Read the Monster back.
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto* monster =
|
2019-11-07 12:22:54 -08:00
|
|
|
flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
|
2018-12-03 09:48:50 -08:00
|
|
|
TEST_EQ_STR(monster->name()->c_str(), "two");
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto* testarrayofstring = monster->testarrayofstring();
|
2018-12-03 09:48:50 -08:00
|
|
|
TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& a = *testarrayofstring;
|
2018-12-03 09:48:50 -08:00
|
|
|
TEST_EQ_STR(a[0]->c_str(), "one");
|
|
|
|
|
TEST_EQ_STR(a[1]->c_str(), "two");
|
|
|
|
|
TEST_EQ_STR(a[2]->c_str(), "one");
|
|
|
|
|
TEST_EQ_STR(a[3]->c_str(), "onetwo");
|
|
|
|
|
TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
|
|
|
|
|
TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
|
|
|
|
|
TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
|
|
|
|
|
|
2019-11-07 12:22:54 -08:00
|
|
|
// Make sure String::operator< works, too, since it is related to
|
|
|
|
|
// StringOffsetCompare.
|
2018-12-03 09:48:50 -08:00
|
|
|
TEST_EQ((*a[0]) < (*a[1]), true);
|
|
|
|
|
TEST_EQ((*a[1]) < (*a[0]), false);
|
|
|
|
|
TEST_EQ((*a[1]) < (*a[2]), false);
|
|
|
|
|
TEST_EQ((*a[2]) < (*a[1]), true);
|
|
|
|
|
TEST_EQ((*a[4]) < (*a[3]), true);
|
|
|
|
|
TEST_EQ((*a[5]) < (*a[4]), false);
|
|
|
|
|
TEST_EQ((*a[5]) < (*a[4]), false);
|
|
|
|
|
TEST_EQ((*a[6]) < (*a[5]), true);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 13:53:38 -07:00
|
|
|
#if !defined(FLATBUFFERS_USE_STD_SPAN) && !defined(FLATBUFFERS_SPAN_MINIMAL)
|
2020-10-13 02:24:18 +07:00
|
|
|
void FlatbuffersSpanTest() {
|
|
|
|
|
// Compile-time checking of non-const [] to const [] conversions.
|
2022-08-26 14:35:21 -07:00
|
|
|
using flatbuffers::internal::is_span_convertible;
|
|
|
|
|
(void)is_span_convertible<int, 1, int, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const int, 1, int, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const int64_t, 1, int64_t, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const uint64_t, 1, uint64_t, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const int, 1, const int, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const int64_t, 1, const int64_t, 1>::type(123);
|
|
|
|
|
(void)is_span_convertible<const uint64_t, 1, const uint64_t, 1>::type(123);
|
2020-10-13 02:24:18 +07:00
|
|
|
|
|
|
|
|
using flatbuffers::span;
|
|
|
|
|
span<char, 0> c1;
|
|
|
|
|
TEST_EQ(c1.size(), 0);
|
|
|
|
|
span<char, flatbuffers::dynamic_extent> c2;
|
|
|
|
|
TEST_EQ(c2.size(), 0);
|
|
|
|
|
span<char> c3;
|
|
|
|
|
TEST_EQ(c3.size(), 0);
|
|
|
|
|
TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
int i_data7[7] = {0, 1, 2, 3, 4, 5, 6};
|
2020-10-13 02:24:18 +07:00
|
|
|
span<int, 7> i1(&i_data7[0], 7);
|
|
|
|
|
span<int> i2(i1); // make dynamic from static
|
|
|
|
|
TEST_EQ(i1.size(), 7);
|
|
|
|
|
TEST_EQ(i1.empty(), false);
|
|
|
|
|
TEST_EQ(i1.size(), i2.size());
|
|
|
|
|
TEST_EQ(i1.data(), i_data7);
|
|
|
|
|
TEST_EQ(i1[2], 2);
|
|
|
|
|
// Make const span from a non-const one.
|
|
|
|
|
span<const int, 7> i3(i1);
|
|
|
|
|
// Construct from a C-array.
|
|
|
|
|
span<int, 7> i4(i_data7);
|
|
|
|
|
span<const int, 7> i5(i_data7);
|
|
|
|
|
span<int> i6(i_data7);
|
|
|
|
|
span<const int> i7(i_data7);
|
|
|
|
|
TEST_EQ(i7.size(), 7);
|
|
|
|
|
// Check construction from a const array.
|
2025-09-23 21:19:33 -07:00
|
|
|
const int i_cdata5[5] = {4, 3, 2, 1, 0};
|
2020-10-13 02:24:18 +07:00
|
|
|
span<const int, 5> i8(i_cdata5);
|
|
|
|
|
span<const int> i9(i_cdata5);
|
|
|
|
|
TEST_EQ(i9.size(), 5);
|
|
|
|
|
// Construction from a (ptr, size) pair.
|
|
|
|
|
span<int, 7> i10(i_data7, 7);
|
|
|
|
|
span<int> i11(i_data7, 7);
|
|
|
|
|
TEST_EQ(i11.size(), 7);
|
|
|
|
|
span<const int, 5> i12(i_cdata5, 5);
|
|
|
|
|
span<const int> i13(i_cdata5, 5);
|
|
|
|
|
TEST_EQ(i13.size(), 5);
|
|
|
|
|
// Construction from std::array.
|
2025-09-23 21:19:33 -07:00
|
|
|
std::array<int, 6> i_arr6 = {{0, 1, 2, 3, 4, 5}};
|
2020-10-13 02:24:18 +07:00
|
|
|
span<int, 6> i14(i_arr6);
|
|
|
|
|
span<const int, 6> i15(i_arr6);
|
|
|
|
|
span<int> i16(i_arr6);
|
|
|
|
|
span<const int> i17(i_arr6);
|
|
|
|
|
TEST_EQ(i17.size(), 6);
|
2025-09-23 21:19:33 -07:00
|
|
|
const std::array<int, 8> i_carr8 = {{0, 1, 2, 3, 4, 5, 6, 7}};
|
2020-10-13 02:24:18 +07:00
|
|
|
span<const int, 8> i18(i_carr8);
|
|
|
|
|
span<const int> i19(i_carr8);
|
|
|
|
|
TEST_EQ(i18.size(), 8);
|
|
|
|
|
TEST_EQ(i19.size(), 8);
|
|
|
|
|
TEST_EQ(i19[7], 7);
|
|
|
|
|
// Check compatibility with flatbuffers::Array.
|
2025-09-23 21:19:33 -07:00
|
|
|
int fbs_int3_underlaying[3] = {0};
|
|
|
|
|
int fbs_int3_data[3] = {1, 2, 3};
|
|
|
|
|
auto& fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
|
2020-10-13 02:24:18 +07:00
|
|
|
fbs_int3.CopyFromSpan(fbs_int3_data);
|
|
|
|
|
TEST_EQ(fbs_int3.Get(1), 2);
|
2025-09-23 21:19:33 -07:00
|
|
|
const int fbs_cint3_data[3] = {2, 3, 4};
|
2020-10-13 02:24:18 +07:00
|
|
|
fbs_int3.CopyFromSpan(fbs_cint3_data);
|
|
|
|
|
TEST_EQ(fbs_int3.Get(1), 3);
|
|
|
|
|
// Check with Array<Enum, N>
|
|
|
|
|
enum class Dummy : uint16_t { Zero = 0, One, Two };
|
|
|
|
|
Dummy fbs_dummy3_underlaying[3] = {};
|
2025-09-23 21:19:33 -07:00
|
|
|
Dummy fbs_dummy3_data[3] = {Dummy::One, Dummy::Two, Dummy::Two};
|
|
|
|
|
auto& fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
|
2020-10-13 02:24:18 +07:00
|
|
|
fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
|
|
|
|
|
TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
void FlatbuffersSpanTest() {}
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-06-29 00:22:02 +07:00
|
|
|
// VS10 does not support typed enums, exclude from tests
|
2019-06-18 00:15:13 +02:00
|
|
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
2021-06-29 00:22:02 +07:00
|
|
|
void FixedLengthArrayTest() {
|
2019-06-18 00:15:13 +02:00
|
|
|
// Generate an ArrayTable containing one ArrayStruct.
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
|
|
|
|
|
TEST_NOTNULL(nStruct0.mutable_a());
|
|
|
|
|
nStruct0.mutable_a()->Mutate(0, 1);
|
|
|
|
|
nStruct0.mutable_a()->Mutate(1, 2);
|
|
|
|
|
TEST_NOTNULL(nStruct0.mutable_c());
|
|
|
|
|
nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
|
|
|
|
|
nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
|
2019-08-23 19:46:47 +02:00
|
|
|
TEST_NOTNULL(nStruct0.mutable_d());
|
|
|
|
|
nStruct0.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::max());
|
|
|
|
|
nStruct0.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::min());
|
2019-06-18 00:15:13 +02:00
|
|
|
MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
|
|
|
|
|
TEST_NOTNULL(nStruct1.mutable_a());
|
|
|
|
|
nStruct1.mutable_a()->Mutate(0, 3);
|
|
|
|
|
nStruct1.mutable_a()->Mutate(1, 4);
|
|
|
|
|
TEST_NOTNULL(nStruct1.mutable_c());
|
|
|
|
|
nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
|
|
|
|
|
nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
|
2019-08-23 19:46:47 +02:00
|
|
|
TEST_NOTNULL(nStruct1.mutable_d());
|
|
|
|
|
nStruct1.mutable_d()->Mutate(0, flatbuffers::numeric_limits<int64_t>::min());
|
|
|
|
|
nStruct1.mutable_d()->Mutate(1, flatbuffers::numeric_limits<int64_t>::max());
|
|
|
|
|
MyGame::Example::ArrayStruct aStruct(2, 12, 1);
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_NOTNULL(aStruct.b());
|
|
|
|
|
TEST_NOTNULL(aStruct.mutable_b());
|
|
|
|
|
TEST_NOTNULL(aStruct.mutable_d());
|
2019-08-23 19:46:47 +02:00
|
|
|
TEST_NOTNULL(aStruct.mutable_f());
|
2019-06-18 00:15:13 +02:00
|
|
|
for (int i = 0; i < aStruct.b()->size(); i++)
|
|
|
|
|
aStruct.mutable_b()->Mutate(i, i + 1);
|
|
|
|
|
aStruct.mutable_d()->Mutate(0, nStruct0);
|
|
|
|
|
aStruct.mutable_d()->Mutate(1, nStruct1);
|
|
|
|
|
auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
|
2020-09-01 00:02:13 +05:30
|
|
|
MyGame::Example::FinishArrayTableBuffer(fbb, aTable);
|
2019-06-18 00:15:13 +02:00
|
|
|
// Verify correctness of the ArrayTable.
|
|
|
|
|
flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
|
2021-06-29 00:22:02 +07:00
|
|
|
TEST_ASSERT(MyGame::Example::VerifyArrayTableBuffer(verifier));
|
|
|
|
|
// Do test.
|
2019-06-18 00:15:13 +02:00
|
|
|
auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
|
|
|
|
|
auto mArStruct = p->mutable_a();
|
|
|
|
|
TEST_NOTNULL(mArStruct);
|
|
|
|
|
TEST_NOTNULL(mArStruct->b());
|
|
|
|
|
TEST_NOTNULL(mArStruct->d());
|
2019-08-23 19:46:47 +02:00
|
|
|
TEST_NOTNULL(mArStruct->f());
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_NOTNULL(mArStruct->mutable_b());
|
|
|
|
|
TEST_NOTNULL(mArStruct->mutable_d());
|
2019-08-23 19:46:47 +02:00
|
|
|
TEST_NOTNULL(mArStruct->mutable_f());
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_EQ(mArStruct->a(), 2);
|
|
|
|
|
TEST_EQ(mArStruct->b()->size(), 15);
|
2021-06-29 00:22:02 +07:00
|
|
|
mArStruct->mutable_b()->Mutate(14, -14);
|
|
|
|
|
TEST_EQ(mArStruct->b()->Get(14), -14);
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_EQ(mArStruct->c(), 12);
|
2019-09-23 23:31:51 +07:00
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(0));
|
|
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(0)->a());
|
|
|
|
|
TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1);
|
|
|
|
|
TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2);
|
|
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(1));
|
|
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(1)->a());
|
|
|
|
|
TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3);
|
|
|
|
|
TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4);
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
|
|
|
|
|
TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
|
|
|
|
|
mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
|
2019-11-26 03:56:47 +07:00
|
|
|
TEST_EQ(5, mArStruct->d()->Get(1)->a()->Get(1));
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::B, mArStruct->d()->Get(0)->b());
|
2019-09-23 23:31:51 +07:00
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(0)->c());
|
2019-11-26 03:56:47 +07:00
|
|
|
TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(0)->c()->Get(0));
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(0)->c()->Get(1));
|
|
|
|
|
TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
|
|
|
|
|
mArStruct->d()->Get(0)->d()->Get(0));
|
|
|
|
|
TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
|
|
|
|
|
mArStruct->d()->Get(0)->d()->Get(1));
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->b());
|
2019-09-23 23:31:51 +07:00
|
|
|
TEST_NOTNULL(mArStruct->d()->Get(1)->c());
|
2019-11-26 03:56:47 +07:00
|
|
|
TEST_EQ(MyGame::Example::TestEnum::C, mArStruct->d()->Get(1)->c()->Get(0));
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::A, mArStruct->d()->Get(1)->c()->Get(1));
|
|
|
|
|
TEST_EQ(flatbuffers::numeric_limits<int64_t>::min(),
|
|
|
|
|
mArStruct->d()->Get(1)->d()->Get(0));
|
|
|
|
|
TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(),
|
|
|
|
|
mArStruct->d()->Get(1)->d()->Get(1));
|
2019-06-18 00:15:13 +02:00
|
|
|
for (int i = 0; i < mArStruct->b()->size() - 1; i++)
|
|
|
|
|
TEST_EQ(mArStruct->b()->Get(i), i + 1);
|
2019-08-23 19:46:47 +02:00
|
|
|
// Check alignment
|
2019-11-26 03:56:47 +07:00
|
|
|
TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->d()) % 8);
|
|
|
|
|
TEST_EQ(0, reinterpret_cast<uintptr_t>(mArStruct->f()) % 8);
|
2020-06-02 03:58:52 +03:00
|
|
|
|
|
|
|
|
// Check if default constructor set all memory zero
|
|
|
|
|
const size_t arr_size = sizeof(MyGame::Example::ArrayStruct);
|
|
|
|
|
char non_zero_memory[arr_size];
|
|
|
|
|
// set memory chunk of size ArrayStruct to 1's
|
2025-09-23 21:19:33 -07:00
|
|
|
std::memset(static_cast<void*>(non_zero_memory), 1, arr_size);
|
2020-06-02 03:58:52 +03:00
|
|
|
// after placement-new it should be all 0's
|
2025-12-19 10:42:57 -08:00
|
|
|
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && defined(_MSC_VER) && \
|
|
|
|
|
defined(_DEBUG)
|
2025-09-23 21:19:33 -07:00
|
|
|
#undef new
|
|
|
|
|
#endif
|
|
|
|
|
MyGame::Example::ArrayStruct* ap =
|
2021-01-22 21:46:53 +03:00
|
|
|
new (non_zero_memory) MyGame::Example::ArrayStruct;
|
2025-12-19 10:42:57 -08:00
|
|
|
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && defined(_MSC_VER) && \
|
|
|
|
|
defined(_DEBUG)
|
|
|
|
|
#define new DEBUG_NEW
|
2025-09-23 21:19:33 -07:00
|
|
|
#endif
|
2020-06-02 03:58:52 +03:00
|
|
|
(void)ap;
|
2025-09-23 21:19:33 -07:00
|
|
|
for (size_t i = 0; i < arr_size; ++i) {
|
|
|
|
|
TEST_EQ(non_zero_memory[i], 0);
|
|
|
|
|
}
|
2019-06-18 00:15:13 +02:00
|
|
|
}
|
2021-06-29 00:22:02 +07:00
|
|
|
#else
|
|
|
|
|
void FixedLengthArrayTest() {}
|
|
|
|
|
#endif // !defined(_MSC_VER) || _MSC_VER >= 1700
|
2019-06-18 00:15:13 +02:00
|
|
|
|
2021-01-22 21:46:53 +03:00
|
|
|
#if !defined(FLATBUFFERS_SPAN_MINIMAL) && \
|
|
|
|
|
(!defined(_MSC_VER) || _MSC_VER >= 1700)
|
2020-10-13 02:24:18 +07:00
|
|
|
void FixedLengthArrayConstructorTest() {
|
2025-09-23 21:19:33 -07:00
|
|
|
const int32_t nested_a[2] = {1, 2};
|
|
|
|
|
MyGame::Example::TestEnum nested_c[2] = {MyGame::Example::TestEnum::A,
|
|
|
|
|
MyGame::Example::TestEnum::B};
|
|
|
|
|
const int64_t int64_2[2] = {-2, -1};
|
2020-10-13 02:24:18 +07:00
|
|
|
|
|
|
|
|
std::array<MyGame::Example::NestedStruct, 2> init_d = {
|
2025-09-23 21:19:33 -07:00
|
|
|
{MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
|
|
|
|
|
nested_c, int64_2),
|
|
|
|
|
MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
|
|
|
|
|
nested_c,
|
|
|
|
|
std::array<int64_t, 2>{{12, 13}})}};
|
2020-10-13 02:24:18 +07:00
|
|
|
|
|
|
|
|
MyGame::Example::ArrayStruct arr_struct(
|
|
|
|
|
8.125,
|
|
|
|
|
std::array<int32_t, 0xF>{
|
2025-09-23 21:19:33 -07:00
|
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
|
2020-10-13 02:24:18 +07:00
|
|
|
-17, init_d, 10, int64_2);
|
|
|
|
|
TEST_EQ(arr_struct.a(), 8.125);
|
|
|
|
|
TEST_EQ(arr_struct.b()->Get(2), 3);
|
|
|
|
|
TEST_EQ(arr_struct.c(), -17);
|
|
|
|
|
|
|
|
|
|
TEST_NOTNULL(arr_struct.d());
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& arr_d_0 = *arr_struct.d()->Get(0);
|
2020-10-13 02:24:18 +07:00
|
|
|
TEST_EQ(arr_d_0.a()->Get(0), 1);
|
|
|
|
|
TEST_EQ(arr_d_0.a()->Get(1), 2);
|
|
|
|
|
TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
|
|
|
|
|
TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
|
|
|
|
|
TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
|
|
|
|
|
TEST_EQ(arr_d_0.d()->Get(0), -2);
|
|
|
|
|
TEST_EQ(arr_d_0.d()->Get(1), -1);
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& arr_d_1 = *arr_struct.d()->Get(1);
|
2020-10-13 02:24:18 +07:00
|
|
|
TEST_EQ(arr_d_1.a()->Get(0), 1);
|
|
|
|
|
TEST_EQ(arr_d_1.a()->Get(1), 2);
|
|
|
|
|
TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
|
|
|
|
|
TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
|
|
|
|
|
TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
|
|
|
|
|
TEST_EQ(arr_d_1.d()->Get(0), 12);
|
|
|
|
|
TEST_EQ(arr_d_1.d()->Get(1), 13);
|
|
|
|
|
|
|
|
|
|
TEST_EQ(arr_struct.e(), 10);
|
|
|
|
|
TEST_EQ(arr_struct.f()->Get(0), -2);
|
|
|
|
|
TEST_EQ(arr_struct.f()->Get(1), -1);
|
Fix dereference operator of VectorIterator to structures (#8425)
For Vector or Array of structures the dereference operator of an
iterator returns the pointer to the structure. However, IndirectHelper,
which is used in the implementation of this operator, is instantiated
in the way that the IndirectHelper::Read returns structure by value.
This is because, Vector and Array instantiate IndirectHelper with
const T*, but VectorIterator instantiates IndirectHelper with T. There
are three IndirectHelper template definition: first for T, second for
Offset<T> and the last one for const T*. Those have different
IndirectHelper:Read implementations and (more importantly) return type.
This is the reason of mismatch in VectorIterator::operator* between
return type declaration and what was exactly returned.
That is, for Array<T,...> where T is scalar the VectorIterator is
instantiated as VectorIterator<T, T>, dereference operator returns T
and its implementation uses IndirectHelper<T> which Read function
returns T.
When T is not scalar, then VectorIterator is instantiated as
VectorIterator<T, const T *>, dereference operator returns const T * and
its implementation uses IndirectHelper<T> which Read function returns T.
The fix is done as follows:
* implement type trait is_specialization_of_Offset and
is_specialization_of_Offset64,
* change partial specialization of IndirectHelper with const T * that
it is instantiated by T and enabled only if T is not scalar and not
specialization of Offset or Offset64,
* remove type differentiation (due to scalar) from Array..
The above makes the IndirectHelper able to correctly instantiate itself
basing only on T. Thus, the instantiation in VectorIterator correctly
instantiate IndirectHelper::Read function, especially the return type.
2025-05-18 07:01:09 +02:00
|
|
|
|
|
|
|
|
// Test for each loop over NestedStruct entries
|
|
|
|
|
for (auto i : *arr_struct.d()) {
|
|
|
|
|
for (auto a : *i->a()) {
|
|
|
|
|
TEST_EQ(a, 1);
|
|
|
|
|
break; // one iteration is enough, just testing compilation
|
|
|
|
|
}
|
|
|
|
|
TEST_EQ(i->b(), MyGame::Example::TestEnum::B);
|
|
|
|
|
for (auto c : *i->c()) {
|
|
|
|
|
TEST_EQ(c, MyGame::Example::TestEnum::A);
|
|
|
|
|
break; // one iteration is enough, just testing compilation
|
|
|
|
|
}
|
|
|
|
|
for (auto d : *i->d()) {
|
|
|
|
|
TEST_EQ(d, -2);
|
|
|
|
|
break; // one iteration is enough, just testing compilation
|
|
|
|
|
}
|
|
|
|
|
break; // one iteration is enough, just testing compilation
|
|
|
|
|
}
|
2020-10-13 02:24:18 +07:00
|
|
|
}
|
|
|
|
|
#else
|
2021-01-22 21:46:53 +03:00
|
|
|
void FixedLengthArrayConstructorTest() {}
|
2020-10-13 02:24:18 +07:00
|
|
|
#endif
|
|
|
|
|
|
2023-01-06 12:11:11 +08:00
|
|
|
void FixedLengthArrayOperatorEqualTest() {
|
2025-09-23 21:19:33 -07:00
|
|
|
const int32_t nested_a[2] = {1, 2};
|
|
|
|
|
MyGame::Example::TestEnum nested_c[2] = {MyGame::Example::TestEnum::A,
|
|
|
|
|
MyGame::Example::TestEnum::B};
|
2023-01-06 12:11:11 +08:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
MyGame::Example::TestEnum nested_cc[2] = {MyGame::Example::TestEnum::A,
|
|
|
|
|
MyGame::Example::TestEnum::C};
|
|
|
|
|
const int64_t int64_2[2] = {-2, -1};
|
2023-01-06 12:11:11 +08:00
|
|
|
|
|
|
|
|
std::array<MyGame::Example::NestedStruct, 2> init_d = {
|
2025-09-23 21:19:33 -07:00
|
|
|
{MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
|
|
|
|
|
nested_c, int64_2),
|
|
|
|
|
MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
|
|
|
|
|
nested_c,
|
|
|
|
|
std::array<int64_t, 2>{{-2, -1}})}};
|
2023-01-06 12:11:11 +08:00
|
|
|
|
|
|
|
|
auto different = MyGame::Example::NestedStruct(
|
|
|
|
|
nested_a, MyGame::Example::TestEnum::B, nested_cc,
|
2025-09-23 21:19:33 -07:00
|
|
|
std::array<int64_t, 2>{{-2, -1}});
|
2023-01-06 12:11:11 +08:00
|
|
|
|
|
|
|
|
TEST_ASSERT(init_d[0] == init_d[1]);
|
|
|
|
|
TEST_ASSERT(init_d[0] != different);
|
|
|
|
|
|
|
|
|
|
std::array<MyGame::Example::ArrayStruct, 3> arr_struct = {
|
2025-09-23 21:19:33 -07:00
|
|
|
MyGame::Example::ArrayStruct(
|
|
|
|
|
8.125,
|
|
|
|
|
std::array<int32_t, 0xF>{
|
|
|
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
|
|
|
|
|
-17, init_d, 10, int64_2),
|
|
|
|
|
|
|
|
|
|
MyGame::Example::ArrayStruct(
|
|
|
|
|
8.125,
|
|
|
|
|
std::array<int32_t, 0xF>{
|
|
|
|
|
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
|
|
|
|
|
-17, init_d, 10, int64_2),
|
|
|
|
|
|
|
|
|
|
MyGame::Example::ArrayStruct(
|
|
|
|
|
8.125,
|
|
|
|
|
std::array<int32_t, 0xF>{
|
|
|
|
|
{1000, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
|
|
|
|
|
-17, init_d, 10, int64_2)};
|
2023-01-06 12:11:11 +08:00
|
|
|
|
|
|
|
|
TEST_ASSERT(arr_struct[0] == arr_struct[1]);
|
|
|
|
|
TEST_ASSERT(arr_struct[1] != arr_struct[2]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-02 00:31:48 +03:00
|
|
|
void NativeTypeTest() {
|
|
|
|
|
const int N = 3;
|
|
|
|
|
|
|
|
|
|
Geometry::ApplicationDataT src_data;
|
2025-08-04 00:06:01 +02:00
|
|
|
src_data.position = flatbuffers::unique_ptr<Native::Vector3D>(
|
|
|
|
|
new Native::Vector3D(1.0f, 2.0f, 3.0f));
|
|
|
|
|
src_data.position_inline = Native::Vector3D(4.0f, 5.0f, 6.0f);
|
2019-08-02 00:31:48 +03:00
|
|
|
src_data.vectors.reserve(N);
|
2021-03-18 19:01:50 +01:00
|
|
|
src_data.vectors_alt.reserve(N);
|
2019-08-02 00:31:48 +03:00
|
|
|
|
|
|
|
|
for (int i = 0; i < N; ++i) {
|
2019-11-07 12:22:54 -08:00
|
|
|
src_data.vectors.push_back(
|
|
|
|
|
Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
|
2021-03-18 19:01:50 +01:00
|
|
|
src_data.vectors_alt.push_back(
|
|
|
|
|
Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
|
2019-08-02 00:31:48 +03:00
|
|
|
}
|
|
|
|
|
|
2025-11-17 22:42:06 +01:00
|
|
|
src_data.matrix = std::unique_ptr<Native::Matrix>(new Native::Matrix(1, 2));
|
2025-11-05 07:50:10 -08:00
|
|
|
src_data.matrix->values = {3, 4};
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < N; ++i) {
|
2025-12-19 10:42:57 -08:00
|
|
|
src_data.matrices.push_back(
|
|
|
|
|
std::unique_ptr<Native::Matrix>(new Native::Matrix(1, i)));
|
2025-11-05 07:50:10 -08:00
|
|
|
std::fill(src_data.matrices[i]->values.begin(),
|
|
|
|
|
src_data.matrices[i]->values.end(), i + 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-02 00:31:48 +03:00
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
|
|
|
|
|
|
2019-11-07 12:22:54 -08:00
|
|
|
auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
|
2019-08-02 00:31:48 +03:00
|
|
|
|
2025-08-04 00:06:01 +02:00
|
|
|
TEST_EQ(dstDataT->position->x, 1.0f);
|
|
|
|
|
TEST_EQ(dstDataT->position->y, 2.0f);
|
|
|
|
|
TEST_EQ(dstDataT->position->z, 3.0f);
|
|
|
|
|
TEST_EQ(dstDataT->position_inline.x, 4.0f);
|
|
|
|
|
TEST_EQ(dstDataT->position_inline.y, 5.0f);
|
|
|
|
|
TEST_EQ(dstDataT->position_inline.z, 6.0f);
|
|
|
|
|
|
2019-08-02 00:31:48 +03:00
|
|
|
for (int i = 0; i < N; ++i) {
|
2025-09-23 21:19:33 -07:00
|
|
|
const Native::Vector3D& v = dstDataT->vectors[i];
|
2019-08-02 00:31:48 +03:00
|
|
|
TEST_EQ(v.x, 10 * i + 0.1f);
|
|
|
|
|
TEST_EQ(v.y, 10 * i + 0.2f);
|
|
|
|
|
TEST_EQ(v.z, 10 * i + 0.3f);
|
2021-03-18 19:01:50 +01:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
const Native::Vector3D& v2 = dstDataT->vectors_alt[i];
|
2021-03-18 19:01:50 +01:00
|
|
|
TEST_EQ(v2.x, 20 * i + 0.1f);
|
|
|
|
|
TEST_EQ(v2.y, 20 * i + 0.2f);
|
|
|
|
|
TEST_EQ(v2.z, 20 * i + 0.3f);
|
2019-08-02 00:31:48 +03:00
|
|
|
}
|
2025-11-05 07:50:10 -08:00
|
|
|
|
|
|
|
|
TEST_EQ(dstDataT->matrix->rows, 1);
|
|
|
|
|
TEST_EQ(dstDataT->matrix->columns, 2);
|
|
|
|
|
TEST_EQ(dstDataT->matrix->values[0], 3);
|
|
|
|
|
TEST_EQ(dstDataT->matrix->values[1], 4);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < N; ++i) {
|
2025-12-19 10:42:57 -08:00
|
|
|
const Native::Matrix& m = *dstDataT->matrices[i];
|
2025-11-05 07:50:10 -08:00
|
|
|
TEST_EQ(m.rows, 1);
|
|
|
|
|
TEST_EQ(m.columns, i);
|
|
|
|
|
for (int j = 0; j < i; ++j) {
|
|
|
|
|
TEST_EQ(m.values[j], i + 0.5f);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-02 00:31:48 +03:00
|
|
|
}
|
|
|
|
|
|
2022-10-18 21:37:06 +02:00
|
|
|
// Guard against -Wunused-function on platforms without file tests.
|
|
|
|
|
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
2021-06-29 00:22:02 +07:00
|
|
|
// VS10 does not support typed enums, exclude from tests
|
2025-09-23 21:19:33 -07:00
|
|
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
|
|
|
|
void FixedLengthArrayJsonTest(const std::string& tests_data_path, bool binary) {
|
2019-06-18 00:15:13 +02:00
|
|
|
// load FlatBuffer schema (.fbs) and JSON from disk
|
|
|
|
|
std::string schemafile;
|
|
|
|
|
std::string jsonfile;
|
2022-08-28 16:54:58 -07:00
|
|
|
TEST_EQ(flatbuffers::LoadFile(
|
|
|
|
|
(tests_data_path + "arrays_test." + (binary ? "bfbs" : "fbs"))
|
|
|
|
|
.c_str(),
|
|
|
|
|
binary, &schemafile),
|
|
|
|
|
true);
|
2019-06-18 00:15:13 +02:00
|
|
|
TEST_EQ(
|
2022-08-28 16:54:58 -07:00
|
|
|
flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
|
|
|
|
|
false, &jsonfile),
|
2019-06-18 00:15:13 +02:00
|
|
|
true);
|
|
|
|
|
|
|
|
|
|
// parse schema first, so we can use it to parse the data after
|
|
|
|
|
flatbuffers::Parser parserOrg, parserGen;
|
|
|
|
|
if (binary) {
|
|
|
|
|
flatbuffers::Verifier verifier(
|
2025-09-23 21:19:33 -07:00
|
|
|
reinterpret_cast<const uint8_t*>(schemafile.c_str()),
|
2019-06-18 00:15:13 +02:00
|
|
|
schemafile.size());
|
|
|
|
|
TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
|
2022-04-06 13:25:43 -07:00
|
|
|
TEST_EQ(parserOrg.Deserialize(
|
2025-09-23 21:19:33 -07:00
|
|
|
reinterpret_cast<const uint8_t*>(schemafile.c_str()),
|
2022-04-06 13:25:43 -07:00
|
|
|
schemafile.size()),
|
2019-06-18 00:15:13 +02:00
|
|
|
true);
|
2022-04-06 13:25:43 -07:00
|
|
|
TEST_EQ(parserGen.Deserialize(
|
2025-09-23 21:19:33 -07:00
|
|
|
reinterpret_cast<const uint8_t*>(schemafile.c_str()),
|
2022-04-06 13:25:43 -07:00
|
|
|
schemafile.size()),
|
2019-06-18 00:15:13 +02:00
|
|
|
true);
|
|
|
|
|
} else {
|
|
|
|
|
TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
|
|
|
|
|
TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
|
|
|
|
|
}
|
|
|
|
|
TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
|
|
|
|
|
|
|
|
|
|
// First, verify it, just in case:
|
|
|
|
|
flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
|
|
|
|
|
parserOrg.builder_.GetSize());
|
|
|
|
|
TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
|
|
|
|
|
|
|
|
|
|
// Export to JSON
|
|
|
|
|
std::string jsonGen;
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(
|
2023-05-11 18:08:42 -07:00
|
|
|
GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
|
2019-06-18 00:15:13 +02:00
|
|
|
|
|
|
|
|
// Import from JSON
|
|
|
|
|
TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
|
|
|
|
|
|
|
|
|
|
// Verify buffer from generated JSON
|
|
|
|
|
flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
|
|
|
|
|
parserGen.builder_.GetSize());
|
|
|
|
|
TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
|
|
|
|
|
|
|
|
|
|
// Compare generated buffer to original
|
|
|
|
|
TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
|
|
|
|
|
TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
|
|
|
|
|
parserGen.builder_.GetBufferPointer(),
|
|
|
|
|
parserOrg.builder_.GetSize()),
|
|
|
|
|
0);
|
2021-06-29 00:22:02 +07:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
void FixedLengthArraySpanTest(const std::string& tests_data_path) {
|
2021-06-29 00:22:02 +07:00
|
|
|
// load FlatBuffer schema (.fbs) and JSON from disk
|
|
|
|
|
std::string schemafile;
|
|
|
|
|
std::string jsonfile;
|
2022-08-28 16:54:58 -07:00
|
|
|
TEST_EQ(flatbuffers::LoadFile((tests_data_path + "arrays_test.fbs").c_str(),
|
2021-06-29 00:22:02 +07:00
|
|
|
false, &schemafile),
|
|
|
|
|
true);
|
2022-08-28 16:54:58 -07:00
|
|
|
TEST_EQ(
|
|
|
|
|
flatbuffers::LoadFile((tests_data_path + "arrays_test.golden").c_str(),
|
|
|
|
|
false, &jsonfile),
|
|
|
|
|
true);
|
2021-06-29 00:22:02 +07:00
|
|
|
|
|
|
|
|
// parse schema first, so we can use it to parse the data after
|
|
|
|
|
flatbuffers::Parser parser;
|
|
|
|
|
TEST_EQ(parser.Parse(schemafile.c_str()), true);
|
|
|
|
|
TEST_EQ(parser.Parse(jsonfile.c_str()), true);
|
2025-09-23 21:19:33 -07:00
|
|
|
auto& fbb = parser.builder_;
|
2021-06-29 00:22:02 +07:00
|
|
|
auto verifier = flatbuffers::Verifier(fbb.GetBufferPointer(), fbb.GetSize());
|
|
|
|
|
TEST_EQ(true, VerifyArrayTableBuffer(verifier));
|
|
|
|
|
|
|
|
|
|
auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
|
|
|
|
|
TEST_NOTNULL(p);
|
|
|
|
|
auto table_struct = p->mutable_a();
|
|
|
|
|
TEST_NOTNULL(table_struct);
|
|
|
|
|
TEST_EQ(2, table_struct->d()->size());
|
|
|
|
|
TEST_NOTNULL(table_struct->d());
|
|
|
|
|
TEST_NOTNULL(table_struct->mutable_d());
|
|
|
|
|
// test array of structs
|
|
|
|
|
auto const_d = flatbuffers::make_span(*table_struct->d());
|
|
|
|
|
auto mutable_d = flatbuffers::make_span(*table_struct->mutable_d());
|
|
|
|
|
TEST_EQ(2, const_d.size());
|
|
|
|
|
TEST_EQ(2, mutable_d.size());
|
|
|
|
|
TEST_ASSERT(const_d[0] == mutable_d[0]);
|
|
|
|
|
TEST_ASSERT(const_d[1] == mutable_d[1]);
|
|
|
|
|
mutable_d[0] = const_d[0]; // mutate
|
|
|
|
|
// test scalars
|
2025-09-23 21:19:33 -07:00
|
|
|
auto& const_nested = const_d[0];
|
|
|
|
|
auto& mutable_nested = mutable_d[0];
|
2021-06-29 00:22:02 +07:00
|
|
|
static_assert(sizeof(MyGame::Example::TestEnum) == sizeof(uint8_t),
|
|
|
|
|
"TestEnum's underlaying type must by byte");
|
|
|
|
|
TEST_NOTNULL(const_nested.d());
|
|
|
|
|
TEST_NOTNULL(mutable_nested.d());
|
|
|
|
|
{
|
|
|
|
|
flatbuffers::span<const MyGame::Example::TestEnum, 2> const_d_c =
|
|
|
|
|
flatbuffers::make_span(*const_nested.c());
|
|
|
|
|
auto mutable_d_c = flatbuffers::make_span(*mutable_nested.mutable_c());
|
|
|
|
|
TEST_EQ(2, const_d_c.size());
|
|
|
|
|
TEST_EQ(2, mutable_d_c.size());
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::C, const_d_c[0]);
|
|
|
|
|
TEST_EQ(MyGame::Example::TestEnum::B, const_d_c[1]);
|
2022-05-10 13:53:38 -07:00
|
|
|
TEST_ASSERT(mutable_d_c.end() == std::copy(const_d_c.begin(),
|
|
|
|
|
const_d_c.end(),
|
2021-06-29 00:22:02 +07:00
|
|
|
mutable_d_c.begin()));
|
|
|
|
|
TEST_ASSERT(
|
2022-05-10 13:53:38 -07:00
|
|
|
std::equal(const_d_c.begin(), const_d_c.end(), mutable_d_c.begin()));
|
2021-06-29 00:22:02 +07:00
|
|
|
}
|
|
|
|
|
// test little endian array of int32
|
2025-09-23 21:19:33 -07:00
|
|
|
#if FLATBUFFERS_LITTLEENDIAN
|
2021-06-29 00:22:02 +07:00
|
|
|
{
|
|
|
|
|
flatbuffers::span<const int32_t, 2> const_d_a =
|
|
|
|
|
flatbuffers::make_span(*const_nested.a());
|
|
|
|
|
auto mutable_d_a = flatbuffers::make_span(*mutable_nested.mutable_a());
|
|
|
|
|
TEST_EQ(2, const_d_a.size());
|
|
|
|
|
TEST_EQ(2, mutable_d_a.size());
|
|
|
|
|
TEST_EQ(-1, const_d_a[0]);
|
|
|
|
|
TEST_EQ(2, const_d_a[1]);
|
2022-05-10 13:53:38 -07:00
|
|
|
TEST_ASSERT(mutable_d_a.end() == std::copy(const_d_a.begin(),
|
|
|
|
|
const_d_a.end(),
|
2021-06-29 00:22:02 +07:00
|
|
|
mutable_d_a.begin()));
|
|
|
|
|
TEST_ASSERT(
|
2022-05-10 13:53:38 -07:00
|
|
|
std::equal(const_d_a.begin(), const_d_a.end(), mutable_d_a.begin()));
|
2021-06-29 00:22:02 +07:00
|
|
|
}
|
2025-09-23 21:19:33 -07:00
|
|
|
#endif
|
2021-06-29 00:22:02 +07:00
|
|
|
}
|
2025-09-23 21:19:33 -07:00
|
|
|
#else
|
2021-06-29 00:22:02 +07:00
|
|
|
void FixedLengthArrayJsonTest(bool /*binary*/) {}
|
|
|
|
|
void FixedLengthArraySpanTest() {}
|
2025-09-23 21:19:33 -07:00
|
|
|
#endif
|
2019-06-18 00:15:13 +02:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
void TestEmbeddedBinarySchema(const std::string& tests_data_path) {
|
2020-03-02 10:15:23 -08:00
|
|
|
// load JSON from disk
|
|
|
|
|
std::string jsonfile;
|
|
|
|
|
TEST_EQ(flatbuffers::LoadFile(
|
2022-08-28 16:54:58 -07:00
|
|
|
(tests_data_path + "monsterdata_test.golden").c_str(), false,
|
2020-03-02 10:15:23 -08:00
|
|
|
&jsonfile),
|
|
|
|
|
true);
|
|
|
|
|
|
|
|
|
|
// parse schema first, so we can use it to parse the data after
|
|
|
|
|
flatbuffers::Parser parserOrg, parserGen;
|
|
|
|
|
flatbuffers::Verifier verifier(MyGame::Example::MonsterBinarySchema::data(),
|
|
|
|
|
MyGame::Example::MonsterBinarySchema::size());
|
|
|
|
|
TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
|
|
|
|
|
TEST_EQ(parserOrg.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
|
|
|
|
|
MyGame::Example::MonsterBinarySchema::size()),
|
|
|
|
|
true);
|
|
|
|
|
TEST_EQ(parserGen.Deserialize(MyGame::Example::MonsterBinarySchema::data(),
|
|
|
|
|
MyGame::Example::MonsterBinarySchema::size()),
|
|
|
|
|
true);
|
|
|
|
|
TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
|
|
|
|
|
|
|
|
|
|
// First, verify it, just in case:
|
|
|
|
|
flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
|
|
|
|
|
parserOrg.builder_.GetSize());
|
|
|
|
|
TEST_EQ(VerifyMonsterBuffer(verifierOrg), true);
|
|
|
|
|
|
|
|
|
|
// Export to JSON
|
|
|
|
|
std::string jsonGen;
|
2023-05-03 13:03:00 -07:00
|
|
|
TEST_NULL(
|
2023-05-11 18:08:42 -07:00
|
|
|
GenText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen));
|
2020-03-02 10:15:23 -08:00
|
|
|
|
|
|
|
|
// Import from JSON
|
|
|
|
|
TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
|
|
|
|
|
|
|
|
|
|
// Verify buffer from generated JSON
|
|
|
|
|
flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
|
|
|
|
|
parserGen.builder_.GetSize());
|
|
|
|
|
TEST_EQ(VerifyMonsterBuffer(verifierGen), true);
|
|
|
|
|
|
|
|
|
|
// Compare generated buffer to original
|
|
|
|
|
TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
|
|
|
|
|
TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
|
|
|
|
|
parserGen.builder_.GetBufferPointer(),
|
|
|
|
|
parserOrg.builder_.GetSize()),
|
|
|
|
|
0);
|
2020-01-24 17:55:34 -05:00
|
|
|
}
|
2022-10-18 21:37:06 +02:00
|
|
|
#endif
|
2020-01-24 17:55:34 -05:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
template <typename T>
|
|
|
|
|
void EmbeddedSchemaAccessByType() {
|
2023-05-04 16:12:45 -07:00
|
|
|
// Get the binary schema from the Type itself.
|
|
|
|
|
// Verify the schema is OK.
|
|
|
|
|
flatbuffers::Verifier verifierEmbeddedSchema(
|
|
|
|
|
T::TableType::BinarySchema::data(), T::TableType::BinarySchema::size());
|
|
|
|
|
TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
|
|
|
|
|
|
|
|
|
|
// Reflect it.
|
|
|
|
|
auto schema = reflection::GetSchema(T::TableType::BinarySchema::data());
|
|
|
|
|
|
|
|
|
|
// This should equal the expected root table.
|
|
|
|
|
TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EmbeddedSchemaAccess() {
|
|
|
|
|
// Get the binary schema for the monster.
|
|
|
|
|
// Verify the schema is OK.
|
|
|
|
|
flatbuffers::Verifier verifierEmbeddedSchema(Monster::BinarySchema::data(),
|
|
|
|
|
Monster::BinarySchema::size());
|
|
|
|
|
TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
|
|
|
|
|
|
|
|
|
|
// Reflect it.
|
|
|
|
|
auto schema = reflection::GetSchema(Monster::BinarySchema::data());
|
|
|
|
|
|
|
|
|
|
// This should equal the expected root table.
|
|
|
|
|
TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
|
|
|
|
|
|
|
|
|
|
// Repeat above, but do so through a template parameter:
|
|
|
|
|
EmbeddedSchemaAccessByType<StatT>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 10:20:06 -07:00
|
|
|
void NestedVerifierTest() {
|
|
|
|
|
// Create a nested monster.
|
|
|
|
|
flatbuffers::FlatBufferBuilder nested_builder;
|
|
|
|
|
FinishMonsterBuffer(
|
|
|
|
|
nested_builder,
|
|
|
|
|
CreateMonster(nested_builder, nullptr, 0, 0,
|
|
|
|
|
nested_builder.CreateString("NestedMonster")));
|
|
|
|
|
|
|
|
|
|
// Verify the nested monster
|
|
|
|
|
flatbuffers::Verifier verifier(nested_builder.GetBufferPointer(),
|
|
|
|
|
nested_builder.GetSize());
|
|
|
|
|
TEST_EQ(true, VerifyMonsterBuffer(verifier));
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Create the outer monster.
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
|
|
|
|
|
// Add the nested monster as a vector of bytes.
|
|
|
|
|
auto nested_monster_bytes = builder.CreateVector(
|
|
|
|
|
nested_builder.GetBufferPointer(), nested_builder.GetSize());
|
|
|
|
|
|
|
|
|
|
auto name = builder.CreateString("OuterMonster");
|
|
|
|
|
|
|
|
|
|
MonsterBuilder mon_builder(builder);
|
|
|
|
|
mon_builder.add_name(name);
|
|
|
|
|
mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
|
|
|
|
|
FinishMonsterBuffer(builder, mon_builder.Finish());
|
|
|
|
|
|
|
|
|
|
// Verify the root monster, which includes verifing the nested monster
|
|
|
|
|
flatbuffers::Verifier verifier(builder.GetBufferPointer(),
|
|
|
|
|
builder.GetSize());
|
|
|
|
|
TEST_EQ(true, VerifyMonsterBuffer(verifier));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Create the outer monster.
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
|
|
|
|
|
// Purposely invalidate the nested flatbuffer setting its length to 1, an
|
|
|
|
|
// invalid length.
|
|
|
|
|
uint8_t invalid_nested_buffer[1];
|
|
|
|
|
auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 1);
|
|
|
|
|
|
|
|
|
|
auto name = builder.CreateString("OuterMonster");
|
|
|
|
|
|
|
|
|
|
MonsterBuilder mon_builder(builder);
|
|
|
|
|
mon_builder.add_name(name);
|
|
|
|
|
mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
|
|
|
|
|
FinishMonsterBuffer(builder, mon_builder.Finish());
|
2022-08-14 12:40:57 -07:00
|
|
|
|
|
|
|
|
// Verify the root monster fails, since the included nested monster fails.
|
|
|
|
|
flatbuffers::Verifier verifier(builder.GetBufferPointer(),
|
|
|
|
|
builder.GetSize());
|
|
|
|
|
TEST_EQ(false, VerifyMonsterBuffer(verifier));
|
2022-08-29 19:25:57 -04:00
|
|
|
|
|
|
|
|
// Verify the root monster succeeds, since we've disabled checking nested
|
|
|
|
|
// flatbuffers
|
|
|
|
|
flatbuffers::Verifier::Options options;
|
|
|
|
|
options.check_nested_flatbuffers = false;
|
|
|
|
|
flatbuffers::Verifier no_check_nested(builder.GetBufferPointer(),
|
|
|
|
|
builder.GetSize(), options);
|
|
|
|
|
TEST_EQ(true, VerifyMonsterBuffer(no_check_nested));
|
2022-08-14 12:40:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Create the outer monster.
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
|
|
|
|
|
// Purposely invalidate the nested flatbuffer setting its length to 0, an
|
|
|
|
|
// invalid length.
|
2025-09-23 21:19:33 -07:00
|
|
|
uint8_t* invalid_nested_buffer = nullptr;
|
2022-08-14 12:40:57 -07:00
|
|
|
auto nested_monster_bytes = builder.CreateVector(invalid_nested_buffer, 0);
|
|
|
|
|
|
|
|
|
|
auto name = builder.CreateString("OuterMonster");
|
|
|
|
|
|
|
|
|
|
MonsterBuilder mon_builder(builder);
|
|
|
|
|
mon_builder.add_name(name);
|
|
|
|
|
mon_builder.add_testnestedflatbuffer(nested_monster_bytes);
|
|
|
|
|
FinishMonsterBuffer(builder, mon_builder.Finish());
|
2022-04-18 10:20:06 -07:00
|
|
|
|
|
|
|
|
// Verify the root monster fails, since the included nested monster fails.
|
|
|
|
|
flatbuffers::Verifier verifier(builder.GetBufferPointer(),
|
|
|
|
|
builder.GetSize());
|
|
|
|
|
TEST_EQ(false, VerifyMonsterBuffer(verifier));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-24 12:11:32 +00:00
|
|
|
void SizeVerifierTest() {
|
|
|
|
|
// Create a monster.
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
FinishMonsterBuffer(builder,
|
|
|
|
|
CreateMonster(builder, nullptr, 0, 0,
|
|
|
|
|
builder.CreateString("NestedMonster")));
|
|
|
|
|
size_t length = builder.GetSize();
|
|
|
|
|
const uint8_t* data = builder.GetBufferPointer();
|
|
|
|
|
|
|
|
|
|
// Verify the monster, using SizeVerifier.
|
|
|
|
|
// We verify in several ways, using several different API functions/methods,
|
|
|
|
|
// to ensure that all of these APIs are tested.
|
|
|
|
|
flatbuffers::SizeVerifier size_verifier(data,
|
|
|
|
|
FLATBUFFERS_MAX_BUFFER_SIZE - 1);
|
|
|
|
|
{
|
|
|
|
|
TEST_EQ(true, VerifyMonsterBuffer(size_verifier));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
TEST_EQ(true, size_verifier.VerifyBuffer<Monster>());
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const MyGame::Example::Monster* my_buffer = GetMonster(data);
|
|
|
|
|
TEST_EQ(true, my_buffer->Verify(size_verifier));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify that the size verifier computed the correct size.
|
|
|
|
|
TEST_EQ(length, size_verifier.GetComputedSize());
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
template <class T, class Container>
|
|
|
|
|
void TestIterators(const std::vector<T>& expected, const Container& tested) {
|
2021-05-10 23:07:56 +07:00
|
|
|
TEST_ASSERT(tested.rbegin().base() == tested.end());
|
|
|
|
|
TEST_ASSERT(tested.crbegin().base() == tested.cend());
|
|
|
|
|
TEST_ASSERT(tested.rend().base() == tested.begin());
|
|
|
|
|
TEST_ASSERT(tested.crend().base() == tested.cbegin());
|
|
|
|
|
|
|
|
|
|
size_t k = 0;
|
|
|
|
|
for (auto it = tested.begin(); it != tested.end(); ++it, ++k) {
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& e = expected.at(k);
|
2021-05-10 23:07:56 +07:00
|
|
|
TEST_EQ(*it, e);
|
|
|
|
|
}
|
|
|
|
|
TEST_EQ(k, expected.size());
|
|
|
|
|
|
|
|
|
|
k = expected.size();
|
|
|
|
|
for (auto it = tested.rbegin(); it != tested.rend(); ++it, --k) {
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& e = expected.at(k - 1);
|
2021-05-10 23:07:56 +07:00
|
|
|
TEST_EQ(*it, e);
|
|
|
|
|
}
|
|
|
|
|
TEST_EQ(k, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FlatbuffersIteratorsTest() {
|
|
|
|
|
{
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
2025-09-23 21:19:33 -07:00
|
|
|
const std::vector<unsigned char> inv_data = {1, 2, 3};
|
2021-05-10 23:07:56 +07:00
|
|
|
{
|
|
|
|
|
auto mon_name = fbb.CreateString("MyMonster"); // key, mandatory
|
|
|
|
|
auto inv_vec = fbb.CreateVector(inv_data);
|
|
|
|
|
auto empty_i64_vec =
|
2025-09-23 21:19:33 -07:00
|
|
|
fbb.CreateVector(static_cast<const int64_t*>(nullptr), 0);
|
2021-05-10 23:07:56 +07:00
|
|
|
MonsterBuilder mb(fbb);
|
|
|
|
|
mb.add_name(mon_name);
|
|
|
|
|
mb.add_inventory(inv_vec);
|
|
|
|
|
mb.add_vector_of_longs(empty_i64_vec);
|
|
|
|
|
FinishMonsterBuffer(fbb, mb.Finish());
|
|
|
|
|
}
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& mon = *flatbuffers::GetRoot<Monster>(fbb.GetBufferPointer());
|
2021-05-10 23:07:56 +07:00
|
|
|
|
|
|
|
|
TEST_EQ_STR("MyMonster", mon.name()->c_str());
|
|
|
|
|
TEST_ASSERT(mon.inventory());
|
|
|
|
|
TEST_ASSERT(mon.vector_of_longs());
|
|
|
|
|
TestIterators(inv_data, *mon.inventory());
|
|
|
|
|
TestIterators(std::vector<int64_t>(), *mon.vector_of_longs());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
MyGame::Example::ArrayStruct aStruct;
|
|
|
|
|
MyGame::Example::FinishArrayTableBuffer(
|
|
|
|
|
fbb, MyGame::Example::CreateArrayTable(fbb, &aStruct));
|
2025-09-23 21:19:33 -07:00
|
|
|
const auto& array_table =
|
2021-05-10 23:07:56 +07:00
|
|
|
*flatbuffers::GetRoot<ArrayTable>(fbb.GetBufferPointer());
|
|
|
|
|
TEST_ASSERT(array_table.a());
|
2025-09-23 21:19:33 -07:00
|
|
|
auto& int_15 = *array_table.a()->b();
|
2021-05-10 23:07:56 +07:00
|
|
|
TestIterators(std::vector<int>(15, 0), int_15);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-05 23:04:05 +02:00
|
|
|
void PrivateAnnotationsLeaks() {
|
|
|
|
|
// Simple schemas and a "has optional scalar" sentinal.
|
|
|
|
|
std::vector<std::string> schemas;
|
|
|
|
|
std::vector<std::string> failure_schemas;
|
|
|
|
|
|
|
|
|
|
// (private) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC (private) { mana: int; }");
|
|
|
|
|
|
|
|
|
|
// (public) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }");
|
|
|
|
|
|
|
|
|
|
// (private) (union) containing (private) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; } "
|
|
|
|
|
"struct ABC (private) { mana: int; } "
|
|
|
|
|
"union Any (private) { Monster, ABC } ");
|
|
|
|
|
|
|
|
|
|
// (public) (union) containing (public) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }"
|
|
|
|
|
"union Any { Monster, ABC }");
|
|
|
|
|
|
|
|
|
|
// (private) (table/struct/enum)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC (private) { mana: int; }"
|
|
|
|
|
"enum Race:byte (private) { None = -1, Human = 0, }");
|
|
|
|
|
|
|
|
|
|
// (public) (table/struct/enum)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }"
|
|
|
|
|
"enum Race:byte { None = -1, Human = 0, }");
|
|
|
|
|
|
|
|
|
|
// (private) (union) containing (private) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC (private) { mana: int; }"
|
|
|
|
|
"enum Race:byte (private) { None = -1, Human = 0, }"
|
|
|
|
|
"union Any (private) { Monster, ABC }");
|
|
|
|
|
|
|
|
|
|
// (public) (union) containing (public) (table/struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }"
|
|
|
|
|
"enum Race:byte { None = -1, Human = 0, }"
|
|
|
|
|
"union Any { Monster, ABC }");
|
|
|
|
|
|
|
|
|
|
// (private) (table), (public struct)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }");
|
|
|
|
|
|
|
|
|
|
// (private) (table), (public) (struct/enum)
|
|
|
|
|
schemas.push_back(
|
2022-08-08 21:22:57 -07:00
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }"
|
|
|
|
|
"enum Race:byte { None = -1, Human = 0, }");
|
2022-06-05 23:04:05 +02:00
|
|
|
|
|
|
|
|
// (public) (struct) containing (public) (enum)
|
|
|
|
|
schemas.push_back(
|
|
|
|
|
"enum Race:byte { None = -1, Human = 0, }"
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; type: Race; }");
|
|
|
|
|
|
|
|
|
|
// (public) (union) containing (private) (table) & (public) (struct)
|
|
|
|
|
failure_schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; }"
|
|
|
|
|
"union Any { Monster, ABC }");
|
|
|
|
|
|
|
|
|
|
// (public) (union) containing (private) (table/struct)
|
|
|
|
|
failure_schemas.push_back(
|
|
|
|
|
"table Monster (private) { mana: int; }"
|
|
|
|
|
"struct ABC (private) { mana: int; }"
|
|
|
|
|
"enum Race:byte { None = -1, Human = 0, }"
|
|
|
|
|
"union Any { Monster, ABC }");
|
|
|
|
|
|
|
|
|
|
// (public) (table) containing (private) (struct)
|
|
|
|
|
failure_schemas.push_back(
|
|
|
|
|
"table Monster { mana: int; ab: ABC; }"
|
|
|
|
|
"struct ABC (private) { mana: int; }");
|
|
|
|
|
|
|
|
|
|
// (public) (struct) containing (private) (enum)
|
|
|
|
|
failure_schemas.push_back(
|
|
|
|
|
"enum Race:byte (private) { None = -1, Human = 0, }"
|
|
|
|
|
"table Monster { mana: int; }"
|
|
|
|
|
"struct ABC { mana: int; type: Race; }");
|
|
|
|
|
|
|
|
|
|
flatbuffers::IDLOptions opts;
|
|
|
|
|
opts.lang_to_generate = flatbuffers::IDLOptions::Language::kSwift;
|
|
|
|
|
opts.no_leak_private_annotations = true;
|
|
|
|
|
|
|
|
|
|
for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
|
|
|
|
|
flatbuffers::Parser parser(opts);
|
|
|
|
|
TEST_ASSERT(parser.Parse(schema->c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
|
|
|
|
|
schema++) {
|
|
|
|
|
flatbuffers::Parser parser(opts);
|
|
|
|
|
TEST_EQ(false, parser.Parse(schema->c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opts.no_leak_private_annotations = false;
|
|
|
|
|
|
|
|
|
|
for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
|
|
|
|
|
flatbuffers::Parser parser(opts);
|
|
|
|
|
TEST_ASSERT(parser.Parse(schema->c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
|
|
|
|
|
schema++) {
|
|
|
|
|
flatbuffers::Parser parser(opts);
|
|
|
|
|
TEST_ASSERT(parser.Parse(schema->c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-14 21:21:55 +02:00
|
|
|
void VectorSpanTest() {
|
|
|
|
|
flatbuffers::FlatBufferBuilder builder;
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
auto mloc = CreateMonster(
|
|
|
|
|
builder, nullptr, 0, 0, builder.CreateString("Monster"),
|
2025-09-23 21:19:33 -07:00
|
|
|
builder.CreateVector<uint8_t>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
|
2022-08-14 21:21:55 +02:00
|
|
|
|
|
|
|
|
FinishMonsterBuffer(builder, mloc);
|
|
|
|
|
|
|
|
|
|
auto monster = GetMonster(builder.GetBufferPointer());
|
|
|
|
|
auto mutable_monster = GetMutableMonster(builder.GetBufferPointer());
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
{ // using references
|
2022-08-14 21:21:55 +02:00
|
|
|
TEST_NOTNULL(monster->inventory());
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<const uint8_t> const_inventory =
|
|
|
|
|
flatbuffers::make_span(*monster->inventory());
|
|
|
|
|
TEST_EQ(const_inventory.size(), 10);
|
|
|
|
|
TEST_EQ(const_inventory[0], 0);
|
|
|
|
|
TEST_EQ(const_inventory[9], 9);
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<uint8_t> mutable_inventory =
|
|
|
|
|
flatbuffers::make_span(*mutable_monster->mutable_inventory());
|
|
|
|
|
TEST_EQ(mutable_inventory.size(), 10);
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 0);
|
|
|
|
|
TEST_EQ(mutable_inventory[9], 9);
|
|
|
|
|
|
|
|
|
|
mutable_inventory[0] = 42;
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 42);
|
|
|
|
|
|
|
|
|
|
mutable_inventory[0] = 0;
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 0);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
{ // using pointers
|
2022-08-14 21:21:55 +02:00
|
|
|
TEST_EQ(flatbuffers::VectorLength(monster->inventory()), 10);
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<const uint8_t> const_inventory =
|
|
|
|
|
flatbuffers::make_span(monster->inventory());
|
|
|
|
|
TEST_EQ(const_inventory.size(), 10);
|
|
|
|
|
TEST_EQ(const_inventory[0], 0);
|
|
|
|
|
TEST_EQ(const_inventory[9], 9);
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<uint8_t> mutable_inventory =
|
|
|
|
|
flatbuffers::make_span(mutable_monster->mutable_inventory());
|
|
|
|
|
TEST_EQ(mutable_inventory.size(), 10);
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 0);
|
|
|
|
|
TEST_EQ(mutable_inventory[9], 9);
|
|
|
|
|
|
|
|
|
|
mutable_inventory[0] = 42;
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 42);
|
|
|
|
|
|
|
|
|
|
mutable_inventory[0] = 0;
|
|
|
|
|
TEST_EQ(mutable_inventory[0], 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
TEST_ASSERT(nullptr == monster->testnestedflatbuffer());
|
|
|
|
|
|
|
|
|
|
TEST_EQ(flatbuffers::VectorLength(monster->testnestedflatbuffer()), 0);
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<const uint8_t> const_nested =
|
|
|
|
|
flatbuffers::make_span(monster->testnestedflatbuffer());
|
|
|
|
|
TEST_ASSERT(const_nested.empty());
|
|
|
|
|
|
|
|
|
|
flatbuffers::span<uint8_t> mutable_nested =
|
|
|
|
|
flatbuffers::make_span(mutable_monster->mutable_testnestedflatbuffer());
|
|
|
|
|
TEST_ASSERT(mutable_nested.empty());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 03:48:10 +08:00
|
|
|
void NativeInlineTableVectorTest() {
|
|
|
|
|
TestNativeInlineTableT test;
|
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
|
|
|
NativeInlineTableT t;
|
|
|
|
|
t.a = i;
|
|
|
|
|
test.t.push_back(t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
auto offset = TestNativeInlineTable::Pack(fbb, &test);
|
|
|
|
|
fbb.Finish(offset);
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
auto* root =
|
2022-08-30 03:48:10 +08:00
|
|
|
flatbuffers::GetRoot<TestNativeInlineTable>(fbb.GetBufferPointer());
|
|
|
|
|
TestNativeInlineTableT unpacked;
|
|
|
|
|
root->UnPackTo(&unpacked);
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
|
|
|
TEST_ASSERT(unpacked.t[i] == test.t[i]);
|
|
|
|
|
}
|
2022-08-30 03:48:10 +08:00
|
|
|
|
|
|
|
|
TEST_ASSERT(unpacked.t == test.t);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-21 23:59:34 +01:00
|
|
|
// Guard against -Wunused-function on platforms without file tests.
|
|
|
|
|
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
2025-09-23 21:19:33 -07:00
|
|
|
void DoNotRequireEofTest(const std::string& tests_data_path) {
|
2022-11-03 08:57:46 -07:00
|
|
|
std::string schemafile;
|
|
|
|
|
bool ok = flatbuffers::LoadFile(
|
|
|
|
|
(tests_data_path + "monster_test.fbs").c_str(), false, &schemafile);
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
auto include_test_path =
|
|
|
|
|
flatbuffers::ConCatPathFileName(tests_data_path, "include_test");
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* include_directories[] = {tests_data_path.c_str(),
|
|
|
|
|
include_test_path.c_str(), nullptr};
|
2022-11-03 08:57:46 -07:00
|
|
|
flatbuffers::IDLOptions opt;
|
|
|
|
|
opt.require_json_eof = false;
|
|
|
|
|
flatbuffers::Parser parser(opt);
|
|
|
|
|
ok = parser.Parse(schemafile.c_str(), include_directories);
|
|
|
|
|
TEST_EQ(ok, true);
|
2022-11-18 11:04:46 -08:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* str = R"(Some text at the beginning. {
|
2022-11-03 08:57:46 -07:00
|
|
|
"name": "Blob",
|
|
|
|
|
"hp": 5
|
2022-11-22 12:11:14 -08:00
|
|
|
}{
|
2022-11-03 08:57:46 -07:00
|
|
|
"name": "Imp",
|
|
|
|
|
"hp": 10
|
|
|
|
|
}
|
2022-11-22 12:11:14 -08:00
|
|
|
Some extra text at the end too.
|
2022-11-03 08:57:46 -07:00
|
|
|
)";
|
2025-09-23 21:19:33 -07:00
|
|
|
const char* tableStart = std::strchr(str, '{');
|
2022-11-03 08:57:46 -07:00
|
|
|
ok = parser.ParseJson(tableStart);
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
const Monster* monster = GetMonster(parser.builder_.GetBufferPointer());
|
2022-11-03 08:57:46 -07:00
|
|
|
TEST_EQ_STR(monster->name()->c_str(), "Blob");
|
|
|
|
|
TEST_EQ(monster->hp(), 5);
|
2022-11-18 11:04:46 -08:00
|
|
|
|
2022-11-03 08:57:46 -07:00
|
|
|
tableStart += parser.BytesConsumed();
|
|
|
|
|
|
|
|
|
|
ok = parser.ParseJson(tableStart);
|
|
|
|
|
TEST_EQ(ok, true);
|
|
|
|
|
|
|
|
|
|
monster = GetMonster(parser.builder_.GetBufferPointer());
|
|
|
|
|
TEST_EQ_STR(monster->name()->c_str(), "Imp");
|
|
|
|
|
TEST_EQ(monster->hp(), 10);
|
|
|
|
|
}
|
2022-12-21 23:59:34 +01:00
|
|
|
#endif
|
2022-11-03 08:57:46 -07:00
|
|
|
|
2023-05-15 12:22:38 +08:00
|
|
|
void UnionUnderlyingTypeTest() {
|
2025-09-23 21:19:33 -07:00
|
|
|
using namespace UnionUnderlyingType;
|
|
|
|
|
TEST_ASSERT(sizeof(ABC) == sizeof(uint32_t));
|
|
|
|
|
TEST_ASSERT(static_cast<int32_t>(ABC::A) == 555);
|
|
|
|
|
TEST_ASSERT(static_cast<int32_t>(ABC::B) == 666);
|
|
|
|
|
TEST_ASSERT(static_cast<int32_t>(ABC::C) == 777);
|
|
|
|
|
|
|
|
|
|
DT buffer;
|
|
|
|
|
AT a;
|
|
|
|
|
a.a = 42;
|
|
|
|
|
BT b;
|
|
|
|
|
b.b = "foo";
|
|
|
|
|
CT c;
|
|
|
|
|
c.c = true;
|
|
|
|
|
buffer.test_union = ABCUnion();
|
|
|
|
|
buffer.test_union.Set(a);
|
|
|
|
|
buffer.test_vector_of_union.resize(3);
|
|
|
|
|
buffer.test_vector_of_union[0].Set(a);
|
|
|
|
|
buffer.test_vector_of_union[1].Set(b);
|
|
|
|
|
buffer.test_vector_of_union[2].Set(c);
|
2023-05-15 12:22:38 +08:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
auto offset = D::Pack(fbb, &buffer);
|
|
|
|
|
fbb.Finish(offset);
|
2023-05-15 12:22:38 +08:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
auto* root = flatbuffers::GetRoot<D>(fbb.GetBufferPointer());
|
|
|
|
|
DT unpacked;
|
|
|
|
|
root->UnPackTo(&unpacked);
|
2023-05-15 12:22:38 +08:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
TEST_ASSERT(unpacked.test_union == buffer.test_union);
|
|
|
|
|
TEST_ASSERT(unpacked.test_vector_of_union == buffer.test_vector_of_union);
|
2023-05-15 12:22:38 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-19 11:49:50 -08:00
|
|
|
void StructsInHashTableTest() {
|
|
|
|
|
#if defined(HAS_ABSL_CONTAINERS) && (!defined(_MSC_VER) || _MSC_VER >= 1700)
|
|
|
|
|
absl::flat_hash_set<ArrayStruct> hash_set;
|
|
|
|
|
ArrayStruct array_struct_1;
|
|
|
|
|
array_struct_1.mutate_a(0.4);
|
|
|
|
|
for (int i = 0; i < array_struct_1.b()->size(); ++i) {
|
|
|
|
|
array_struct_1.mutable_b()->Mutate(i, i * 2);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < array_struct_1.d()->size(); ++i) {
|
|
|
|
|
NestedStruct nested_struct;
|
|
|
|
|
nested_struct.mutable_a()->Mutate(0, i * 3);
|
|
|
|
|
array_struct_1.mutable_d()->Mutate(i, nested_struct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArrayStruct array_struct_2;
|
|
|
|
|
array_struct_2.mutate_e(999);
|
|
|
|
|
|
|
|
|
|
hash_set.insert(array_struct_1);
|
|
|
|
|
hash_set.insert(array_struct_2);
|
|
|
|
|
|
|
|
|
|
TEST_EQ(hash_set.size(), 2);
|
|
|
|
|
TEST_ASSERT(hash_set.contains(array_struct_1));
|
|
|
|
|
TEST_ASSERT(hash_set.contains(array_struct_2));
|
|
|
|
|
|
|
|
|
|
ArrayStruct array_struct_3 = array_struct_1;
|
|
|
|
|
array_struct_3.mutable_b()->Mutate(0, 2);
|
|
|
|
|
TEST_ASSERT(!hash_set.contains(array_struct_3));
|
|
|
|
|
|
|
|
|
|
hash_set.insert(array_struct_3);
|
|
|
|
|
TEST_ASSERT(hash_set.contains(array_struct_3));
|
|
|
|
|
#endif // defined(HAS_ABSL_CONTAINERS) && (!defined(_MSC_VER) || _MSC_VER >=
|
|
|
|
|
// 1700)
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 09:16:30 -07:00
|
|
|
static void Offset64Tests() {
|
2023-05-31 11:52:05 -07:00
|
|
|
#if INCLUDE_64_BIT_TESTS
|
2023-05-09 09:16:30 -07:00
|
|
|
Offset64Test();
|
|
|
|
|
Offset64SerializedFirst();
|
|
|
|
|
Offset64NestedFlatBuffer();
|
|
|
|
|
Offset64CreateDirect();
|
|
|
|
|
Offset64Evolution();
|
|
|
|
|
Offset64VectorOfStructs();
|
|
|
|
|
Offset64SizePrefix();
|
|
|
|
|
Offset64ManyVectors();
|
2023-05-26 11:49:06 -07:00
|
|
|
Offset64ForceAlign();
|
2023-05-31 11:52:05 -07:00
|
|
|
#endif
|
2023-05-09 09:16:30 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-12 02:11:06 +00:00
|
|
|
// Test that Pack() generates correctly namespace-qualified Create* calls
|
|
|
|
|
// when referencing tables from different namespaces. (issue #8948)
|
|
|
|
|
void CrossNamespacePackTest() {
|
|
|
|
|
// Build a Consumer with a cross-namespace TableWithNative reference.
|
|
|
|
|
foo::ConsumerT consumer;
|
|
|
|
|
consumer.c1 = std::make_unique<native::TableWithNativeT>();
|
|
|
|
|
consumer.c1->value = 42;
|
|
|
|
|
|
|
|
|
|
// Add a vector element too.
|
|
|
|
|
consumer.c2.push_back(std::make_unique<native::TableWithNativeT>());
|
|
|
|
|
consumer.c2[0]->value = 99;
|
|
|
|
|
|
|
|
|
|
// Pack and verify round-trip.
|
|
|
|
|
flatbuffers::FlatBufferBuilder fbb;
|
|
|
|
|
fbb.Finish(foo::Consumer::Pack(fbb, &consumer));
|
|
|
|
|
|
|
|
|
|
auto* packed = flatbuffers::GetRoot<foo::Consumer>(fbb.GetBufferPointer());
|
|
|
|
|
auto unpacked = packed->UnPack();
|
|
|
|
|
TEST_EQ(unpacked->c1->value, 42);
|
|
|
|
|
TEST_EQ(unpacked->c2.size(), 1);
|
|
|
|
|
TEST_EQ(unpacked->c2[0]->value, 99);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
int FlatBufferTests(const std::string& tests_data_path) {
|
2014-01-27 16:52:49 -08:00
|
|
|
// Run our various test suites:
|
|
|
|
|
|
2015-02-24 13:14:46 +01:00
|
|
|
std::string rawbuf;
|
2017-06-16 15:04:42 -07:00
|
|
|
auto flatbuf1 = CreateFlatBufferTest(rawbuf);
|
2021-11-12 14:01:11 -08:00
|
|
|
auto flatbuf = std::move(flatbuf1); // Test move assignment.
|
2017-11-16 19:08:41 +01:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
AccessFlatBufferTest(reinterpret_cast<const uint8_t*>(rawbuf.c_str()),
|
2015-03-07 13:00:05 -08:00
|
|
|
rawbuf.length());
|
2017-05-24 15:55:15 -05:00
|
|
|
AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
|
2014-01-27 16:52:49 -08:00
|
|
|
|
2017-05-24 15:55:15 -05:00
|
|
|
MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
|
2015-04-27 16:25:06 -07:00
|
|
|
|
2017-05-24 15:55:15 -05:00
|
|
|
ObjectFlatBuffersTest(flatbuf.data());
|
2022-09-13 22:00:01 -07:00
|
|
|
UnPackTo(flatbuf.data());
|
2016-07-01 18:08:51 -07:00
|
|
|
|
2017-08-24 17:44:03 -07:00
|
|
|
MiniReflectFlatBuffersTest(flatbuf.data());
|
2020-09-23 02:57:01 +02:00
|
|
|
MiniReflectFixedLengthArrayTest();
|
2017-08-24 17:44:03 -07:00
|
|
|
|
2016-10-10 15:55:26 -07:00
|
|
|
SizePrefixedTest();
|
|
|
|
|
|
2022-09-21 20:05:05 +02:00
|
|
|
AlignmentTest();
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
|
|
|
|
ParseAndGenerateTextTest(tests_data_path, false);
|
|
|
|
|
ParseAndGenerateTextTest(tests_data_path, true);
|
|
|
|
|
FixedLengthArrayJsonTest(tests_data_path, false);
|
|
|
|
|
FixedLengthArrayJsonTest(tests_data_path, true);
|
|
|
|
|
ReflectionTest(tests_data_path, flatbuf.data(), flatbuf.size());
|
|
|
|
|
ParseProtoTest(tests_data_path);
|
|
|
|
|
EvolutionTest(tests_data_path);
|
|
|
|
|
UnionDeprecationTest(tests_data_path);
|
|
|
|
|
UnionVectorTest(tests_data_path);
|
|
|
|
|
GenerateTableTextTest(tests_data_path);
|
|
|
|
|
TestEmbeddedBinarySchema(tests_data_path);
|
|
|
|
|
JsonOptionalTest(tests_data_path, false);
|
|
|
|
|
JsonOptionalTest(tests_data_path, true);
|
|
|
|
|
MultiFileNameClashTest(tests_data_path);
|
|
|
|
|
InvalidNestedFlatbufferTest(tests_data_path);
|
|
|
|
|
JsonDefaultTest(tests_data_path);
|
|
|
|
|
JsonEnumsTest(tests_data_path);
|
|
|
|
|
TestMonsterExtraFloats(tests_data_path);
|
|
|
|
|
ParseIncorrectMonsterJsonTest(tests_data_path);
|
|
|
|
|
FixedLengthArraySpanTest(tests_data_path);
|
2022-11-03 08:57:46 -07:00
|
|
|
DoNotRequireEofTest(tests_data_path);
|
2023-04-26 07:37:06 +02:00
|
|
|
JsonUnionStructTest();
|
2025-12-07 14:05:54 -05:00
|
|
|
VectorTableNakedPtrTest();
|
2022-12-22 17:48:48 +01:00
|
|
|
#else
|
|
|
|
|
// Guard against -Wunused-parameter.
|
|
|
|
|
(void)tests_data_path;
|
2022-08-28 16:54:58 -07:00
|
|
|
#endif
|
2014-01-27 16:52:49 -08:00
|
|
|
|
2022-02-23 16:08:11 -08:00
|
|
|
UtilConvertCase();
|
|
|
|
|
|
2014-01-27 16:52:49 -08:00
|
|
|
FuzzTest1();
|
|
|
|
|
FuzzTest2();
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
TriviallyCopyableTest();
|
2014-01-27 16:52:49 -08:00
|
|
|
ErrorTest();
|
2016-06-15 13:54:17 -07:00
|
|
|
ValueTest();
|
2019-04-09 00:21:30 +07:00
|
|
|
EnumValueTest();
|
2022-08-17 01:48:41 +08:00
|
|
|
NestedListTest();
|
2014-07-14 17:49:04 -07:00
|
|
|
EnumStringsTest();
|
2018-10-08 23:37:35 +02:00
|
|
|
EnumNamesTest();
|
2018-10-18 19:39:08 +02:00
|
|
|
EnumOutOfRangeTest();
|
2016-04-29 12:57:48 -07:00
|
|
|
IntegerOutOfRangeTest();
|
2017-04-18 04:19:43 +10:00
|
|
|
IntegerBoundaryTest();
|
2014-08-20 13:22:16 -07:00
|
|
|
UnicodeTest();
|
2016-08-01 14:04:51 -07:00
|
|
|
UnicodeTestAllowNonUTF8();
|
2016-08-18 10:14:32 -07:00
|
|
|
UnicodeTestGenerateTextFailsOnNonUTF8();
|
2016-04-28 12:27:38 -07:00
|
|
|
UnicodeSurrogatesTest();
|
|
|
|
|
UnicodeInvalidSurrogatesTest();
|
2016-08-01 14:04:51 -07:00
|
|
|
InvalidUTF8Test();
|
2015-12-22 00:02:19 -08:00
|
|
|
UnknownFieldsTest();
|
2016-06-20 16:06:30 -07:00
|
|
|
ParseUnionTest();
|
2021-05-14 21:56:52 +01:00
|
|
|
ValidSameNameDifferentNamespaceTest();
|
2016-07-20 17:24:50 -07:00
|
|
|
ConformTest();
|
2017-06-16 11:57:58 -07:00
|
|
|
ParseProtoBufAsciiTest();
|
2017-08-02 17:07:43 +02:00
|
|
|
TypeAliasesTest();
|
2017-11-16 14:19:31 -08:00
|
|
|
EndianSwapTest();
|
2018-12-03 09:48:50 -08:00
|
|
|
CreateSharedStringTest();
|
2016-02-01 18:00:30 -08:00
|
|
|
FlexBuffersTest();
|
2022-08-05 10:45:01 -07:00
|
|
|
FlexBuffersReuseBugTest();
|
2019-12-23 11:12:41 -08:00
|
|
|
FlexBuffersDeprecatedTest();
|
2018-06-18 22:42:26 +05:30
|
|
|
UninitializedVectorTest();
|
2018-09-22 01:53:59 +02:00
|
|
|
EqualOperatorTest();
|
2018-10-12 00:37:47 +07:00
|
|
|
NumericUtilsTest();
|
|
|
|
|
IsAsciiUtilsTest();
|
|
|
|
|
ValidFloatTest();
|
|
|
|
|
InvalidFloatTest();
|
2019-06-18 00:15:13 +02:00
|
|
|
FixedLengthArrayTest();
|
2019-08-02 00:31:48 +03:00
|
|
|
NativeTypeTest();
|
2020-09-10 16:04:36 -04:00
|
|
|
OptionalScalarsTest();
|
2020-07-16 13:43:47 -07:00
|
|
|
ParseFlexbuffersFromJsonWithNullTest();
|
2020-10-13 02:24:18 +07:00
|
|
|
FlatbuffersSpanTest();
|
|
|
|
|
FixedLengthArrayConstructorTest();
|
2023-01-06 12:11:11 +08:00
|
|
|
FixedLengthArrayOperatorEqualTest();
|
2021-01-05 03:33:31 +07:00
|
|
|
FieldIdentifierTest();
|
2021-02-12 09:41:10 -05:00
|
|
|
StringVectorDefaultsTest();
|
2021-03-16 01:44:42 +07:00
|
|
|
FlexBuffersFloatingPointTest();
|
2021-05-10 23:07:56 +07:00
|
|
|
FlatbuffersIteratorsTest();
|
2022-01-25 17:01:16 -05:00
|
|
|
WarningsAsErrorsTest();
|
2022-04-18 10:20:06 -07:00
|
|
|
NestedVerifierTest();
|
2025-11-24 12:11:32 +00:00
|
|
|
SizeVerifierTest();
|
2022-06-05 23:04:05 +02:00
|
|
|
PrivateAnnotationsLeaks();
|
2022-08-13 00:27:17 +08:00
|
|
|
JsonUnsortedArrayTest();
|
2022-08-14 21:21:55 +02:00
|
|
|
VectorSpanTest();
|
2022-08-30 03:48:10 +08:00
|
|
|
NativeInlineTableVectorTest();
|
2022-11-18 11:04:46 -08:00
|
|
|
FixedSizedScalarKeyInStructTest();
|
2023-01-24 16:37:13 -08:00
|
|
|
StructKeyInStructTest();
|
|
|
|
|
NestedStructKeyInStructTest();
|
|
|
|
|
FixedSizedStructArrayKeyInStructTest();
|
2023-05-04 16:12:45 -07:00
|
|
|
EmbeddedSchemaAccess();
|
2023-05-09 09:16:30 -07:00
|
|
|
Offset64Tests();
|
2023-05-15 12:22:38 +08:00
|
|
|
UnionUnderlyingTypeTest();
|
2025-12-19 11:49:50 -08:00
|
|
|
StructsInHashTableTest();
|
2025-12-19 14:32:51 -08:00
|
|
|
DefaultVectorsStringsTest();
|
2026-03-12 02:11:06 +00:00
|
|
|
CrossNamespacePackTest();
|
2018-09-24 12:03:31 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-08-28 16:54:58 -07:00
|
|
|
} // namespace
|
|
|
|
|
} // namespace tests
|
|
|
|
|
} // namespace flatbuffers
|
2018-09-24 12:03:31 -07:00
|
|
|
|
2025-09-23 21:19:33 -07:00
|
|
|
int main(int argc, const char* argv[]) {
|
2023-05-09 20:33:54 -07:00
|
|
|
std::string tests_data_path = "tests/";
|
2022-08-28 16:54:58 -07:00
|
|
|
|
2022-01-27 14:21:01 -08:00
|
|
|
for (int argi = 1; argi < argc; argi++) {
|
|
|
|
|
std::string arg = argv[argi];
|
|
|
|
|
if (arg == "--test_path") {
|
|
|
|
|
if (++argi >= argc) {
|
|
|
|
|
fprintf(stderr, "error: missing path following: %s\n", arg.c_str());
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
2022-08-28 16:54:58 -07:00
|
|
|
// Override default path if provided one.
|
|
|
|
|
tests_data_path = argv[argi];
|
|
|
|
|
|
2022-01-27 14:21:01 -08:00
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "error: Unknown argument: %s\n", arg.c_str());
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-04 02:04:14 +07:00
|
|
|
InitTestEngine();
|
2018-09-24 12:03:31 -07:00
|
|
|
|
2018-11-17 00:24:06 +07:00
|
|
|
std::string req_locale;
|
|
|
|
|
if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
|
2019-05-03 03:57:58 +07:00
|
|
|
&req_locale)) {
|
2018-11-17 00:24:06 +07:00
|
|
|
TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
|
|
|
|
|
req_locale.c_str());
|
|
|
|
|
req_locale = flatbuffers::RemoveStringQuotes(req_locale);
|
|
|
|
|
std::string the_locale;
|
|
|
|
|
TEST_ASSERT_FUNC(
|
|
|
|
|
flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
|
|
|
|
|
TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-28 16:54:58 -07:00
|
|
|
#ifdef FLATBUFFERS_TEST_PATH_PREFIX
|
|
|
|
|
tests_data_path =
|
|
|
|
|
FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) + tests_data_path;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
flatbuffers::tests::FlatBufferTests(tests_data_path);
|
2018-09-24 12:03:31 -07:00
|
|
|
FlatBufferBuilderTest();
|
|
|
|
|
|
2014-01-27 16:52:49 -08:00
|
|
|
if (!testing_fails) {
|
|
|
|
|
TEST_OUTPUT_LINE("ALL TESTS PASSED");
|
|
|
|
|
} else {
|
|
|
|
|
TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
|
|
|
|
|
}
|
2019-01-25 04:30:11 +07:00
|
|
|
return CloseTestEngine();
|
2014-01-27 16:52:49 -08:00
|
|
|
}
|