Add the file a symbol is declared in to Reflection (#6613)

* Add the file a symbol is declared in to Reflection

If we move a code-generator to depend on Reflection,
it may need to know which file something was declared in
to properly name generated files.

* Doc comments in reflection, and more precise tests

* Add --project-root flag to flatc, normalize declaraion_file to this root

* fix --project-root stuff

* posixpath

* fix scripts

* format

* rename --project-root to --bfbs-filenames

Also, make it optional, rather than defaulting to `./`, if its not
specified, then don't serialize the filenames.

* bfbs generation

* fix some tests

* uncomment a thing

* add  to project root directory conditionally

* fix

* git clang format

* Added help description and removed != nullptr

* "

* Remove accidental change to docs

* Remove accidental change to docs

* Pool strings

Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
Casper
2021-06-17 11:50:04 -04:00
committed by GitHub
parent 2cf7bb7966
commit c58ae94225
20 changed files with 868 additions and 674 deletions

View File

@@ -443,6 +443,7 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS)
OUTPUT ${GEN_BINARY_SCHEMA}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}"
-b --schema --bfbs-comments --bfbs-builtins
--bfbs-filenames ${SRC_FBS_DIR}
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
-o "${SRC_FBS_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
@@ -468,6 +469,7 @@ function(compile_flatbuffers_schema_to_embedded_binary SRC_FBS OPT)
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
${OPT}
--bfbs-comments --bfbs-builtins --bfbs-gen-embed
--bfbs-filenames ${SRC_FBS_DIR}
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
-o "${SRC_FBS_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"

View File

@@ -41,7 +41,7 @@ generator="--grpc $current_dir/greeter.fbs"
cd go
cd greeter
fbc --go ${generator}
fbc --bfbs-filenames ../.. --go ${generator}
cd ${current_dir}
@@ -50,7 +50,7 @@ cd python
cd greeter
fbc --python ${generator}
fbc --bfbs-filenames ../.. --python ${generator}
cd ${current_dir}
@@ -58,7 +58,7 @@ cd ${current_dir}
cd swift
cd Greeter/Sources/Model
fbc --swift ${generator}
fbc --bfbs-filenames ../../../.. --swift ${generator}
cd ${current_dir}
@@ -66,6 +66,6 @@ cd ${current_dir}
cd ts
cd greeter/src
fbc --ts ${generator}
fbc --bfbs-filenames ../../.. --ts ${generator}
cd ${current_dir}

View File

