#include "flexbuffers_test.h"
#include <limits>
#include "flatbuffers/flexbuffers.h"
#include "flatbuffers/idl.h"
#include "is_quiet_nan.h"
#include "test_assert.h"
namespace flatbuffers {
namespace tests {
static const auto infinity_d = std::numeric_limits<double>::infinity();
void FlexBuffersTest() {
flexbuffers::Builder slb(512,
flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
slb.Map([&]() {
slb.Vector("vec", [&]() {
slb += -100; slb += "Fred";
slb.IndirectFloat(4.0f);
auto i_f = slb.LastValue();
uint8_t blob[] = { 77 };
slb.Blob(blob, 1);
slb += false;
slb.ReuseValue(i_f);
});
int ints[] = { 1, 2, 3 };
slb.Vector("bar", ints, 3);
slb.FixedTypedVector("bar3", ints, 3);
bool bools[] = { true, false, true, false };
slb.Vector("bools", bools, 4);
slb.Bool("bool", true);
slb.Double("foo", 100);
slb.Map("mymap", [&]() {
slb.String("foo", "Fred"); });
});
slb.Finish();
#ifdef FLATBUFFERS_TEST_VERBOSE
for (size_t i = 0; i < slb.GetBuffer().size(); i++)
printf("%d ", slb.GetBuffer().data()[i]);
printf("\n");
#endif
std::vector<uint8_t> reuse_tracker;
TEST_EQ(flexbuffers::VerifyBuffer(slb.GetBuffer().data(),
slb.GetBuffer().size(), &reuse_tracker),
true);
auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
TEST_EQ(map.size(), 7);
auto vec = map["vec"].AsVector();
TEST_EQ(vec.size(), 6);
TEST_EQ(vec[0].AsInt64(), -100);
TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
TEST_EQ(vec[1].AsInt64(), 0); TEST_EQ(vec[2].AsDouble(), 4.0);
TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); TEST_EQ_STR(vec[2].AsString().c_str(), ""); TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); TEST_EQ(vec[0].As<int64_t>(), -100);
TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
TEST_EQ(vec[1].As<int64_t>(), 0); TEST_EQ(vec[2].As<double>(), 4.0);
TEST_EQ(vec[3].IsBlob(), true);
auto blob = vec[3].AsBlob();
TEST_EQ(blob.size(), 1);
TEST_EQ(blob.data()[0], 77);
TEST_EQ(vec[4].IsBool(), true); TEST_EQ(vec[4].AsBool(), false); TEST_EQ(vec[5].AsDouble(), 4.0); auto tvec = map["bar"].AsTypedVector();
TEST_EQ(tvec.size(), 3);
TEST_EQ(tvec[2].AsInt8(), 3);
auto tvec3 = map["bar3"].AsFixedTypedVector();
TEST_EQ(tvec3.size(), 3);
TEST_EQ(tvec3[2].AsInt8(), 3);
TEST_EQ(map["bool"].AsBool(), true);
auto tvecb = map["bools"].AsTypedVector();
TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
TEST_EQ(map["foo"].AsUInt8(), 100);
TEST_EQ(map["unknown"].IsNull(), true);
auto mymap = map["mymap"].AsMap();
TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
TEST_EQ(vec[0].MutateInt(-99), true);
TEST_EQ(vec[0].AsInt64(), -99);
TEST_EQ(vec[1].MutateString("John"), true); TEST_EQ_STR(vec[1].AsString().c_str(), "John");
TEST_EQ(vec[1].MutateString("Alfred"), false); TEST_EQ(vec[2].MutateFloat(2.0f), true);
TEST_EQ(vec[2].AsFloat(), 2.0f);
TEST_EQ(vec[2].MutateFloat(3.14159), false); TEST_EQ(vec[4].AsBool(), false); TEST_EQ(vec[4].MutateBool(true), true); TEST_EQ(vec[4].AsBool(), true);
flatbuffers::Parser parser;
slb.Clear();
auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
TEST_EQ(flexbuffers::VerifyBuffer(slb.GetBuffer().data(),
slb.GetBuffer().size(), &reuse_tracker),
true);
auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
auto jmap = jroot.AsMap();
auto jvec = jmap["a"].AsVector();
TEST_EQ(jvec[0].AsInt64(), 123);
TEST_EQ(jvec[1].AsDouble(), 456.0);
TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
TEST_EQ(jmap["c"].IsBool(), true); TEST_EQ(jmap["c"].AsBool(), true); TEST_EQ(jmap["d"].IsBool(), true); TEST_EQ(jmap["d"].AsBool(), false); auto jsonback = jroot.ToString();
TEST_EQ_STR(jsontest, jsonback.c_str());
std::string jsonback_indented;
jroot.ToString(true, false, jsonback_indented, true, 0, " ");
auto jsontest_indented =
"{\n a: [\n 123,\n 456.0\n ],\n b: \"hello\",\n c: true,\n d: false\n}";
TEST_EQ_STR(jsontest_indented, jsonback_indented.c_str());
slb.Clear();
slb.Vector([&]() {
for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
slb.Vector([&]() {
for (int i = 0; i < 130; ++i) slb.Add(static_cast<uint8_t>(255));
slb.Vector([] {});
});
});
slb.Finish();
TEST_EQ(slb.GetSize(), 664);
}
void FlexBuffersReuseBugTest() {
flexbuffers::Builder slb;
slb.Map([&]() {
slb.Vector("vec", [&]() {});
slb.Bool("bool", true);
});
slb.Finish();
std::vector<uint8_t> reuse_tracker;
TEST_EQ(flexbuffers::VerifyBuffer(slb.GetBuffer().data(),
slb.GetBuffer().size(), &reuse_tracker),
true);
}
void FlexBuffersFloatingPointTest() {
#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
flexbuffers::Builder slb(512,
flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
flatbuffers::Parser parser;
slb.Clear();
auto jsontest =
"{ a: [1.0, nan, inf, infinity, -inf, +inf, -infinity, 8.0] }";
TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
TEST_EQ(flexbuffers::VerifyBuffer(slb.GetBuffer().data(),
slb.GetBuffer().size(), nullptr),
true);
auto jmap = jroot.AsMap();
auto jvec = jmap["a"].AsVector();
TEST_EQ(8, jvec.size());
TEST_EQ(1.0, jvec[0].AsDouble());
TEST_ASSERT(is_quiet_nan(jvec[1].AsDouble()));
TEST_EQ(infinity_d, jvec[2].AsDouble());
TEST_EQ(infinity_d, jvec[3].AsDouble());
TEST_EQ(-infinity_d, jvec[4].AsDouble());
TEST_EQ(+infinity_d, jvec[5].AsDouble());
TEST_EQ(-infinity_d, jvec[6].AsDouble());
TEST_EQ(8.0, jvec[7].AsDouble());
#endif
}
void FlexBuffersDeprecatedTest() {
flexbuffers::Builder slb;
std::string test_data(300, 'A');
auto start = slb.StartVector();
slb.String(test_data);
slb.String("hello");
slb.EndVector(start, true, false);
slb.Finish();
TEST_EQ(flexbuffers::VerifyBuffer(slb.GetBuffer().data(),
slb.GetBuffer().size(), nullptr),
true);
auto vec = flexbuffers::GetRoot(slb.GetBuffer()).AsTypedVector();
TEST_EQ(vec.ElementType(), flexbuffers::FBT_KEY);
TEST_EQ_STR(vec[0].AsKey(), test_data.c_str());
TEST_EQ_STR(vec[0].AsString().c_str(), test_data.c_str());
TEST_EQ_STR(vec[1].AsKey(), "hello");
TEST_EQ_STR(vec[1].AsString().c_str(), "hello");
}
void ParseFlexbuffersFromJsonWithNullTest() {
{
char json[] = "{\"opt_field\": 123 }";
flatbuffers::Parser parser;
flexbuffers::Builder flexbuild;
parser.ParseFlexBuffer(json, nullptr, &flexbuild);
auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
TEST_EQ(root.AsMap()["opt_field"].AsInt64(), 123);
}
{
char json[] = "{\"opt_field\": 123.4 }";
flatbuffers::Parser parser;
flexbuffers::Builder flexbuild;
parser.ParseFlexBuffer(json, nullptr, &flexbuild);
auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
TEST_EQ(root.AsMap()["opt_field"].AsDouble(), 123.4);
}
{
char json[] = "{\"opt_field\": null }";
flatbuffers::Parser parser;
flexbuffers::Builder flexbuild;
parser.ParseFlexBuffer(json, nullptr, &flexbuild);
auto root = flexbuffers::GetRoot(flexbuild.GetBuffer());
TEST_ASSERT(!root.AsMap().IsTheEmptyMap());
TEST_ASSERT(root.AsMap()["opt_field"].IsNull());
TEST_EQ(root.ToString(), std::string("{ opt_field: null }"));
}
}
} }