Add warning to schema parser if field name is not snake_case. (#6005)

* Added code gen for evolution tests back in.

* General generate code and clang format

* Added code gen for evolution tests back in.

* General generate code and clang format

* reran generate_code.sh

* Added code gen for evolution tests back in.

* General generate code and clang format

* Added code gen for evolution tests back in.

* General generate code and clang format

* Enforce snake_case for schema field names

* Switched to basic for loop, Fixed warning message
This commit is contained in:
Derek Bailey
2020-06-26 11:16:02 -07:00
committed by GitHub
parent 35d45cac7a
commit 60b6066feb
2 changed files with 101 additions and 85 deletions

View File

@@ -82,6 +82,16 @@ static bool ValidateUTF8(const std::string &str) {
return true;
}
static bool IsLowerSnakeCase(const std::string &str) {
for (size_t i = 0; i < str.length(); i++) {
char c = str[i];
if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
return false;
}
}
return true;
}
// Convert an underscore_based_indentifier in to camelCase.
// Also uppercases the first character if first is true.
std::string MakeCamel(const std::string &in, bool first) {
@@ -671,6 +681,10 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
if (LookupCreateStruct(name, false, false))
return Error("field name can not be the same as table/struct name");
if (!IsLowerSnakeCase(name)) {
Warning("field names should be lowercase snake_case, got: " + name);
}
std::vector<std::string> dc = doc_comment_;
EXPECT(kTokenIdentifier);
EXPECT(':');

View File

@@ -1549,7 +1549,7 @@ void TestError_(const char *src, const char *error_substr, bool strict_json,
("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
func);
} else if (!strstr(parser.error_.c_str(), error_substr)) {
TestFail(parser.error_.c_str(), error_substr,
TestFail(error_substr, parser.error_.c_str(),
("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
func);
}
@@ -1626,6 +1626,8 @@ void ErrorTest() {
// Array of non-scalar
TestError("table X { x:int; } struct Y { y:[X:2]; }",
"may contain only scalar or struct fields");
// Non-snake case field names
TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
}
template<typename T>
@@ -1637,7 +1639,7 @@ T TestValue(const char *json, const char *type_name,
if (check_default) { parser.opts.output_default_scalars_in_json = true; }
// Simple schema.
std::string schema = std::string(decls ? decls : "") + "\n" +
"table X { Y:" + std::string(type_name) +
"table X { y:" + std::string(type_name) +
"; } root_type X;";
auto schema_done = parser.Parse(schema.c_str());
TEST_EQ_STR(parser.error_.c_str(), "");
@@ -1666,45 +1668,45 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
void ValueTest() {
// Test scientific notation numbers.
TEST_EQ(
FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
true);
// number in string
TEST_EQ(FloatCompare(TestValue<float>("{ Y:\"0.0314159e+2\" }", "float"),
TEST_EQ(FloatCompare(TestValue<float>("{ y:\"0.0314159e+2\" }", "float"),
3.14159f),
true);
// Test conversion functions.
TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }", "float"), -1),
TEST_EQ(FloatCompare(TestValue<float>("{ y:cos(rad(180)) }", "float"), -1),
true);
// int embedded to string
TEST_EQ(TestValue<int>("{ Y:\"-876\" }", "int=-123"), -876);
TEST_EQ(TestValue<int>("{ Y:\"876\" }", "int=-123"), 876);
TEST_EQ(TestValue<int>("{ y:\"-876\" }", "int=-123"), -876);
TEST_EQ(TestValue<int>("{ y:\"876\" }", "int=-123"), 876);
// Test negative hex constant.
TEST_EQ(TestValue<int>("{ Y:-0x8ea0 }", "int=-0x8ea0"), -36512);
TEST_EQ(TestValue<int>("{ y:-0x8ea0 }", "int=-0x8ea0"), -36512);
TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
// positive hex constant
TEST_EQ(TestValue<int>("{ Y:0x1abcdef }", "int=0x1"), 0x1abcdef);
TEST_EQ(TestValue<int>("{ y:0x1abcdef }", "int=0x1"), 0x1abcdef);
// with optional '+' sign
TEST_EQ(TestValue<int>("{ Y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
TEST_EQ(TestValue<int>("{ y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
// hex in string
TEST_EQ(TestValue<int>("{ Y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
TEST_EQ(TestValue<int>("{ y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
// Make sure we do unsigned 64bit correctly.
TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }", "ulong"),
TEST_EQ(TestValue<uint64_t>("{ y:12335089644688340133 }", "ulong"),
12335089644688340133ULL);
// bool in string
TEST_EQ(TestValue<bool>("{ Y:\"false\" }", "bool=true"), false);
TEST_EQ(TestValue<bool>("{ Y:\"true\" }", "bool=\"true\""), true);
TEST_EQ(TestValue<bool>("{ Y:'false' }", "bool=true"), false);
TEST_EQ(TestValue<bool>("{ Y:'true' }", "bool=\"true\""), true);
TEST_EQ(TestValue<bool>("{ y:\"false\" }", "bool=true"), false);
TEST_EQ(TestValue<bool>("{ y:\"true\" }", "bool=\"true\""), true);
TEST_EQ(TestValue<bool>("{ y:'false' }", "bool=true"), false);
TEST_EQ(TestValue<bool>("{ y:'true' }", "bool=\"true\""), true);
// check comments before and after json object
TEST_EQ(TestValue<int>("/*before*/ { Y:1 } /*after*/", "int"), 1);
TEST_EQ(TestValue<int>("//before \n { Y:1 } //after", "int"), 1);
TEST_EQ(TestValue<int>("/*before*/ { y:1 } /*after*/", "int"), 1);
TEST_EQ(TestValue<int>("//before \n { y:1 } //after", "int"), 1);
}
void NestedListTest() {
@@ -1776,18 +1778,18 @@ void EnumOutOfRangeTest() {
}
void EnumValueTest() {
// json: "{ Y:0 }", schema: table X { Y : "E"}
// json: "{ Y:0 }", schema: table X { y: "E"}
// 0 in enum (V=0) E then Y=0 is valid.
TEST_EQ(TestValue<int>("{ Y:0 }", "E", "enum E:int { V }"), 0);
TEST_EQ(TestValue<int>("{ Y:V }", "E", "enum E:int { V }"), 0);
TEST_EQ(TestValue<int>("{ y:0 }", "E", "enum E:int { V }"), 0);
TEST_EQ(TestValue<int>("{ y:V }", "E", "enum E:int { V }"), 0);
// A default value of Y is 0.
TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5);
TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { V=5 }"), 5);
// Generate json with defaults and check.
TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
// 5 in enum
TEST_EQ(TestValue<int>("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
TEST_EQ(TestValue<int>("{ y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
// Generate json with defaults and check.
TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
@@ -1799,9 +1801,9 @@ void EnumValueTest() {
"enum E:ulong { V = 18446744073709551615 }"),
18446744073709551615ULL);
// Assign non-enum value to enum field. Is it right?
TEST_EQ(TestValue<int>("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7);
TEST_EQ(TestValue<int>("{ y:7 }", "E", "enum E:int { V = 0 }"), 7);
// Check that non-ascending values are valid.
TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
TEST_EQ(TestValue<int>("{ y:5 }", "E=V", "enum E:int { Z=10, V=5 }"), 5);
}
void IntegerOutOfRangeTest() {
@@ -1895,26 +1897,26 @@ void IntegerBoundaryTest() {
TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
18446744073709551615ULL);
TEST_EQ(TestValue<int8_t>("{ Y:127 }", "byte"), 127);
TEST_EQ(TestValue<int8_t>("{ Y:-128 }", "byte"), -128);
TEST_EQ(TestValue<uint8_t>("{ Y:255 }", "ubyte"), 255);
TEST_EQ(TestValue<uint8_t>("{ Y:0 }", "ubyte"), 0);
TEST_EQ(TestValue<int16_t>("{ Y:32767 }", "short"), 32767);
TEST_EQ(TestValue<int16_t>("{ Y:-32768 }", "short"), -32768);
TEST_EQ(TestValue<uint16_t>("{ Y:65535 }", "ushort"), 65535);
TEST_EQ(TestValue<uint16_t>("{ Y:0 }", "ushort"), 0);
TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }", "int"), 2147483647);
TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }", "int") + 1, -2147483647);
TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }", "uint"), 4294967295);
TEST_EQ(TestValue<uint32_t>("{ Y:0 }", "uint"), 0);
TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }", "long"),
TEST_EQ(TestValue<int8_t>("{ y:127 }", "byte"), 127);
TEST_EQ(TestValue<int8_t>("{ y:-128 }", "byte"), -128);
TEST_EQ(TestValue<uint8_t>("{ y:255 }", "ubyte"), 255);
TEST_EQ(TestValue<uint8_t>("{ y:0 }", "ubyte"), 0);
TEST_EQ(TestValue<int16_t>("{ y:32767 }", "short"), 32767);
TEST_EQ(TestValue<int16_t>("{ y:-32768 }", "short"), -32768);
TEST_EQ(TestValue<uint16_t>("{ y:65535 }", "ushort"), 65535);
TEST_EQ(TestValue<uint16_t>("{ y:0 }", "ushort"), 0);
TEST_EQ(TestValue<int32_t>("{ y:2147483647 }", "int"), 2147483647);
TEST_EQ(TestValue<int32_t>("{ y:-2147483648 }", "int") + 1, -2147483647);
TEST_EQ(TestValue<uint32_t>("{ y:4294967295 }", "uint"), 4294967295);
TEST_EQ(TestValue<uint32_t>("{ y:0 }", "uint"), 0);
TEST_EQ(TestValue<int64_t>("{ y:9223372036854775807 }", "long"),
9223372036854775807LL);
TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }", "long") + 1LL,
TEST_EQ(TestValue<int64_t>("{ y:-9223372036854775808 }", "long") + 1LL,
-9223372036854775807LL);
TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }", "ulong"),
TEST_EQ(TestValue<uint64_t>("{ y:18446744073709551615 }", "ulong"),
18446744073709551615ULL);
TEST_EQ(TestValue<uint64_t>("{ Y:0 }", "ulong"), 0);
TEST_EQ(TestValue<uint64_t>("{ Y: 18446744073709551615 }", "uint64"),
TEST_EQ(TestValue<uint64_t>("{ y:0 }", "ulong"), 0);
TEST_EQ(TestValue<uint64_t>("{ y: 18446744073709551615 }", "uint64"),
18446744073709551615ULL);
// check that the default works
TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
@@ -1923,77 +1925,77 @@ void IntegerBoundaryTest() {
void ValidFloatTest() {
// check rounding to infinity
TEST_EQ(TestValue<float>("{ Y:+3.4029e+38 }", "float"), +infinityf);
TEST_EQ(TestValue<float>("{ Y:-3.4029e+38 }", "float"), -infinityf);
TEST_EQ(TestValue<double>("{ Y:+1.7977e+308 }", "double"), +infinityd);
TEST_EQ(TestValue<double>("{ Y:-1.7977e+308 }", "double"), -infinityd);
TEST_EQ(TestValue<float>("{ y:+3.4029e+38 }", "float"), +infinityf);
TEST_EQ(TestValue<float>("{ y:-3.4029e+38 }", "float"), -infinityf);
TEST_EQ(TestValue<double>("{ y:+1.7977e+308 }", "double"), +infinityd);
TEST_EQ(TestValue<double>("{ y:-1.7977e+308 }", "double"), -infinityd);
TEST_EQ(
FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
FloatCompare(TestValue<float>("{ y:0.0314159e+2 }", "float"), 3.14159f),
true);
// float in string
TEST_EQ(FloatCompare(TestValue<float>("{ Y:\" 0.0314159e+2 \" }", "float"),
TEST_EQ(FloatCompare(TestValue<float>("{ y:\" 0.0314159e+2 \" }", "float"),
3.14159f),
true);
TEST_EQ(TestValue<float>("{ Y:1 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:1.0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:1. }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:+1. }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:-1. }", "float"), -1.0f);
TEST_EQ(TestValue<float>("{ Y:1.e0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:1.e+0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:1.e-0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ Y:0.125 }", "float"), 0.125f);
TEST_EQ(TestValue<float>("{ Y:.125 }", "float"), 0.125f);
TEST_EQ(TestValue<float>("{ Y:-.125 }", "float"), -0.125f);
TEST_EQ(TestValue<float>("{ Y:+.125 }", "float"), +0.125f);
TEST_EQ(TestValue<float>("{ Y:5 }", "float"), 5.0f);
TEST_EQ(TestValue<float>("{ Y:\"5\" }", "float"), 5.0f);
TEST_EQ(TestValue<float>("{ y:1 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:1.0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:1. }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:+1. }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:-1. }", "float"), -1.0f);
TEST_EQ(TestValue<float>("{ y:1.e0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:1.e+0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:1.e-0 }", "float"), 1.0f);
TEST_EQ(TestValue<float>("{ y:0.125 }", "float"), 0.125f);
TEST_EQ(TestValue<float>("{ y:.125 }", "float"), 0.125f);
TEST_EQ(TestValue<float>("{ y:-.125 }", "float"), -0.125f);
TEST_EQ(TestValue<float>("{ y:+.125 }", "float"), +0.125f);
TEST_EQ(TestValue<float>("{ y:5 }", "float"), 5.0f);
TEST_EQ(TestValue<float>("{ y:\"5\" }", "float"), 5.0f);
#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
// Old MSVC versions may have problem with this check.
// https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
TEST_EQ(TestValue<double>("{ Y:6.9294956446009195e15 }", "double"),
TEST_EQ(TestValue<double>("{ y:6.9294956446009195e15 }", "double"),
6929495644600920.0);
// check nan's
TEST_EQ(std::isnan(TestValue<double>("{ Y:nan }", "double")), true);
TEST_EQ(std::isnan(TestValue<float>("{ Y:nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ Y:\"nan\" }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ Y:+nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ Y:-nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<double>("{ y:nan }", "double")), true);
TEST_EQ(std::isnan(TestValue<float>("{ y:nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ y:\"nan\" }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ y:+nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>("{ y:-nan }", "float")), true);
TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
// check inf
TEST_EQ(TestValue<float>("{ Y:inf }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ Y:\"inf\" }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ Y:+inf }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ Y:-inf }", "float"), -infinityf);
TEST_EQ(TestValue<float>("{ y:inf }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ y:\"inf\" }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ y:+inf }", "float"), infinityf);
TEST_EQ(TestValue<float>("{ y:-inf }", "float"), -infinityf);
TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
TestValue<double>(
"{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
"{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
"3.0e2] }",
"[double]");
TestValue<float>(
"{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
"{ y: [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
"3.0e2] }",
"[float]");
// Test binary format of float point.
// https://en.cppreference.com/w/cpp/language/floating_literal
// 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
TEST_EQ(TestValue<double>("{ Y:0x12.34p-1 }", "double"), 9.1015625);
TEST_EQ(TestValue<double>("{ y:0x12.34p-1 }", "double"), 9.1015625);
// hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
TEST_EQ(TestValue<float>("{ Y:-0x0.2p0 }", "float"), -0.125f);
TEST_EQ(TestValue<float>("{ Y:-0x.2p1 }", "float"), -0.25f);
TEST_EQ(TestValue<float>("{ Y:0x1.2p3 }", "float"), 9.0f);
TEST_EQ(TestValue<float>("{ Y:0x10.1p0 }", "float"), 16.0625f);
TEST_EQ(TestValue<double>("{ Y:0x1.2p3 }", "double"), 9.0);
TEST_EQ(TestValue<double>("{ Y:0x10.1p0 }", "double"), 16.0625);
TEST_EQ(TestValue<double>("{ Y:0xC.68p+2 }", "double"), 49.625);
TestValue<double>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
TestValue<float>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
TEST_EQ(TestValue<float>("{ y:-0x0.2p0 }", "float"), -0.125f);
TEST_EQ(TestValue<float>("{ y:-0x.2p1 }", "float"), -0.25f);
TEST_EQ(TestValue<float>("{ y:0x1.2p3 }", "float"), 9.0f);
TEST_EQ(TestValue<float>("{ y:0x10.1p0 }", "float"), 16.0625f);
TEST_EQ(TestValue<double>("{ y:0x1.2p3 }", "double"), 9.0);
TEST_EQ(TestValue<double>("{ y:0x10.1p0 }", "double"), 16.0625);
TEST_EQ(TestValue<double>("{ y:0xC.68p+2 }", "double"), 49.625);
TestValue<double>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
TestValue<float>("{ y: [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
#else // FLATBUFFERS_HAS_NEW_STRTOD
TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");