@@ -266,7 +266,8 @@ struct Definition {
defined_namespace(nullptr),
serialized_location(0),
index(-1),
refcount(1) {}
refcount(1),
declaration_file(nullptr) {}
flatbuffers::Offset<
flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
@@ -286,6 +287,7 @@ struct Definition {
uoffset_t serialized_location;
int index; // Inside the vector it is stored.
int refcount;
const std::string *declaration_file;
};
struct FieldDef : public Definition {
@@ -591,6 +593,7 @@ struct IDLOptions {
std::string filename_suffix;
std::string filename_extension;
bool no_warnings;
std::string project_root;
// Possible options for the more general generator below.
enum Language {
@@ -677,6 +680,7 @@ struct IDLOptions {
filename_suffix("_generated"),
filename_extension(),
no_warnings(false),
project_root(""),
lang(IDLOptions::kJava),
mini_reflect(IDLOptions::kNone),
require_explicit_ids(false),
@@ -941,14 +945,15 @@ class Parser : public ParserState {
StructDef *LookupCreateStruct(const std::string &name,
bool create_if_new = true,
bool definition = false);
FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest,
const char *filename);
FLATBUFFERS_CHECKED_ERROR ParseNamespace();
FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name,
StructDef **dest);
FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name, bool is_union,
EnumDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseDecl();
FLATBUFFERS_CHECKED_ERROR ParseService();
FLATBUFFERS_CHECKED_ERROR ParseDecl(const char *filename);
FLATBUFFERS_CHECKED_ERROR ParseService(const char *filename);
FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def,
bool isextend, bool inside_oneof);
FLATBUFFERS_CHECKED_ERROR ParseProtoOption();
@@ -985,6 +990,8 @@ class Parser : public ParserState {
FLATBUFFERS_CHECKED_ERROR RecurseError();
template<typename F> CheckedError Recurse(F f);
const std::string &GetPooledString(const std::string &s) const;
public:
SymbolTable<Type> types_;
SymbolTable<StructDef> structs_;
@@ -1020,6 +1027,10 @@ class Parser : public ParserState {
std::vector<std::pair<Value, FieldDef *>> field_stack_;
// TODO(cneo): Refactor parser to use string_cache more often to save
// on memory usage.
mutable std::set<std::string> string_cache_;
int anonymous_counter_;
int parse_depth_counter_; // stack-overflow guard
};

View File

@@ -114,6 +114,7 @@ inline const char *EnumNameBaseType(BaseType e) {
return EnumNamesBaseType()[index];
}
/// New schema language features that are not supported by old code generators.
enum AdvancedFeatures {
AdvancedArrayFeatures = 1ULL,
AdvancedUnionFeatures = 2ULL,
@@ -401,7 +402,8 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_IS_UNION = 8,
VT_UNDERLYING_TYPE = 10,
VT_ATTRIBUTES = 12,
VT_DOCUMENTATION = 14
VT_DOCUMENTATION = 14,
VT_DECLARATION_FILE = 16
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -427,6 +429,10 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
/// File that this Enum is declared in.
const flatbuffers::String *declaration_file() const {
return GetPointer<const flatbuffers::String *>(VT_DECLARATION_FILE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
@@ -443,6 +449,8 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
VerifyOffset(verifier, VT_DECLARATION_FILE) &&
verifier.VerifyString(declaration_file()) &&
verifier.EndTable();
}
};
@@ -469,6 +477,9 @@ struct EnumBuilder {
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation);
}
void add_declaration_file(flatbuffers::Offset<flatbuffers::String> declaration_file) {
fbb_.AddOffset(Enum::VT_DECLARATION_FILE, declaration_file);
}
explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -490,8 +501,10 @@ inline flatbuffers::Offset<Enum> CreateEnum(
bool is_union = false,
flatbuffers::Offset<reflection::Type> underlying_type = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0,
flatbuffers::Offset<flatbuffers::String> declaration_file = 0) {
EnumBuilder builder_(_fbb);
builder_.add_declaration_file(declaration_file);
builder_.add_documentation(documentation);
builder_.add_attributes(attributes);
builder_.add_underlying_type(underlying_type);
@@ -508,11 +521,13 @@ inline flatbuffers::Offset<Enum> CreateEnumDirect(
bool is_union = false,
flatbuffers::Offset<reflection::Type> underlying_type = 0,
std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr,
const char *declaration_file = nullptr) {
auto name__ = name ? _fbb.CreateString(name) : 0;
auto values__ = values ? _fbb.CreateVectorOfSortedTables<reflection::EnumVal>(values) : 0;
auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0;
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0;
return reflection::CreateEnum(
_fbb,
name__,
@@ -520,7 +535,8 @@ inline flatbuffers::Offset<Enum> CreateEnumDirect(
is_union,
underlying_type,
attributes__,
documentation__);
documentation__,
declaration_file__);
}
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -730,7 +746,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_MINALIGN = 10,
VT_BYTESIZE = 12,
VT_ATTRIBUTES = 14,
VT_DOCUMENTATION = 16
VT_DOCUMENTATION = 16,
VT_DECLARATION_FILE = 18
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -759,6 +776,10 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
/// File that this Object is declared in.
const flatbuffers::String *declaration_file() const {
return GetPointer<const flatbuffers::String *>(VT_DECLARATION_FILE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
@@ -775,6 +796,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
VerifyOffset(verifier, VT_DECLARATION_FILE) &&
verifier.VerifyString(declaration_file()) &&
verifier.EndTable();
}
};
@@ -804,6 +827,9 @@ struct ObjectBuilder {
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation);
}
void add_declaration_file(flatbuffers::Offset<flatbuffers::String> declaration_file) {
fbb_.AddOffset(Object::VT_DECLARATION_FILE, declaration_file);
}
explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -825,8 +851,10 @@ inline flatbuffers::Offset<Object> CreateObject(
int32_t minalign = 0,
int32_t bytesize = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0,
flatbuffers::Offset<flatbuffers::String> declaration_file = 0) {
ObjectBuilder builder_(_fbb);
builder_.add_declaration_file(declaration_file);
builder_.add_documentation(documentation);
builder_.add_attributes(attributes);
builder_.add_bytesize(bytesize);
@@ -845,11 +873,13 @@ inline flatbuffers::Offset<Object> CreateObjectDirect(
int32_t minalign = 0,
int32_t bytesize = 0,
std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr,
const char *declaration_file = nullptr) {
auto name__ = name ? _fbb.CreateString(name) : 0;
auto fields__ = fields ? _fbb.CreateVectorOfSortedTables<reflection::Field>(fields) : 0;
auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0;
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0;
return reflection::CreateObject(
_fbb,
name__,
@@ -858,7 +888,8 @@ inline flatbuffers::Offset<Object> CreateObjectDirect(
minalign,
bytesize,
attributes__,
documentation__);
documentation__,
declaration_file__);
}
struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -983,7 +1014,8 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_NAME = 4,
VT_CALLS = 6,
VT_ATTRIBUTES = 8,
VT_DOCUMENTATION = 10
VT_DOCUMENTATION = 10,
VT_DECLARATION_FILE = 12
};
const flatbuffers::String *name() const {
return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -1003,6 +1035,10 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
}
/// File that this Service is declared in.
const flatbuffers::String *declaration_file() const {
return GetPointer<const flatbuffers::String *>(VT_DECLARATION_FILE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_NAME) &&
@@ -1016,6 +1052,8 @@ struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyOffset(verifier, VT_DOCUMENTATION) &&
verifier.VerifyVector(documentation()) &&
verifier.VerifyVectorOfStrings(documentation()) &&
VerifyOffset(verifier, VT_DECLARATION_FILE) &&
verifier.VerifyString(declaration_file()) &&
verifier.EndTable();
}
};
@@ -1036,6 +1074,9 @@ struct ServiceBuilder {
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation);
}
void add_declaration_file(flatbuffers::Offset<flatbuffers::String> declaration_file) {
fbb_.AddOffset(Service::VT_DECLARATION_FILE, declaration_file);
}
explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -1053,8 +1094,10 @@ inline flatbuffers::Offset<Service> CreateService(
flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>>> calls = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0,
flatbuffers::Offset<flatbuffers::String> declaration_file = 0) {
ServiceBuilder builder_(_fbb);
builder_.add_declaration_file(declaration_file);
builder_.add_documentation(documentation);
builder_.add_attributes(attributes);
builder_.add_calls(calls);
@@ -1067,17 +1110,20 @@ inline flatbuffers::Offset<Service> CreateServiceDirect(
const char *name = nullptr,
std::vector<flatbuffers::Offset<reflection::RPCCall>> *calls = nullptr,
std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr,
const char *declaration_file = nullptr) {
auto name__ = name ? _fbb.CreateString(name) : 0;
auto calls__ = calls ? _fbb.CreateVectorOfSortedTables<reflection::RPCCall>(calls) : 0;
auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0;
auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
auto declaration_file__ = declaration_file ? _fbb.CreateString(declaration_file) : 0;
return reflection::CreateService(
_fbb,
name__,
calls__,
attributes__,
documentation__);
documentation__,
declaration_file__);
}
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -1089,7 +1135,8 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_FILE_EXT = 10,
VT_ROOT_TABLE = 12,
VT_SERVICES = 14,
VT_ADVANCED_FEATURES = 16
VT_ADVANCED_FEATURES = 16,
VT_FBS_FILES = 18
};
const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *>(VT_OBJECTS);
@@ -1112,6 +1159,11 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
reflection::AdvancedFeatures advanced_features() const {
return static_cast<reflection::AdvancedFeatures>(GetField<uint64_t>(VT_ADVANCED_FEATURES, 0));
}
/// All the files used in this compilation. Files are relative to where
/// flatc was invoked.
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *fbs_files() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_FBS_FILES);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
@@ -1130,6 +1182,9 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
verifier.VerifyVector(services()) &&
verifier.VerifyVectorOfTables(services()) &&
VerifyField<uint64_t>(verifier, VT_ADVANCED_FEATURES) &&
VerifyOffset(verifier, VT_FBS_FILES) &&
verifier.VerifyVector(fbs_files()) &&
verifier.VerifyVectorOfStrings(fbs_files()) &&
verifier.EndTable();
}
};
@@ -1159,6 +1214,9 @@ struct SchemaBuilder {
void add_advanced_features(reflection::AdvancedFeatures advanced_features) {
fbb_.AddElement<uint64_t>(Schema::VT_ADVANCED_FEATURES, static_cast<uint64_t>(advanced_features), 0);
}
void add_fbs_files(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> fbs_files) {
fbb_.AddOffset(Schema::VT_FBS_FILES, fbs_files);
}
explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -1180,9 +1238,11 @@ inline flatbuffers::Offset<Schema> CreateSchema(
flatbuffers::Offset<flatbuffers::String> file_ext = 0,
flatbuffers::Offset<reflection::Object> root_table = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services = 0,
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) {
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0),
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> fbs_files = 0) {
SchemaBuilder builder_(_fbb);
builder_.add_advanced_features(advanced_features);
builder_.add_fbs_files(fbs_files);
builder_.add_services(services);
builder_.add_root_table(root_table);
builder_.add_file_ext(file_ext);
@@ -1200,12 +1260,14 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
const char *file_ext = nullptr,
flatbuffers::Offset<reflection::Object> root_table = 0,
std::vector<flatbuffers::Offset<reflection::Service>> *services = nullptr,
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) {
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0),
const std::vector<flatbuffers::Offset<flatbuffers::String>> *fbs_files = nullptr) {
auto objects__ = objects ? _fbb.CreateVectorOfSortedTables<reflection::Object>(objects) : 0;
auto enums__ = enums ? _fbb.CreateVectorOfSortedTables<reflection::Enum>(enums) : 0;
auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0;
auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0;
auto services__ = services ? _fbb.CreateVectorOfSortedTables<reflection::Service>(services) : 0;
auto fbs_files__ = fbs_files ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*fbs_files) : 0;
return reflection::CreateSchema(
_fbb,
objects__,
@@ -1214,7 +1276,8 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
file_ext__,
root_table,
services__,
advanced_features);
advanced_features,
fbs_files__);
}
inline const reflection::Schema *GetSchema(const void *buf) {

View File

@@ -468,6 +468,7 @@ std::string ConCatPathFileName(const std::string &path,
// Replaces any '\\' separators with '/'
std::string PosixPath(const char *path);
std::string PosixPath(const std::string &path);
// This function ensure a directory exists, by recursively
// creating dirs for any parts of the path that don't exist yet.
@@ -477,6 +478,10 @@ void EnsureDirExists(const std::string &filepath);
// Returns the input path if the absolute path couldn't be resolved.
std::string AbsolutePath(const std::string &filepath);
// Returns files relative to the --project_root path, prefixed with `//`.
std::string RelativeToRootPath(const std::string &project,
const std::string &filepath);
// To and from UTF-8 unicode conversion functions
// Convert a unicode code point into a UTF-8 representation by appending it

View File

@@ -60,6 +60,8 @@ table Enum {
underlying_type:Type (required);
attributes:[KeyValue];
documentation:[string];
/// File that this Enum is declared in.
declaration_file: string;
}
table Field {
@@ -85,6 +87,8 @@ table Object { // Used for both tables and structs.
bytesize:int; // For structs.
attributes:[KeyValue];
documentation:[string];
/// File that this Object is declared in.
declaration_file: string;
}
table RPCCall {
@@ -100,9 +104,11 @@ table Service {
calls:[RPCCall];
attributes:[KeyValue];
documentation:[string];
/// File that this Service is declared in.
declaration_file: string;
}
// New schema language features that are not supported by old code generators.
/// New schema language features that are not supported by old code generators.
enum AdvancedFeatures : ulong (bit_flags) {
AdvancedArrayFeatures,
AdvancedUnionFeatures,
@@ -118,6 +124,9 @@ table Schema {
root_table:Object;
services:[Service]; // Sorted.
advanced_features:AdvancedFeatures;
/// All the files used in this compilation. Files are relative to where
/// flatc was invoked.
fbs_files:[string];
}
root_type Schema;

Binary file not shown.

0
scripts/check-grpc-generated-code.sh Normal file → Executable file
View File

0
scripts/clang-format-all.sh Normal file → Executable file
View File

0
scripts/clang-format-git.sh Normal file → Executable file
View File

View File

@@ -149,6 +149,8 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
" --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
" --grpc Generate GRPC interfaces for the specified languages.\n"
" --schema Serialize schemas instead of JSON (use with -b).\n"
" --bfbs-filenames PATH Adds declaration filenames, relative to PATH and prefixed with"
" `//`, to the binary schema.\n"
" --bfbs-comments Add doc comments to the binary schema files.\n"
" --bfbs-builtins Add builtin attributes to the binary schema files.\n"
" --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n"
@@ -221,6 +223,11 @@ int FlatCompiler::Compile(int argc, const char **argv) {
flatbuffers::PosixPath(argv[argi]));
include_directories.push_back(
include_directories_storage.back().c_str());
} else if (arg == "--bfbs-filenames") {
if (++argi > argc) Error("missing path following: " + arg, true);
opts.project_root = argv[argi];
if (!DirExists(opts.project_root.c_str()))
Error(arg + " is not a directory: " + opts.project_root);
} else if (arg == "--conform") {
if (++argi >= argc) Error("missing path following: " + arg, true);
conform_to_schema = flatbuffers::PosixPath(argv[argi]);
@@ -436,8 +443,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
bool is_binary =
static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
auto ext = flatbuffers::GetExtension(filename);
auto is_schema = ext == "fbs" || ext == "proto";
auto is_binary_schema = ext == reflection::SchemaExtension();
const bool is_schema = ext == "fbs" || ext == "proto";
const bool is_binary_schema = ext == reflection::SchemaExtension();
if (is_binary) {
parser->builder_.Clear();
parser->builder_.PushFlatBuffer(

View File

@@ -158,6 +158,10 @@ CheckedError Parser::RecurseError() {
" reached");
}
const std::string &Parser::GetPooledString(const std::string &s) const {
return *(string_cache_.insert(s).first);
}
class Parser::ParseDepthGuard {
public:
explicit ParseDepthGuard(Parser *parser_not_null)
@@ -2281,13 +2285,18 @@ struct EnumValBuilder {
bool user_value;
};
CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest,
const char *filename) {
std::vector<std::string> enum_comment = doc_comment_;
NEXT();
std::string enum_name = attribute_;
EXPECT(kTokenIdentifier);
EnumDef *enum_def;
ECHECK(StartEnum(enum_name, is_union, &enum_def));
if (filename != nullptr && !opts.project_root.empty()) {
enum_def->declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
enum_def->doc_comment = enum_comment;
if (!is_union && !opts.proto_mode) {
// Give specialized error message, since this type spec used to
@@ -2516,7 +2525,7 @@ static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
return a_id < b_id;
}
CheckedError Parser::ParseDecl() {
CheckedError Parser::ParseDecl(const char *filename) {
std::vector<std::string> dc = doc_comment_;
bool fixed = IsIdent("struct");
if (!fixed && !IsIdent("table")) return Error("declaration expected");
@@ -2527,6 +2536,10 @@ CheckedError Parser::ParseDecl() {
ECHECK(StartStruct(name, &struct_def));
struct_def->doc_comment = dc;
struct_def->fixed = fixed;
if (filename && !opts.project_root.empty()) {
struct_def->declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
ECHECK(ParseMetaData(&struct_def->attributes));
struct_def->sortbysize =
struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
@@ -2606,7 +2619,7 @@ CheckedError Parser::ParseDecl() {
return NoError();
}
CheckedError Parser::ParseService() {
CheckedError Parser::ParseService(const char *filename) {
std::vector<std::string> service_comment = doc_comment_;
NEXT();
auto service_name = attribute_;
@@ -2616,6 +2629,10 @@ CheckedError Parser::ParseService() {
service_def.file = file_being_parsed_;
service_def.doc_comment = service_comment;
service_def.defined_namespace = current_namespace_;
if (filename != nullptr && !opts.project_root.empty()) {
service_def.declaration_file =
&GetPooledString(RelativeToRootPath(opts.project_root, filename));
}
if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
&service_def))
return Error("service already exists: " + service_name);
@@ -2731,7 +2748,7 @@ CheckedError Parser::ParseProtoDecl() {
} else if (IsIdent("enum")) {
// These are almost the same, just with different terminator:
EnumDef *enum_def;
ECHECK(ParseEnum(false, &enum_def));
ECHECK(ParseEnum(false, &enum_def, nullptr));
if (Is(';')) NEXT();
// Temp: remove any duplicates, as .fbs files can't handle them.
enum_def->RemoveDuplicates();
@@ -3371,9 +3388,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
} else if (token_ == '{') {
return NoError();
} else if (IsIdent("enum")) {
ECHECK(ParseEnum(false, nullptr));
ECHECK(ParseEnum(false, nullptr, source_filename));
} else if (IsIdent("union")) {
ECHECK(ParseEnum(true, nullptr));
ECHECK(ParseEnum(true, nullptr, source_filename));
} else if (IsIdent("root_type")) {
NEXT();
auto root_type = attribute_;
@@ -3412,9 +3429,9 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
EXPECT(';');
known_attributes_[name] = false;
} else if (IsIdent("rpc_service")) {
ECHECK(ParseService());
ECHECK(ParseService(source_filename));
} else {
ECHECK(ParseDecl());
ECHECK(ParseDecl(source_filename));
}
}
return NoError();
@@ -3491,32 +3508,44 @@ void Parser::Serialize() {
AssignIndices(structs_.vec);
AssignIndices(enums_.vec);
std::vector<Offset<reflection::Object>> object_offsets;
std::set<std::string> files;
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
object_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
std::vector<Offset<reflection::Enum>> enum_offsets;
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
enum_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
std::vector<Offset<reflection::Service>> service_offsets;
for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
service_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
const std::string *file = (*it)->declaration_file;
if (file) files.insert(*file);
}
auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
auto fiid__ = builder_.CreateString(file_identifier_);
auto fext__ = builder_.CreateString(file_extension_);
auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
auto schema_offset = reflection::CreateSchema(
// TODO(caspern): CreateVectorOfSharedStrings
std::vector<Offset<flatbuffers::String>> file_offsets;
for (auto it = files.begin(); it != files.end(); it++) {
file_offsets.push_back(builder_.CreateSharedString(*it));
}
const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
const auto fiid__ = builder_.CreateString(file_identifier_);
const auto fext__ = builder_.CreateString(file_extension_);
const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
const auto files__ = builder_.CreateVector(file_offsets);
const auto schema_offset = reflection::CreateSchema(
builder_, objs__, enum__, fiid__, fext__,
(root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
static_cast<reflection::AdvancedFeatures>(advanced_features_));
static_cast<reflection::AdvancedFeatures>(advanced_features_), files__);
if (opts.size_prefixed) {
builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
} else {
@@ -3557,16 +3586,18 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
field_offsets.push_back((*it)->Serialize(
builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
return reflection::CreateObject(*builder, name__, flds__, fixed,
static_cast<int>(minalign),
static_cast<int>(bytesize), attr__, docs__);
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateObject(
*builder, name__, flds__, fixed, static_cast<int>(minalign),
static_cast<int>(bytesize), attr__, docs__, file__);
}
bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
@@ -3685,14 +3716,17 @@ Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
servicecall_offsets.push_back((*it)->Serialize(builder, parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto call__ = builder->CreateVector(servicecall_offsets);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto call__ = builder->CreateVector(servicecall_offsets);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
return reflection::CreateService(*builder, name__, call__, attr__, docs__);
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateService(*builder, name__, call__, attr__, docs__,
file__);
}
bool ServiceDef::Deserialize(Parser &parser,
@@ -3719,16 +3753,18 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder, parser));
}
auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
auto name__ = builder->CreateString(qualified_name);
auto vals__ = builder->CreateVector(enumval_offsets);
auto type__ = underlying_type.Serialize(builder);
auto attr__ = SerializeAttributes(builder, parser);
auto docs__ = parser.opts.binary_schema_comments
const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
const auto name__ = builder->CreateString(qualified_name);
const auto vals__ = builder->CreateVector(enumval_offsets);
const auto type__ = underlying_type.Serialize(builder);
const auto attr__ = SerializeAttributes(builder, parser);
const auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
std::string decl_file_in_project = declaration_file ? *declaration_file : "";
const auto file__ = builder->CreateSharedString(decl_file_in_project);
return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
attr__, docs__);
attr__, docs__, file__);
}
bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {

View File

@@ -178,6 +178,9 @@ std::string PosixPath(const char *path) {
std::replace(p.begin(), p.end(), '\\', '/');
return p;
}
std::string PosixPath(const std::string &path) {
return PosixPath(path.c_str());
}
void EnsureDirExists(const std::string &filepath) {
auto parent = StripFileName(filepath);
@@ -217,6 +220,27 @@ std::string AbsolutePath(const std::string &filepath) {
// clang-format on
}
std::string RelativeToRootPath(const std::string &project,
const std::string &filepath) {
std::string absolute_project = PosixPath(AbsolutePath(project));
if (absolute_project.back() != '/') absolute_project += "/";
std::string absolute_filepath = PosixPath(AbsolutePath(filepath));
if (absolute_filepath.size() < absolute_project.size() ||
absolute_filepath.substr(0, absolute_project.size()) !=
absolute_project) {
printf(
"The --bfbs-filenames directory must contain all files and included "
"files.\n");
printf("project: %s\n", project.c_str());
printf("filepath: %s\n", filepath.c_str());
printf("absolute_project: %s\n", absolute_project.c_str());
printf("absolute_filepath:%s\n", absolute_filepath.c_str());
FLATBUFFERS_ASSERT(0);
}
const std::string relpath = absolute_filepath.substr(absolute_project.size());
return "//" + relpath;
}
// Locale-independent code.
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
(FLATBUFFERS_LOCALE_INDEPENDENT > 0)

Binary file not shown.

View File

@@ -53,7 +53,7 @@ set TEST_NOINCL_FLAGS=%TEST_BASE_FLAGS% --no-includes
..\%buildtype%\flatc.exe --ts --gen-name-strings %TEST_BASE_FLAGS% %TEST_TS_FLAGS% -o union_vector union_vector/union_vector.fbs
..\%buildtype%\flatc.exe --rust -I include_test -o include_test include_test/include_test1.fbs || goto FAIL
..\%buildtype%\flatc.exe --rust -I include_test -o include_test/sub include_test/sub/include_test2.fbs || goto FAIL
..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs || goto FAIL
..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-filenames . --bfbs-builtins -I include_test monster_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --cpp --bfbs-comments --bfbs-builtins --bfbs-gen-embed %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% -I include_test monster_test.fbs || goto FAIL
..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs || goto FAIL

View File

@@ -50,7 +50,7 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_TS_FLAGS -o namespace_te
../flatc --ts --gen-name-strings $TEST_BASE_FLAGS $TEST_TS_FLAGS -o union_vector union_vector/union_vector.fbs
../flatc --rust -I include_test -o include_test include_test/include_test1.fbs
../flatc --rust -I include_test -o include_test/sub include_test/sub/include_test2.fbs
../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs
../flatc -b --schema --bfbs-comments --bfbs-filenames . --bfbs-builtins -I include_test monster_test.fbs
../flatc --cpp --bfbs-comments --bfbs-builtins --bfbs-gen-embed $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS -I include_test monster_test.fbs
../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs
@@ -72,10 +72,10 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_TS_FLAGS -o namespace_te
working_dir=`pwd`
cd FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests
$working_dir/../flatc --swift --grpc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS -I ${working_dir}/include_test ${working_dir}/monster_test.fbs
$working_dir/../flatc --swift $TEST_BASE_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS ${working_dir}/union_vector/union_vector.fbs
$working_dir/../flatc --swift ${working_dir}/optional_scalars.fbs
$working_dir/../flatc --swift --gen-object-api ${working_dir}/more_defaults.fbs
$working_dir/../flatc --bfbs-filenames $working_dir --swift --grpc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS -I ${working_dir}/include_test ${working_dir}/monster_test.fbs
$working_dir/../flatc --bfbs-filenames $working_dir --swift $TEST_BASE_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS ${working_dir}/union_vector/union_vector.fbs
$working_dir/../flatc --bfbs-filenames $working_dir --swift ${working_dir}/optional_scalars.fbs
$working_dir/../flatc --bfbs-filenames $working_dir --swift --gen-object-api ${working_dir}/more_defaults.fbs
cd $working_dir
# Tests if the --filename-suffix and --filename-ext works and produces the same

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
fn main() {
use std::process::Command;
let project_root = std::env::current_dir()
.unwrap()
.parent() // flatbuffers/tests/rust_usage test
@@ -10,7 +9,6 @@ fn main() {
.parent() // flatbuffers/
.unwrap()
.to_path_buf();
let sample_schema = {
let mut s = project_root.to_path_buf();
s.push("samples");
@@ -35,5 +33,6 @@ fn main() {
.expect("Failed to generate file");
let genfile = "monster_gen.rs";
std::fs::rename(&genfile, out_dir.join("monster_generated.rs")).unwrap();
std::fs::rename(&genfile, out_dir.join("monster_generated.rs"))
.expect("Could not rename monster_ge.rs to monster_generated.rs");
}

View File

@@ -919,7 +919,30 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
// Make sure the schema is what we expect it to be.
auto &schema = *reflection::GetSchema(bfbsfile.c_str());
auto root_table = schema.root_table();
// Check the declaration files.
TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
TEST_EQ_STR(root_table->declaration_file()->c_str(), "//monster_test.fbs");
TEST_EQ_STR(
schema.objects()->LookupByKey("TableA")->declaration_file()->c_str(),
"//include_test/include_test1.fbs");
TEST_EQ_STR(schema.objects()
->LookupByKey("MyGame.OtherNameSpace.Unused")
->declaration_file()
->c_str(),
"//include_test/sub/include_test2.fbs");
TEST_EQ_STR(schema.enums()
->LookupByKey("MyGame.OtherNameSpace.FromInclude")
->declaration_file()
->c_str(),
"//include_test/sub/include_test2.fbs");
TEST_EQ(schema.fbs_files()->size(), 3);
TEST_EQ_STR(schema.fbs_files()->Get(0)->c_str(),
"//include_test/include_test1.fbs");
TEST_EQ_STR(schema.fbs_files()->Get(1)->c_str(),
"//include_test/sub/include_test2.fbs");
TEST_EQ_STR(schema.fbs_files()->Get(2)->c_str(), "//monster_test.fbs");
// Check Root table fields
auto fields = root_table->fields();
auto hp_field_ptr = fields->LookupByKey("hp");
TEST_NOTNULL(hp_field_ptr);
@@ -1290,6 +1313,7 @@ void ParseProtoTestWithIncludes() {
flatbuffers::IDLOptions opts;
opts.include_dependence_headers = true;
opts.proto_mode = true;
opts.project_root = test_data_path;
// Parse proto.
flatbuffers::Parser parser(opts);
@@ -1307,9 +1331,15 @@ void ParseProtoTestWithIncludes() {
auto import_fbs = flatbuffers::GenerateFBS(import_parser, "test");
// Ensure generated file is parsable.
flatbuffers::Parser parser2;
TEST_EQ(
parser2.Parse(import_fbs.c_str(), include_directories, "imported.fbs"),
flatbuffers::IDLOptions opts2;
opts2.project_root = protopath;
flatbuffers::Parser parser2(opts2);
// Since `imported.fbs` isn't in the filesystem AbsolutePath can't figure it
// out by itself. We manually construct it so Parser works.
std::string imported_fbs = flatbuffers::PosixPath(
flatbuffers::AbsolutePath(protopath) + "/imported.fbs");
TEST_EQ(parser2.Parse(import_fbs.c_str(), include_directories,
imported_fbs.c_str()),
true);
TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
@@ -1324,7 +1354,8 @@ void ParseProtoTestWithIncludes() {
// Ensure generated file is parsable.
flatbuffers::Parser parser4;
TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, "imported.fbs"), true);
TEST_EQ(parser4.Parse(import_fbs.c_str(), nullptr, imported_fbs.c_str()),
true);
TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
}