From ed11b08fc9829b45cd3c5c77b4735c2024036cfb Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 3 May 2023 13:03:00 -0700 Subject: [PATCH] GenerateText gives text error on failure --- include/flatbuffers/code_generator.h | 2 + include/flatbuffers/idl.h | 15 +-- include/flatbuffers/registry.h | 6 +- samples/sample_bfbs.cpp | 4 +- samples/sample_text.cpp | 2 +- src/flatc.cpp | 5 +- src/idl_gen_text.cpp | 142 ++++++++++++++------------- tests/fuzz_test.cpp | 2 +- tests/json_test.cpp | 10 +- tests/monster_test.cpp | 9 +- tests/parser_test.cpp | 12 +-- tests/proto_test.cpp | 4 +- tests/test.cpp | 20 ++-- tests/test_assert.h | 1 + 14 files changed, 122 insertions(+), 112 deletions(-) diff --git a/include/flatbuffers/code_generator.h b/include/flatbuffers/code_generator.h index 85d4430cf..a88b789cb 100644 --- a/include/flatbuffers/code_generator.h +++ b/include/flatbuffers/code_generator.h @@ -36,6 +36,8 @@ class CodeGenerator { NOT_IMPLEMENTED = 3 }; + std::string status_detail; + // Generate code from the provided `parser`. // // DEPRECATED: prefer using the other overload of GenerateCode for bfbs. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 6865f12f7..eb385fab8 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -1200,13 +1200,14 @@ class Parser : public ParserState { // strict_json adds "quotes" around field names if true. // If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8 // byte arrays in String values), returns false. -extern bool GenerateTextFromTable(const Parser &parser, const void *table, - const std::string &tablename, - std::string *text); -extern bool GenerateText(const Parser &parser, const void *flatbuffer, - std::string *text); -extern bool GenerateTextFile(const Parser &parser, const std::string &path, - const std::string &file_name); +extern const char *GenerateTextFromTable(const Parser &parser, const void *table, + const std::string &tablename, + std::string *text); +extern const char *GenerateText(const Parser &parser, const void *flatbuffer, + std::string *text); +extern const char *GenerateTextFile(const Parser &parser, + const std::string &path, + const std::string &file_name); // Generate Json schema to string // See idl_gen_json_schema.cpp. diff --git a/include/flatbuffers/registry.h b/include/flatbuffers/registry.h index e8bb8f5e3..80c385c36 100644 --- a/include/flatbuffers/registry.h +++ b/include/flatbuffers/registry.h @@ -52,8 +52,10 @@ class Registry { Parser parser; if (!LoadSchema(ident, &parser)) return false; // Now we're ready to generate text. - if (!GenerateText(parser, flatbuf, dest)) { - lasterror_ = "unable to generate text for FlatBuffer binary"; + auto err = GenerateText(parser, flatbuf, dest); + if (err) { + lasterror_ = "unable to generate text for FlatBuffer binary: " + + std::string(err); return false; } return true; diff --git a/samples/sample_bfbs.cpp b/samples/sample_bfbs.cpp index 560de70bc..c0017bea3 100644 --- a/samples/sample_bfbs.cpp +++ b/samples/sample_bfbs.cpp @@ -59,13 +59,13 @@ int main(int /*argc*/, const char * /*argv*/[]) { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen1; - if (!GenerateText(parser1, parser1.builder_.GetBufferPointer(), &jsongen1)) { + if (GenerateText(parser1, parser1.builder_.GetBufferPointer(), &jsongen1)) { printf("Couldn't serialize parsed data to JSON!\n"); return 1; } std::string jsongen2; - if (!GenerateText(parser2, parser2.builder_.GetBufferPointer(), &jsongen2)) { + if (GenerateText(parser2, parser2.builder_.GetBufferPointer(), &jsongen2)) { printf("Couldn't serialize parsed data to JSON!\n"); return 1; } diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp index d46185b36..8580b523d 100644 --- a/samples/sample_text.cpp +++ b/samples/sample_text.cpp @@ -45,7 +45,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; - if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) { + if (GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) { printf("Couldn't serialize parsed data to JSON!\n"); return 1; } diff --git a/src/flatc.cpp b/src/flatc.cpp index 4a3ffb70a..99433c3bf 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -869,7 +869,8 @@ std::unique_ptr FlatCompiler::GenerateCode(const FlatCOptions &options, code_generator->GenerateCode(bfbs_buffer, bfbs_length); if (status != CodeGenerator::Status::OK) { Error("Unable to generate " + code_generator->LanguageName() + - " for " + filebase + " using bfbs generator."); + " for " + filebase + code_generator->status_detail + + " using bfbs generator."); } } else { if ((!code_generator->IsSchemaOnly() || @@ -878,7 +879,7 @@ std::unique_ptr FlatCompiler::GenerateCode(const FlatCOptions &options, filebase) != CodeGenerator::Status::OK) { Error("Unable to generate " + code_generator->LanguageName() + - " for " + filebase); + " for " + filebase + code_generator->status_detail); } } } diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index 9de3a6d37..5100e97a1 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -54,10 +54,10 @@ struct JsonPrinter { // for a single FlatBuffer value into JSON format. // The general case for scalars: template - bool PrintScalar(T val, const Type &type, int /*indent*/) { + void PrintScalar(T val, const Type &type, int /*indent*/) { if (IsBool(type.base_type)) { text += val != 0 ? "true" : "false"; - return true; // done + return; // done } if (opts.output_enum_identifiers && type.enum_def) { @@ -66,7 +66,7 @@ struct JsonPrinter { text += '\"'; text += ev->name; text += '\"'; - return true; // done + return; // done } else if (val && enum_def.attributes.Lookup("bit_flags")) { const auto entry_len = text.length(); const auto u64 = static_cast(val); @@ -84,7 +84,7 @@ struct JsonPrinter { // Don't slice if (u64 != mask) if (mask && (u64 == mask)) { text[text.length() - 1] = '\"'; - return true; // done + return; // done } text.resize(entry_len); // restore } @@ -92,7 +92,7 @@ struct JsonPrinter { } text += NumToString(val); - return true; + return; } void AddComma() { @@ -102,7 +102,7 @@ struct JsonPrinter { // Print a vector or an array of JSON values, comma seperated, wrapped in // "[]". template - bool PrintContainer(PrintScalarTag, const Container &c, size_t size, + const char *PrintContainer(PrintScalarTag, const Container &c, size_t size, const Type &type, int indent, const uint8_t *) { const auto elem_indent = indent + Indent(); text += '['; @@ -113,18 +113,18 @@ struct JsonPrinter { AddNewLine(); } AddIndent(elem_indent); - if (!PrintScalar(c[i], type, elem_indent)) { return false; } + PrintScalar(c[i], type, elem_indent); } AddNewLine(); AddIndent(indent); text += ']'; - return true; + return nullptr; } // Print a vector or an array of JSON values, comma seperated, wrapped in // "[]". template - bool PrintContainer(PrintPointerTag, const Container &c, size_t size, + const char *PrintContainer(PrintPointerTag, const Container &c, size_t size, const Type &type, int indent, const uint8_t *prev_val) { const auto is_struct = IsStruct(type); const auto elem_indent = indent + Indent(); @@ -139,19 +139,18 @@ struct JsonPrinter { auto ptr = is_struct ? reinterpret_cast( c.Data() + type.struct_def->bytesize * i) : c[i]; - if (!PrintOffset(ptr, type, elem_indent, prev_val, - static_cast(i))) { - return false; - } + auto err = PrintOffset(ptr, type, elem_indent, prev_val, + static_cast(i)); + if (err) return err; } AddNewLine(); AddIndent(indent); text += ']'; - return true; + return nullptr; } template - bool PrintVector(const void *val, const Type &type, int indent, + const char *PrintVector(const void *val, const Type &type, int indent, const uint8_t *prev_val) { typedef Vector Container; typedef typename PrintTag::type tag; @@ -162,14 +161,15 @@ struct JsonPrinter { // Print an array a sequence of JSON values, comma separated, wrapped in "[]". template - bool PrintArray(const void *val, size_t size, const Type &type, int indent) { + const char *PrintArray(const void *val, size_t size, const Type &type, + int indent) { typedef Array Container; typedef typename PrintTag::type tag; auto &arr = *reinterpret_cast(val); return PrintContainer(tag(), arr, size, type, indent, nullptr); } - bool PrintOffset(const void *val, const Type &type, int indent, + const char *PrintOffset(const void *val, const Type &type, int indent, const uint8_t *prev_val, soffset_t vector_index) { switch (type.base_type) { case BASE_TYPE_UNION: { @@ -186,7 +186,7 @@ struct JsonPrinter { if (enum_val) { return PrintOffset(val, enum_val->union_type, indent, nullptr, -1); } else { - return false; + return "unknown enum value"; } } case BASE_TYPE_STRUCT: @@ -194,8 +194,9 @@ struct JsonPrinter { indent); case BASE_TYPE_STRING: { auto s = reinterpret_cast(val); - return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8, - opts.natural_utf8); + bool ok = EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8, + opts.natural_utf8); + return ok ? nullptr : "string contains non-utf8 bytes"; } case BASE_TYPE_VECTOR: { const auto vec_type = type.VectorType(); @@ -203,17 +204,15 @@ struct JsonPrinter { // clang-format off switch (vec_type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ - case BASE_TYPE_ ## ENUM: \ - if (!PrintVector( \ - val, vec_type, indent, prev_val)) { \ - return false; \ - } \ - break; + case BASE_TYPE_ ## ENUM: { \ + auto err = PrintVector(val, vec_type, indent, prev_val); \ + if (err) return err; \ + break; } FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD } // clang-format on - return true; + return nullptr; } case BASE_TYPE_ARRAY: { const auto vec_type = type.VectorType(); @@ -221,12 +220,10 @@ struct JsonPrinter { // clang-format off switch (vec_type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ - case BASE_TYPE_ ## ENUM: \ - if (!PrintArray( \ - val, type.fixed_length, vec_type, indent)) { \ - return false; \ - } \ - break; + case BASE_TYPE_ ## ENUM: { \ + auto err = PrintArray(val, type.fixed_length, vec_type, indent); \ + if (err) return err; \ + break; } FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) // Arrays of scalars or structs are only possible. FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) @@ -234,9 +231,11 @@ struct JsonPrinter { case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0); } // clang-format on - return true; + return nullptr; } - default: FLATBUFFERS_ASSERT(0); return false; + default: + FLATBUFFERS_ASSERT(0); + return "unknown type"; } } @@ -250,29 +249,28 @@ struct JsonPrinter { // Generate text for a scalar field. template - bool GenField(const FieldDef &fd, const Table *table, bool fixed, + void GenField(const FieldDef &fd, const Table *table, bool fixed, int indent) { if (fixed) { - return PrintScalar( + PrintScalar( reinterpret_cast(table)->GetField(fd.value.offset), fd.value.type, indent); } else if (fd.IsOptional()) { auto opt = table->GetOptional(fd.value.offset); if (opt) { - return PrintScalar(*opt, fd.value.type, indent); + PrintScalar(*opt, fd.value.type, indent); } else { text += "null"; - return true; } } else { - return PrintScalar( + PrintScalar( table->GetField(fd.value.offset, GetFieldDefault(fd)), fd.value.type, indent); } } // Generate text for non-scalar field. - bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, + const char *GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, int indent, const uint8_t *prev_val) { const void *val = nullptr; if (fixed) { @@ -290,7 +288,7 @@ struct JsonPrinter { auto vec = table->GetPointer *>(fd.value.offset); auto root = flexbuffers::GetRoot(vec->data(), vec->size()); root.ToString(true, opts.strict_json, text); - return true; + return nullptr; } else if (fd.nested_flatbuffer && opts.json_nested_flatbuffers) { auto vec = table->GetPointer *>(fd.value.offset); auto root = GetRoot(vec->data()); @@ -305,7 +303,8 @@ struct JsonPrinter { // Generate text for a struct or table, values separated by commas, indented, // and bracketed by "{}" - bool GenStruct(const StructDef &struct_def, const Table *table, int indent) { + const char *GenStruct(const StructDef &struct_def, const Table *table, + int indent) { text += '{'; int fieldout = 0; const uint8_t *prev_val = nullptr; @@ -329,11 +328,9 @@ struct JsonPrinter { // clang-format off switch (fd.value.type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ - case BASE_TYPE_ ## ENUM: \ - if (!GenField(fd, table, struct_def.fixed, elem_indent)) { \ - return false; \ - } \ - break; + case BASE_TYPE_ ## ENUM: { \ + GenField(fd, table, struct_def.fixed, elem_indent); \ + break; } FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) #undef FLATBUFFERS_TD // Generate drop-thru case statements for all pointer types: @@ -342,10 +339,11 @@ struct JsonPrinter { FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD) #undef FLATBUFFERS_TD - if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) { - return false; - } - break; + { + auto err = GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val); + if (err) return err; + break; + } } // clang-format on // Track prev val for use with union types. @@ -359,7 +357,7 @@ struct JsonPrinter { AddNewLine(); AddIndent(indent); text += '}'; - return true; + return nullptr; } JsonPrinter(const Parser &parser, std::string &dest) @@ -371,16 +369,17 @@ struct JsonPrinter { std::string &text; }; -static bool GenerateTextImpl(const Parser &parser, const Table *table, - const StructDef &struct_def, std::string *_text) { +static const char *GenerateTextImpl(const Parser &parser, const Table *table, + const StructDef &struct_def, std::string *_text) { JsonPrinter printer(parser, *_text); - if (!printer.GenStruct(struct_def, table, 0)) { return false; } + auto err = printer.GenStruct(struct_def, table, 0); + if (err) return err; printer.AddNewLine(); - return true; + return nullptr; } // Generate a text representation of a flatbuffer in JSON format. -bool GenerateTextFromTable(const Parser &parser, const void *table, +const char *GenerateTextFromTable(const Parser &parser, const void *table, const std::string &table_name, std::string *_text) { auto struct_def = parser.LookupStruct(table_name); if (struct_def == nullptr) { return false; } @@ -389,7 +388,7 @@ bool GenerateTextFromTable(const Parser &parser, const void *table, } // Generate a text representation of a flatbuffer in JSON format. -bool GenerateText(const Parser &parser, const void *flatbuffer, +const char *GenerateText(const Parser &parser, const void *flatbuffer, std::string *_text) { FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType() auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot
(flatbuffer) @@ -402,21 +401,24 @@ static std::string TextFileName(const std::string &path, return path + file_name + ".json"; } -bool GenerateTextFile(const Parser &parser, const std::string &path, - const std::string &file_name) { +const char *GenerateTextFile(const Parser &parser, const std::string &path, + const std::string &file_name) { if (parser.opts.use_flexbuffers) { std::string json; parser.flex_root_.ToString(true, parser.opts.strict_json, json); return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), - json.c_str(), json.size(), true); + json.c_str(), json.size(), true) + ? nullptr + : "SaveFile failed"; } - if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true; + if (!parser.builder_.GetSize() || !parser.root_struct_def_) return nullptr; std::string text; - if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) { - return false; - } + auto err = GenerateText(parser, parser.builder_.GetBufferPointer(), &text); + if (err) return err; return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text, - false); + false) + ? nullptr + : "SaveFile failed"; } std::string TextMakeRule(const Parser &parser, const std::string &path, @@ -439,7 +441,11 @@ class TextCodeGenerator : public CodeGenerator { public: Status GenerateCode(const Parser &parser, const std::string &path, const std::string &filename) override { - if (!GenerateTextFile(parser, path, filename)) { return Status::ERROR; } + auto err = GenerateTextFile(parser, path, filename); + if (err) { + status_detail = " (" + std::string(err) + ")"; + return Status::ERROR; + } return Status::OK; } diff --git a/tests/fuzz_test.cpp b/tests/fuzz_test.cpp index b0ba3cd30..f6ee238d7 100644 --- a/tests/fuzz_test.cpp +++ b/tests/fuzz_test.cpp @@ -275,7 +275,7 @@ void FuzzTest2() { parser.opts.indent_step = 0; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); if (jsongen != json) { // These strings are larger than a megabyte, so we show the bytes around diff --git a/tests/json_test.cpp b/tests/json_test.cpp index e4249f9ec..8acbb10ee 100644 --- a/tests/json_test.cpp +++ b/tests/json_test.cpp @@ -37,7 +37,7 @@ void JsonDefaultTest(const std::string& tests_data_path) { FinishMonsterBuffer(builder, color_monster.Finish()); std::string jsongen; auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); // default value of the "color" field is Blue TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true); // default value of the "testf" field is 3.14159 @@ -66,7 +66,7 @@ void JsonEnumsTest(const std::string& tests_data_path) { FinishMonsterBuffer(builder, color_monster.Finish()); std::string jsongen; auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true); // Test forward compatibility with 'output_enum_identifiers = true'. // Current Color doesn't have '(1u << 2)' field, let's add it. @@ -79,7 +79,7 @@ void JsonEnumsTest(const std::string& tests_data_path) { static_cast((1u << 2) | Color_Blue | Color_Red)); FinishMonsterBuffer(builder, future_color.Finish()); result = GenerateText(parser, builder.GetBufferPointer(), &future_json); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ(std::string::npos != future_json.find("color: 13"), true); } @@ -120,7 +120,7 @@ void JsonOptionalTest(const std::string& tests_data_path, bool default_scalars) std::string jsongen; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str()); } @@ -199,7 +199,7 @@ root_type JsonUnionStructTest; std::string json_generated; auto generate_result = GenerateText(parser, parser.builder_.GetBufferPointer(), &json_generated); - TEST_EQ(true, generate_result); + TEST_NULL(generate_result); TEST_EQ_STR(json_source, json_generated.c_str()); } diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp index ed6d55bf6..2ca3277a9 100644 --- a/tests/monster_test.cpp +++ b/tests/monster_test.cpp @@ -626,7 +626,7 @@ void TestMonsterExtraFloats(const std::string &tests_data_path) { TEST_EQ(def_extra->d3(), -infinity_d); std::string jsongen; auto result = GenerateText(parser, def_obj, &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); // Check expected default values. TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true); TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true); @@ -777,7 +777,7 @@ void ParseAndGenerateTextTest(const std::string &tests_data_path, bool binary) { std::string jsongen; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str()); // We can also do the above using the convenient Registry that knows about @@ -815,9 +815,8 @@ void ParseAndGenerateTextTest(const std::string &tests_data_path, bool binary) { // request natural printing for utf-8 strings parser.opts.natural_utf8 = true; parser.opts.strict_json = true; - TEST_EQ( - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8), - true); + TEST_NULL( + GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8)); TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str()); } diff --git a/tests/parser_test.cpp b/tests/parser_test.cpp index 4d9e0762b..7bcf62bff 100644 --- a/tests/parser_test.cpp +++ b/tests/parser_test.cpp @@ -455,8 +455,8 @@ T TestValue(const char *json, const char *type_name, // Check with print. std::string print_back; parser.opts.indent_step = -1; - TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back), - true); + TEST_NULL( + GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back)); // restore value from its default if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); } @@ -713,7 +713,7 @@ void UnicodeTest() { parser.opts.indent_step = -1; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}"); @@ -733,7 +733,7 @@ void UnicodeTestAllowNonUTF8() { parser.opts.indent_step = -1; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR( jsongen.c_str(), "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" @@ -759,7 +759,7 @@ void UnicodeTestGenerateTextFailsOnNonUTF8() { parser.opts.allow_non_utf8 = false; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, false); + TEST_EQ_STR(result, "string contains non-utf8 bytes"); } void UnicodeSurrogatesTest() { @@ -800,7 +800,7 @@ void UnknownFieldsTest() { parser.opts.indent_step = -1; auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}"); } diff --git a/tests/proto_test.cpp b/tests/proto_test.cpp index 6c98bc140..3480bc57f 100644 --- a/tests/proto_test.cpp +++ b/tests/proto_test.cpp @@ -317,9 +317,9 @@ void ParseProtoBufAsciiTest() { TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true); // Similarly, in text output, it should omit these. std::string text; - auto ok = flatbuffers::GenerateText( + auto err = flatbuffers::GenerateText( parser, parser.builder_.GetBufferPointer(), &text); - TEST_EQ(ok, true); + TEST_NULL(err); TEST_EQ_STR(text.c_str(), "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n"); } diff --git a/tests/test.cpp b/tests/test.cpp index 6bc23ed6d..e7d154d48 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -120,12 +120,12 @@ void GenerateTableTextTest(const std::string &tests_data_path) { std::string jsongen; auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster", &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); // Test sub table const Vec3 *pos = monster->pos(); jsongen.clear(); result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); 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}}"); @@ -133,13 +133,13 @@ void GenerateTableTextTest(const std::string &tests_data_path) { jsongen.clear(); result = GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}"); const Test *test4 = monster->test4()->Get(0); jsongen.clear(); result = GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}"); } @@ -337,7 +337,7 @@ void UnionVectorTest(const std::string &tests_data_path) { // Generate text using parsed schema. std::string jsongen; auto result = GenerateText(parser, fbb.GetBufferPointer(), &jsongen); - TEST_EQ(result, true); + TEST_NULL(result); TEST_EQ_STR(jsongen.c_str(), "{\n" " main_character_type: \"Rapunzel\",\n" @@ -955,9 +955,8 @@ void FixedLengthArrayJsonTest(const std::string &tests_data_path, bool binary) { // Export to JSON std::string jsonGen; - TEST_EQ( - GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen), - true); + TEST_NULL( + GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen)); // Import from JSON TEST_EQ(parserGen.Parse(jsonGen.c_str()), true); @@ -1082,9 +1081,8 @@ void TestEmbeddedBinarySchema(const std::string &tests_data_path) { // Export to JSON std::string jsonGen; - TEST_EQ( - GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen), - true); + TEST_NULL( + GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen)); // Import from JSON TEST_EQ(parserGen.Parse(jsonGen.c_str()), true); diff --git a/tests/test_assert.h b/tests/test_assert.h index 8b4133827..75e5c518d 100644 --- a/tests/test_assert.h +++ b/tests/test_assert.h @@ -19,6 +19,7 @@ #define TEST_EQ(exp, val) TestEq(exp, val, "'" #exp "' != '" #val "'", __FILE__, __LINE__, "") #define TEST_NE(exp, val) TestNe(exp, val, "'" #exp "' == '" #val "'", __FILE__, __LINE__, "") #define TEST_ASSERT(val) TestEq(true, !!(val), "'" "true" "' != '" #val "'", __FILE__, __LINE__, "") +#define TEST_NULL(val) TestEq(true, (val) == nullptr, "'" "nullptr" "' != '" #val "'", __FILE__, __LINE__, "") #define TEST_NOTNULL(val) TestEq(true, (val) != nullptr, "'" "nullptr" "' == '" #val "'", __FILE__, __LINE__, "") #define TEST_EQ_STR(exp, val) TestEqStr(exp, val, "'" #exp "' != '" #val "'", __FILE__, __LINE__, "")