schema-test.c++ (16833B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #define CAPNP_TESTING_CAPNP 1 23 24 #include "schema.h" 25 #include <kj/compat/gtest.h> 26 #include "test-util.h" 27 28 // TODO(cleanup): Auto-generate stringification functions for union discriminants. 29 namespace capnp { 30 namespace schema { 31 inline kj::String KJ_STRINGIFY(Type::Which which) { 32 return kj::str(static_cast<uint16_t>(which)); 33 } 34 } // namespace schema 35 } // namespace capnp 36 37 namespace capnp { 38 namespace _ { // private 39 namespace { 40 41 TEST(Schema, Structs) { 42 StructSchema schema = Schema::from<TestAllTypes>(); 43 44 EXPECT_EQ(typeId<TestAllTypes>(), schema.getProto().getId()); 45 46 EXPECT_TRUE(schema.getDependency(typeId<TestEnum>()) == Schema::from<TestEnum>()); 47 EXPECT_TRUE(schema.getDependency(typeId<TestEnum>()) != schema); 48 EXPECT_TRUE(schema.getDependency(typeId<TestAllTypes>()) == Schema::from<TestAllTypes>()); 49 EXPECT_TRUE(schema.getDependency(typeId<TestAllTypes>()) == schema); 50 EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId<TestDefaults>())); 51 52 EXPECT_TRUE(schema.asStruct() == schema); 53 EXPECT_NONFATAL_FAILURE(schema.asEnum()); 54 EXPECT_NONFATAL_FAILURE(schema.asInterface()); 55 ASSERT_EQ("TestAllTypes", schema.getUnqualifiedName()); 56 57 ASSERT_EQ(schema.getFields().size(), schema.getProto().getStruct().getFields().size()); 58 StructSchema::Field field = schema.getFields()[0]; 59 EXPECT_EQ("voidField", field.getProto().getName()); 60 EXPECT_TRUE(field.getContainingStruct() == schema); 61 62 StructSchema::Field lookup = schema.getFieldByName("voidField"); 63 EXPECT_TRUE(lookup == field); 64 EXPECT_TRUE(lookup != schema.getFields()[1]); 65 EXPECT_FALSE(lookup.getProto().getSlot().getHadExplicitDefault()); 66 67 EXPECT_FALSE(schema.getFieldByName("int32Field").getProto().getSlot().getHadExplicitDefault()); 68 69 EXPECT_TRUE(Schema::from<TestDefaults>().getFieldByName("int32Field") 70 .getProto().getSlot().getHadExplicitDefault()); 71 72 EXPECT_TRUE(schema.findFieldByName("noSuchField") == nullptr); 73 74 EXPECT_TRUE(schema.findFieldByName("int32Field") != nullptr); 75 EXPECT_TRUE(schema.findFieldByName("float32List") != nullptr); 76 EXPECT_TRUE(schema.findFieldByName("dataList") != nullptr); 77 EXPECT_TRUE(schema.findFieldByName("textField") != nullptr); 78 EXPECT_TRUE(schema.findFieldByName("structField") != nullptr); 79 } 80 81 TEST(Schema, FieldLookupOutOfOrder) { 82 // Tests that name lookup works correctly when the fields are defined out-of-order in the schema 83 // file. 84 auto schema = Schema::from<test::TestOutOfOrder>().asStruct(); 85 86 EXPECT_EQ("qux", schema.getFields()[0].getProto().getName()); 87 EXPECT_EQ("grault", schema.getFields()[1].getProto().getName()); 88 EXPECT_EQ("bar", schema.getFields()[2].getProto().getName()); 89 EXPECT_EQ("foo", schema.getFields()[3].getProto().getName()); 90 EXPECT_EQ("corge", schema.getFields()[4].getProto().getName()); 91 EXPECT_EQ("waldo", schema.getFields()[5].getProto().getName()); 92 EXPECT_EQ("quux", schema.getFields()[6].getProto().getName()); 93 EXPECT_EQ("garply", schema.getFields()[7].getProto().getName()); 94 EXPECT_EQ("baz", schema.getFields()[8].getProto().getName()); 95 96 EXPECT_EQ(3, schema.getFieldByName("foo").getProto().getOrdinal().getExplicit()); 97 EXPECT_EQ(2, schema.getFieldByName("bar").getProto().getOrdinal().getExplicit()); 98 EXPECT_EQ(8, schema.getFieldByName("baz").getProto().getOrdinal().getExplicit()); 99 EXPECT_EQ(0, schema.getFieldByName("qux").getProto().getOrdinal().getExplicit()); 100 EXPECT_EQ(6, schema.getFieldByName("quux").getProto().getOrdinal().getExplicit()); 101 EXPECT_EQ(4, schema.getFieldByName("corge").getProto().getOrdinal().getExplicit()); 102 EXPECT_EQ(1, schema.getFieldByName("grault").getProto().getOrdinal().getExplicit()); 103 EXPECT_EQ(7, schema.getFieldByName("garply").getProto().getOrdinal().getExplicit()); 104 EXPECT_EQ(5, schema.getFieldByName("waldo").getProto().getOrdinal().getExplicit()); 105 } 106 107 TEST(Schema, Unions) { 108 auto schema = Schema::from<TestUnion>().asStruct(); 109 110 EXPECT_TRUE(schema.findFieldByName("bit0") != nullptr); 111 EXPECT_TRUE(schema.findFieldByName("u1f0s8") == nullptr); 112 113 auto union1 = schema.getFieldByName("union1"); 114 auto union1g = schema.getDependency(union1.getProto().getGroup().getTypeId()).asStruct(); 115 EXPECT_EQ(schema, union1g.getDependency(union1g.getProto().getScopeId())); 116 EXPECT_TRUE(union1g.findFieldByName("bin0") == nullptr); 117 118 auto u1f0s8 = union1g.getFieldByName("u1f0s8"); 119 EXPECT_EQ("u1f0s8", u1f0s8.getProto().getName()); 120 EXPECT_TRUE(u1f0s8.getContainingStruct() == union1g); 121 122 EXPECT_TRUE(union1g.findFieldByName("u1f1s8") != nullptr); 123 EXPECT_TRUE(union1g.findFieldByName("u1f0s32") != nullptr); 124 EXPECT_TRUE(union1g.findFieldByName("u1f0sp") != nullptr); 125 EXPECT_TRUE(union1g.findFieldByName("u1f1s1") != nullptr); 126 127 EXPECT_TRUE(union1g.findFieldByName("u0f0s1") == nullptr); 128 EXPECT_TRUE(union1g.findFieldByName("u2f0s8") == nullptr); 129 EXPECT_TRUE(union1g.findFieldByName("noSuchField") == nullptr); 130 } 131 132 TEST(Schema, Enums) { 133 EnumSchema schema = Schema::from<TestEnum>(); 134 135 EXPECT_EQ(typeId<TestEnum>(), schema.getProto().getId()); 136 137 EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId<TestAllTypes>())); 138 EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId<TestEnum>())); 139 140 EXPECT_NONFATAL_FAILURE(schema.asStruct()); 141 EXPECT_NONFATAL_FAILURE(schema.asInterface()); 142 EXPECT_TRUE(schema.asEnum() == schema); 143 144 ASSERT_EQ(schema.getEnumerants().size(), 145 schema.getProto().getEnum().getEnumerants().size()); 146 EnumSchema::Enumerant enumerant = schema.getEnumerants()[0]; 147 EXPECT_EQ("foo", enumerant.getProto().getName()); 148 EXPECT_TRUE(enumerant.getContainingEnum() == schema); 149 150 EnumSchema::Enumerant lookup = schema.getEnumerantByName("foo"); 151 EXPECT_TRUE(lookup == enumerant); 152 EXPECT_TRUE(lookup != schema.getEnumerants()[1]); 153 154 EXPECT_TRUE(schema.findEnumerantByName("noSuchEnumerant") == nullptr); 155 156 EXPECT_TRUE(schema.findEnumerantByName("bar") != nullptr); 157 EXPECT_TRUE(schema.findEnumerantByName("qux") != nullptr); 158 EXPECT_TRUE(schema.findEnumerantByName("corge") != nullptr); 159 EXPECT_TRUE(schema.findEnumerantByName("grault") != nullptr); 160 } 161 162 // TODO(someday): Test interface schemas when interfaces are implemented. 163 164 TEST(Schema, Lists) { 165 EXPECT_EQ(schema::Type::VOID, Schema::from<List<Void>>().whichElementType()); 166 EXPECT_EQ(schema::Type::BOOL, Schema::from<List<bool>>().whichElementType()); 167 EXPECT_EQ(schema::Type::INT8, Schema::from<List<int8_t>>().whichElementType()); 168 EXPECT_EQ(schema::Type::INT16, Schema::from<List<int16_t>>().whichElementType()); 169 EXPECT_EQ(schema::Type::INT32, Schema::from<List<int32_t>>().whichElementType()); 170 EXPECT_EQ(schema::Type::INT64, Schema::from<List<int64_t>>().whichElementType()); 171 EXPECT_EQ(schema::Type::UINT8, Schema::from<List<uint8_t>>().whichElementType()); 172 EXPECT_EQ(schema::Type::UINT16, Schema::from<List<uint16_t>>().whichElementType()); 173 EXPECT_EQ(schema::Type::UINT32, Schema::from<List<uint32_t>>().whichElementType()); 174 EXPECT_EQ(schema::Type::UINT64, Schema::from<List<uint64_t>>().whichElementType()); 175 EXPECT_EQ(schema::Type::FLOAT32, Schema::from<List<float>>().whichElementType()); 176 EXPECT_EQ(schema::Type::FLOAT64, Schema::from<List<double>>().whichElementType()); 177 EXPECT_EQ(schema::Type::TEXT, Schema::from<List<Text>>().whichElementType()); 178 EXPECT_EQ(schema::Type::DATA, Schema::from<List<Data>>().whichElementType()); 179 180 EXPECT_NONFATAL_FAILURE(Schema::from<List<uint16_t>>().getStructElementType()); 181 EXPECT_NONFATAL_FAILURE(Schema::from<List<uint16_t>>().getEnumElementType()); 182 EXPECT_NONFATAL_FAILURE(Schema::from<List<uint16_t>>().getInterfaceElementType()); 183 EXPECT_NONFATAL_FAILURE(Schema::from<List<uint16_t>>().getListElementType()); 184 185 { 186 ListSchema schema = Schema::from<List<TestAllTypes>>(); 187 EXPECT_EQ(schema::Type::STRUCT, schema.whichElementType()); 188 EXPECT_TRUE(schema.getStructElementType() == Schema::from<TestAllTypes>()); 189 EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); 190 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 191 EXPECT_NONFATAL_FAILURE(schema.getListElementType()); 192 } 193 194 { 195 ListSchema schema = Schema::from<List<TestEnum>>(); 196 EXPECT_EQ(schema::Type::ENUM, schema.whichElementType()); 197 EXPECT_TRUE(schema.getEnumElementType() == Schema::from<TestEnum>()); 198 EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); 199 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 200 EXPECT_NONFATAL_FAILURE(schema.getListElementType()); 201 } 202 203 // TODO(someday): Test interfaces. 204 205 { 206 ListSchema schema = Schema::from<List<List<int32_t>>>(); 207 EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); 208 EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); 209 EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); 210 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 211 212 ListSchema inner = schema.getListElementType(); 213 EXPECT_EQ(schema::Type::INT32, inner.whichElementType()); 214 } 215 216 { 217 ListSchema schema = Schema::from<List<List<TestAllTypes>>>(); 218 EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); 219 EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); 220 EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); 221 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 222 223 ListSchema inner = schema.getListElementType(); 224 EXPECT_EQ(schema::Type::STRUCT, inner.whichElementType()); 225 EXPECT_TRUE(inner.getStructElementType() == Schema::from<TestAllTypes>()); 226 } 227 228 { 229 ListSchema schema = Schema::from<List<List<TestEnum>>>(); 230 EXPECT_EQ(schema::Type::LIST, schema.whichElementType()); 231 EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); 232 EXPECT_NONFATAL_FAILURE(schema.getEnumElementType()); 233 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 234 235 ListSchema inner = schema.getListElementType(); 236 EXPECT_EQ(schema::Type::ENUM, inner.whichElementType()); 237 EXPECT_TRUE(inner.getEnumElementType() == Schema::from<TestEnum>()); 238 } 239 240 { 241 auto context = Schema::from<TestAllTypes>(); 242 auto type = context.getFieldByName("enumList").getProto().getSlot().getType(); 243 244 ListSchema schema = ListSchema::of(type.getList().getElementType(), context); 245 EXPECT_EQ(schema::Type::ENUM, schema.whichElementType()); 246 EXPECT_TRUE(schema.getEnumElementType() == Schema::from<TestEnum>()); 247 EXPECT_NONFATAL_FAILURE(schema.getStructElementType()); 248 EXPECT_NONFATAL_FAILURE(schema.getInterfaceElementType()); 249 EXPECT_NONFATAL_FAILURE(schema.getListElementType()); 250 } 251 } 252 253 TEST(Schema, UnnamedUnion) { 254 StructSchema schema = Schema::from<test::TestUnnamedUnion>(); 255 256 EXPECT_TRUE(schema.findFieldByName("") == nullptr); 257 258 EXPECT_TRUE(schema.findFieldByName("foo") != nullptr); 259 EXPECT_TRUE(schema.findFieldByName("bar") != nullptr); 260 EXPECT_TRUE(schema.findFieldByName("before") != nullptr); 261 EXPECT_TRUE(schema.findFieldByName("after") != nullptr); 262 } 263 264 TEST(Schema, NullSchemas) { 265 EXPECT_EQ(0xff, (uint)Schema().getProto().which()); 266 EXPECT_TRUE(StructSchema().getProto().isStruct()); 267 EXPECT_TRUE(EnumSchema().getProto().isEnum()); 268 EXPECT_TRUE(InterfaceSchema().getProto().isInterface()); 269 EXPECT_TRUE(ConstSchema().getProto().isConst()); 270 271 EXPECT_EQ("(null schema)", Schema().getProto().getDisplayName()); 272 EXPECT_EQ("(null struct schema)", StructSchema().getProto().getDisplayName()); 273 EXPECT_EQ("(null enum schema)", EnumSchema().getProto().getDisplayName()); 274 EXPECT_EQ("(null interface schema)", InterfaceSchema().getProto().getDisplayName()); 275 EXPECT_EQ("(null const schema)", ConstSchema().getProto().getDisplayName()); 276 277 EXPECT_TRUE(Schema::from<Capability>() == InterfaceSchema()); 278 EXPECT_EQ(InterfaceSchema().getProto().getId(), typeId<Capability>()); 279 } 280 281 TEST(Schema, Interfaces) { 282 InterfaceSchema schema = Schema::from<test::TestMoreStuff>(); 283 284 EXPECT_EQ(typeId<test::TestMoreStuff>(), schema.getProto().getId()); 285 286 EXPECT_TRUE(schema.getDependency(typeId<test::TestCallOrder>()) == 287 Schema::from<test::TestCallOrder>()); 288 EXPECT_TRUE(schema.getDependency(typeId<test::TestCallOrder>()) != schema); 289 EXPECT_NONFATAL_FAILURE(schema.getDependency(typeId<TestDefaults>())); 290 291 EXPECT_TRUE(schema.asInterface() == schema); 292 EXPECT_NONFATAL_FAILURE(schema.asStruct()); 293 EXPECT_NONFATAL_FAILURE(schema.asEnum()); 294 295 ASSERT_EQ(schema.getMethods().size(), schema.getProto().getInterface().getMethods().size()); 296 InterfaceSchema::Method method = schema.getMethods()[0]; 297 EXPECT_EQ("callFoo", method.getProto().getName()); 298 EXPECT_TRUE(method.getContainingInterface() == schema); 299 300 InterfaceSchema::Method lookup = schema.getMethodByName("callFoo"); 301 EXPECT_TRUE(lookup == method); 302 EXPECT_TRUE(lookup != schema.getMethods()[1]); 303 304 EXPECT_TRUE(Schema::from<TestDefaults>().getFieldByName("int32Field") 305 .getProto().getSlot().getHadExplicitDefault()); 306 307 EXPECT_TRUE(schema.findMethodByName("noSuchMethod") == nullptr); 308 309 EXPECT_TRUE(schema.findMethodByName("callFooWhenResolved") != nullptr); 310 EXPECT_TRUE(schema.findMethodByName("neverReturn") != nullptr); 311 EXPECT_TRUE(schema.findMethodByName("hold") != nullptr); 312 EXPECT_TRUE(schema.findMethodByName("callHeld") != nullptr); 313 EXPECT_TRUE(schema.findMethodByName("getHeld") != nullptr); 314 315 auto params = schema.getDependency(schema.getMethodByName("methodWithDefaults") 316 .getProto().getParamStructType()).asStruct(); 317 EXPECT_FALSE(params.getFieldByName("a").getProto().getSlot().getHadExplicitDefault()); 318 EXPECT_TRUE(params.getFieldByName("b").getProto().getSlot().getHadExplicitDefault()); 319 EXPECT_TRUE(params.getFieldByName("c").getProto().getSlot().getHadExplicitDefault()); 320 } 321 322 TEST(Schema, Generics) { 323 StructSchema allTypes = Schema::from<TestAllTypes>(); 324 StructSchema tap = Schema::from<test::TestAnyPointer>(); 325 StructSchema schema = Schema::from<test::TestUseGenerics>(); 326 327 StructSchema branded; 328 329 { 330 StructSchema::Field basic = schema.getFieldByName("basic"); 331 branded = basic.getType().asStruct(); 332 333 StructSchema::Field foo = branded.getFieldByName("foo"); 334 EXPECT_TRUE(foo.getType().asStruct() == allTypes); 335 EXPECT_TRUE(foo.getType().asStruct() != tap); 336 337 StructSchema instance2 = branded.getFieldByName("rev").getType().asStruct(); 338 StructSchema::Field foo2 = instance2.getFieldByName("foo"); 339 EXPECT_TRUE(foo2.getType().asStruct() == tap); 340 EXPECT_TRUE(foo2.getType().asStruct() != allTypes); 341 } 342 343 { 344 StructSchema inner2 = schema.getFieldByName("inner2").getType().asStruct(); 345 346 StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); 347 Type boundFoo = bound.getFieldByName("foo").getType(); 348 EXPECT_FALSE(boundFoo.isAnyPointer()); 349 EXPECT_TRUE(boundFoo.asStruct() == allTypes); 350 351 StructSchema unbound = inner2.getFieldByName("innerUnbound").getType().asStruct(); 352 Type unboundFoo = unbound.getFieldByName("foo").getType(); 353 EXPECT_TRUE(unboundFoo.isAnyPointer()); 354 } 355 356 { 357 InterfaceSchema cap = schema.getFieldByName("genericCap").getType().asInterface(); 358 InterfaceSchema::Method method = cap.getMethodByName("call"); 359 360 StructSchema inner2 = method.getParamType(); 361 StructSchema bound = inner2.getFieldByName("innerBound").getType().asStruct(); 362 Type boundFoo = bound.getFieldByName("foo").getType(); 363 EXPECT_FALSE(boundFoo.isAnyPointer()); 364 EXPECT_TRUE(boundFoo.asStruct() == allTypes); 365 EXPECT_TRUE(inner2.getFieldByName("baz").getType().isText()); 366 367 StructSchema results = method.getResultType(); 368 EXPECT_TRUE(results.getFieldByName("qux").getType().isData()); 369 370 EXPECT_TRUE(results.getFieldByName("gen").getType().asStruct() == branded); 371 } 372 } 373 374 } // namespace 375 } // namespace _ (private) 376 } // namespace capnp