From 7de1a5e347c2acf13519d162fd39ed89a7a42669 Mon Sep 17 00:00:00 2001 From: ll-antn <42381407+ll-antn@users.noreply.github.com> Date: Fri, 2 Aug 2019 00:16:44 +0300 Subject: [PATCH] [C++ ] Correctly serialize bit_flags enums to JSON with output_enum_identifiers option (#5454) * Support output_enum_identifiers for enums with multiple bit values * Cast bit_flag enum val to uint64_t instead of int64_t --- src/idl_gen_text.cpp | 21 ++++++++++++++++----- tests/test.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index ef2dce7db..9825dcedb 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -51,11 +51,22 @@ bool Print(T val, Type type, int /*indent*/, Type * /*union_type*/, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; if (type.enum_def && opts.output_enum_identifiers) { - auto ev = type.enum_def->ReverseLookup(static_cast(val)); - if (ev) { - text += "\""; - text += ev->name; - text += "\""; + std::vector enum_values; + if (auto ev = type.enum_def->ReverseLookup(static_cast(val))) { + enum_values.push_back(ev); + } else if (val && type.enum_def->attributes.Lookup("bit_flags")) { + for (auto it = type.enum_def->Vals().begin(), + e = type.enum_def->Vals().end(); + it != e; ++it) { + if ((*it)->GetAsUInt64() & static_cast(val)) + enum_values.push_back(*it); + } + } + if (!enum_values.empty()) { + text += '\"'; + for (auto it = enum_values.begin(), e = enum_values.end(); it != e; ++it) + text += (*it)->name + ' '; + text[text.length() - 1] = '\"'; return true; } } diff --git a/tests/test.cpp b/tests/test.cpp index 903c58df7..444455d01 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -620,6 +620,32 @@ void JsonDefaultTest() { TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true); } +void JsonEnumsTest() { + // load FlatBuffer schema (.fbs) from disk + std::string schemafile; + TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(), + false, &schemafile), + true); + // parse schema first, so we can use it to parse the data after + flatbuffers::Parser parser; + auto include_test_path = + flatbuffers::ConCatPathFileName(test_data_path, "include_test"); + const char *include_directories[] = { test_data_path.c_str(), + include_test_path.c_str(), nullptr }; + parser.opts.output_enum_identifiers = true; + TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true); + flatbuffers::FlatBufferBuilder builder; + auto name = builder.CreateString("bitflag_enum"); + MonsterBuilder color_monster(builder); + color_monster.add_name(name); + color_monster.add_color(Color(Color_Blue | Color_Red)); + FinishMonsterBuffer(builder, color_monster.Finish()); + std::string jsongen; + auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); + TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true); +} + #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) // The IEEE-754 quiet_NaN is not simple binary constant. // All binary NaN bit strings have all the bits of the biased exponent field E @@ -2975,6 +3001,7 @@ int FlatBufferTests() { EndianSwapTest(); CreateSharedStringTest(); JsonDefaultTest(); + JsonEnumsTest(); FlexBuffersTest(); UninitializedVectorTest(); EqualOperatorTest();