blob: da0fd743cf9138cbcee1b2dcd51e3afedaf145c8 [file] [log] [blame]
Austin Schuh2dd86a92022-09-14 21:19:23 -07001#include "evolution_test.h"
2
3#include "evolution_test/evolution_v1_generated.h"
4#include "evolution_test/evolution_v2_generated.h"
5#include "flatbuffers/idl.h"
6#include "test_assert.h"
7
8namespace flatbuffers {
9namespace tests {
10
11void EvolutionTest(const std::string &tests_data_path) {
12 // VS10 does not support typed enums, exclude from tests
13#if !defined(_MSC_VER) || _MSC_VER >= 1700
14 const int NUM_VERSIONS = 2;
15 std::string schemas[NUM_VERSIONS];
16 std::string jsonfiles[NUM_VERSIONS];
17 std::vector<uint8_t> binaries[NUM_VERSIONS];
18
19 flatbuffers::IDLOptions idl_opts;
20 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
21 flatbuffers::Parser parser(idl_opts);
22
23 // Load all the schema versions and their associated data.
24 for (int i = 0; i < NUM_VERSIONS; ++i) {
25 std::string schema = tests_data_path + "evolution_test/evolution_v" +
26 flatbuffers::NumToString(i + 1) + ".fbs";
27 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
28 std::string json = tests_data_path + "evolution_test/evolution_v" +
29 flatbuffers::NumToString(i + 1) + ".json";
30 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
31
32 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
33 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
34
35 auto bufLen = parser.builder_.GetSize();
36 auto buf = parser.builder_.GetBufferPointer();
37 binaries[i].reserve(bufLen);
38 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
39 }
40
41 // Assert that all the verifiers for the different schema versions properly
42 // verify any version data.
43 for (int i = 0; i < NUM_VERSIONS; ++i) {
44 flatbuffers::Verifier verifier(&binaries[i].front(), binaries[i].size());
45 TEST_ASSERT(Evolution::V1::VerifyRootBuffer(verifier));
46 TEST_ASSERT(Evolution::V2::VerifyRootBuffer(verifier));
47 }
48
49 // Test backwards compatibility by reading old data with an evolved schema.
50 auto root_v1_viewed_from_v2 = Evolution::V2::GetRoot(&binaries[0].front());
51 // field 'k' is new in version 2, so it should be null.
52 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->k());
53 // field 'l' is new in version 2 with a default of 56.
54 TEST_EQ(root_v1_viewed_from_v2->l(), 56);
55 // field 'c' of 'TableA' is new in version 2, so it should be null.
56 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->e()->c());
57 // 'TableC' was added to field 'c' union in version 2, so it should be null.
58 TEST_ASSERT(nullptr == root_v1_viewed_from_v2->c_as_TableC());
59 // The field 'c' union should be of type 'TableB' regardless of schema version
60 TEST_ASSERT(root_v1_viewed_from_v2->c_type() == Evolution::V2::Union::TableB);
61 // The field 'f' was renamed to 'ff' in version 2, it should still be
62 // readable.
63 TEST_EQ(root_v1_viewed_from_v2->ff()->a(), 16);
64
65 // Test forwards compatibility by reading new data with an old schema.
66 auto root_v2_viewed_from_v1 = Evolution::V1::GetRoot(&binaries[1].front());
67 // The field 'c' union in version 2 is a new table (index = 3) and should
68 // still be accessible, but not interpretable.
69 TEST_EQ(static_cast<uint8_t>(root_v2_viewed_from_v1->c_type()), 3);
70 TEST_NOTNULL(root_v2_viewed_from_v1->c());
71 // The field 'd' enum in verison 2 has new members and should still be
72 // accessible, but not interpretable.
73 TEST_EQ(static_cast<int8_t>(root_v2_viewed_from_v1->d()), 3);
74 // The field 'a' in version 2 is deprecated and should return the default
75 // value (0) instead of the value stored in the in the buffer (42).
76 TEST_EQ(root_v2_viewed_from_v1->a(), 0);
77 // The field 'ff' was originally named 'f' in version 1, it should still be
78 // readable.
79 TEST_EQ(root_v2_viewed_from_v1->f()->a(), 35);
80#endif
81}
82
83void ConformTest() {
84 flatbuffers::Parser parser;
85 TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
86
87 auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
88 const char *expected_err) {
89 flatbuffers::Parser parser2;
90 TEST_EQ(parser2.Parse(test), true);
91 auto err = parser2.ConformTo(parser1);
92 TEST_NOTNULL(strstr(err.c_str(), expected_err));
93 };
94
95 test_conform(parser, "table T { A:byte; }", "types differ for field");
96 test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
97 test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
98 test_conform(parser, "table T { B:float; }",
99 "field renamed to different type");
100 test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
101}
102
103void UnionDeprecationTest(const std::string& tests_data_path) {
104 const int NUM_VERSIONS = 2;
105 std::string schemas[NUM_VERSIONS];
106 std::string jsonfiles[NUM_VERSIONS];
107 std::vector<uint8_t> binaries[NUM_VERSIONS];
108
109 flatbuffers::IDLOptions idl_opts;
110 idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
111 flatbuffers::Parser parser(idl_opts);
112
113 // Load all the schema versions and their associated data.
114 for (int i = 0; i < NUM_VERSIONS; ++i) {
115 std::string schema = tests_data_path + "evolution_test/evolution_v" +
116 flatbuffers::NumToString(i + 1) + ".fbs";
117 TEST_ASSERT(flatbuffers::LoadFile(schema.c_str(), false, &schemas[i]));
118 std::string json = tests_data_path + "evolution_test/evolution_v" +
119 flatbuffers::NumToString(i + 1) + ".json";
120 TEST_ASSERT(flatbuffers::LoadFile(json.c_str(), false, &jsonfiles[i]));
121
122 TEST_ASSERT(parser.Parse(schemas[i].c_str()));
123 TEST_ASSERT(parser.Parse(jsonfiles[i].c_str()));
124
125 auto bufLen = parser.builder_.GetSize();
126 auto buf = parser.builder_.GetBufferPointer();
127 binaries[i].reserve(bufLen);
128 std::copy(buf, buf + bufLen, std::back_inserter(binaries[i]));
129 }
130
131 auto v2 = parser.LookupStruct("Evolution.V2.Root");
132 TEST_NOTNULL(v2);
133 auto j_type_field = v2->fields.Lookup("j_type");
134 TEST_NOTNULL(j_type_field);
135 TEST_ASSERT(j_type_field->deprecated);
136}
137
138} // namespace tests
139} // namespace flatbuffers