dynamic-test.c++ (17880B)
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 #include "dynamic.h" 23 #include "message.h" 24 #include <kj/debug.h> 25 #include <kj/compat/gtest.h> 26 #include "test-util.h" 27 28 namespace capnp { 29 namespace _ { // private 30 namespace { 31 32 template <typename Element, typename T> 33 void checkList(T reader, std::initializer_list<ReaderFor<Element>> expected) { 34 auto list = reader.template as<DynamicList>(); 35 ASSERT_EQ(expected.size(), list.size()); 36 for (uint i = 0; i < expected.size(); i++) { 37 EXPECT_EQ(expected.begin()[i], list[i].template as<Element>()); 38 } 39 40 auto typed = reader.template as<List<Element>>(); 41 ASSERT_EQ(expected.size(), typed.size()); 42 for (uint i = 0; i < expected.size(); i++) { 43 EXPECT_EQ(expected.begin()[i], typed[i]); 44 } 45 } 46 47 TEST(DynamicApi, Build) { 48 MallocMessageBuilder builder; 49 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 50 51 initDynamicTestMessage(root); 52 checkTestMessage(root.asReader().as<TestAllTypes>()); 53 54 checkDynamicTestMessage(root.asReader()); 55 checkDynamicTestMessage(root); 56 } 57 58 TEST(DynamicApi, Read) { 59 MallocMessageBuilder builder; 60 auto root = builder.initRoot<TestAllTypes>(); 61 62 initTestMessage(root); 63 64 checkDynamicTestMessage(toDynamic(root.asReader())); 65 checkDynamicTestMessage(toDynamic(root).asReader()); 66 checkDynamicTestMessage(toDynamic(root)); 67 } 68 69 TEST(DynamicApi, Defaults) { 70 AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}}; 71 kj::ArrayPtr<const word> segments[1] = {kj::arrayPtr(nullRoot.words, 1)}; 72 SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); 73 auto root = reader.getRoot<DynamicStruct>(Schema::from<TestDefaults>()); 74 checkDynamicTestMessage(root); 75 } 76 77 TEST(DynamicApi, DefaultsBuilder) { 78 MallocMessageBuilder builder; 79 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestDefaults>()); 80 81 checkTestMessage(root.asReader().as<TestDefaults>()); 82 checkDynamicTestMessage(root.asReader()); 83 84 // This will initialize the whole message, replacing null pointers with copies of defaults. 85 checkDynamicTestMessage(root); 86 87 // Check again now that the message is initialized. 88 checkTestMessage(root.asReader().as<TestDefaults>()); 89 checkDynamicTestMessage(root.asReader()); 90 checkDynamicTestMessage(root); 91 } 92 93 TEST(DynamicApi, Zero) { 94 MallocMessageBuilder builder; 95 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 96 97 checkDynamicTestMessageAllZero(root.asReader()); 98 checkTestMessageAllZero(root.asReader().as<TestAllTypes>()); 99 checkDynamicTestMessageAllZero(root); 100 checkTestMessageAllZero(root.asReader().as<TestAllTypes>()); 101 } 102 103 TEST(DynamicApi, ListListsBuild) { 104 MallocMessageBuilder builder; 105 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestListDefaults>()); 106 107 initDynamicTestLists(root); 108 checkTestMessage(root.asReader().as<TestListDefaults>()); 109 110 checkDynamicTestLists(root.asReader()); 111 checkDynamicTestLists(root); 112 } 113 114 TEST(DynamicApi, ListListsRead) { 115 MallocMessageBuilder builder; 116 auto root = builder.initRoot<TestListDefaults>(); 117 118 initTestMessage(root); 119 120 checkDynamicTestLists(toDynamic(root.asReader())); 121 checkDynamicTestLists(toDynamic(root).asReader()); 122 checkDynamicTestLists(toDynamic(root)); 123 } 124 125 TEST(DynamicApi, AnyPointers) { 126 MallocMessageBuilder builder; 127 auto root = builder.getRoot<test::TestAnyPointer>(); 128 129 initDynamicTestMessage( 130 root.getAnyPointerField().initAs<DynamicStruct>(Schema::from<TestAllTypes>())); 131 checkTestMessage(root.asReader().getAnyPointerField().getAs<TestAllTypes>()); 132 133 checkDynamicTestMessage( 134 root.asReader().getAnyPointerField().getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 135 checkDynamicTestMessage( 136 root.getAnyPointerField().getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 137 138 { 139 { 140 auto list = root.getAnyPointerField().initAs<DynamicList>(Schema::from<List<uint32_t>>(), 4); 141 list.set(0, 123); 142 list.set(1, 456); 143 list.set(2, 789); 144 list.set(3, 123456789); 145 } 146 147 { 148 auto list = root.asReader().getAnyPointerField().getAs<List<uint32_t>>(); 149 ASSERT_EQ(4u, list.size()); 150 EXPECT_EQ(123u, list[0]); 151 EXPECT_EQ(456u, list[1]); 152 EXPECT_EQ(789u, list[2]); 153 EXPECT_EQ(123456789u, list[3]); 154 } 155 156 checkList<uint32_t>(root.asReader().getAnyPointerField().getAs<DynamicList>( 157 Schema::from<List<uint32_t>>()), {123u, 456u, 789u, 123456789u}); 158 checkList<uint32_t>(root.getAnyPointerField().getAs<DynamicList>( 159 Schema::from<List<uint32_t>>()), {123u, 456u, 789u, 123456789u}); 160 } 161 162 // Setting an AnyPointer to various types should work. 163 toDynamic(root).set("anyPointerField", capnp::Text::Reader("foo")); 164 EXPECT_EQ("foo", root.getAnyPointerField().getAs<Text>()); 165 166 { 167 auto orphan = builder.getOrphanage().newOrphan<TestAllTypes>(); 168 initTestMessage(orphan.get()); 169 toDynamic(root).set("anyPointerField", orphan.getReader()); 170 checkTestMessage(root.getAnyPointerField().getAs<TestAllTypes>()); 171 172 toDynamic(root).adopt("anyPointerField", kj::mv(orphan)); 173 checkTestMessage(root.getAnyPointerField().getAs<TestAllTypes>()); 174 } 175 176 { 177 auto lorphan = builder.getOrphanage().newOrphan<List<uint32_t>>(3); 178 lorphan.get().set(0, 12); 179 lorphan.get().set(1, 34); 180 lorphan.get().set(2, 56); 181 toDynamic(root).set("anyPointerField", lorphan.getReader()); 182 auto l = root.getAnyPointerField().getAs<List<uint32_t>>(); 183 ASSERT_EQ(3, l.size()); 184 EXPECT_EQ(12, l[0]); 185 EXPECT_EQ(34, l[1]); 186 EXPECT_EQ(56, l[2]); 187 } 188 189 // Just compile this one. 190 toDynamic(root).set("anyPointerField", Capability::Client(nullptr)); 191 root.getAnyPointerField().getAs<Capability>(); 192 } 193 194 TEST(DynamicApi, DynamicAnyPointers) { 195 MallocMessageBuilder builder; 196 auto root = builder.getRoot<DynamicStruct>(Schema::from<test::TestAnyPointer>()); 197 198 initDynamicTestMessage( 199 root.get("anyPointerField").as<AnyPointer>() 200 .initAs<DynamicStruct>(Schema::from<TestAllTypes>())); 201 checkTestMessage( 202 root.asReader().as<test::TestAnyPointer>().getAnyPointerField().getAs<TestAllTypes>()); 203 204 checkDynamicTestMessage( 205 root.asReader().get("anyPointerField").as<AnyPointer>() 206 .getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 207 checkDynamicTestMessage( 208 root.asReader().get("anyPointerField").as<AnyPointer>() 209 .getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 210 checkDynamicTestMessage( 211 root.get("anyPointerField").as<AnyPointer>().asReader() 212 .getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 213 checkDynamicTestMessage( 214 root.get("anyPointerField").as<AnyPointer>() 215 .getAs<DynamicStruct>(Schema::from<TestAllTypes>())); 216 217 { 218 { 219 auto list = root.init("anyPointerField").as<AnyPointer>() 220 .initAs<DynamicList>(Schema::from<List<uint32_t>>(), 4); 221 list.set(0, 123); 222 list.set(1, 456); 223 list.set(2, 789); 224 list.set(3, 123456789); 225 } 226 227 { 228 auto list = root.asReader().as<test::TestAnyPointer>() 229 .getAnyPointerField().getAs<List<uint32_t>>(); 230 ASSERT_EQ(4u, list.size()); 231 EXPECT_EQ(123u, list[0]); 232 EXPECT_EQ(456u, list[1]); 233 EXPECT_EQ(789u, list[2]); 234 EXPECT_EQ(123456789u, list[3]); 235 } 236 237 checkList<uint32_t>( 238 root.asReader().get("anyPointerField").as<AnyPointer>() 239 .getAs<DynamicList>(Schema::from<List<uint32_t>>()), 240 {123u, 456u, 789u, 123456789u}); 241 checkList<uint32_t>( 242 root.asReader().get("anyPointerField").as<AnyPointer>() 243 .getAs<DynamicList>(Schema::from<List<uint32_t>>()), 244 {123u, 456u, 789u, 123456789u}); 245 checkList<uint32_t>( 246 root.get("anyPointerField").as<AnyPointer>().asReader() 247 .getAs<DynamicList>(Schema::from<List<uint32_t>>()), 248 {123u, 456u, 789u, 123456789u}); 249 checkList<uint32_t>( 250 root.get("anyPointerField").as<AnyPointer>() 251 .getAs<DynamicList>(Schema::from<List<uint32_t>>()), 252 {123u, 456u, 789u, 123456789u}); 253 } 254 } 255 256 TEST(DynamicApi, DynamicAnyStructs) { 257 MallocMessageBuilder builder; 258 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 259 260 root.as<AnyStruct>().as<TestAllTypes>().setInt8Field(123); 261 EXPECT_EQ(root.get("int8Field").as<int8_t>(), 123); 262 EXPECT_EQ(root.asReader().as<AnyStruct>().as<TestAllTypes>().getInt8Field(), 123); 263 } 264 265 #define EXPECT_MAYBE_EQ(name, exp, expected, actual) \ 266 KJ_IF_MAYBE(name, exp) { \ 267 EXPECT_EQ(expected, actual); \ 268 } else { \ 269 KJ_FAIL_EXPECT("Maybe was empty."); \ 270 } 271 272 TEST(DynamicApi, UnionsRead) { 273 MallocMessageBuilder builder; 274 auto root = builder.initRoot<TestUnion>(); 275 276 root.getUnion0().setU0f1s32(1234567); 277 root.getUnion1().setU1f1sp("foo"); 278 root.getUnion2().setU2f0s1(true); 279 root.getUnion3().setU3f0s64(1234567890123456789ll); 280 281 { 282 auto dynamic = toDynamic(root.asReader()); 283 { 284 auto u = dynamic.get("union0").as<DynamicStruct>(); 285 EXPECT_MAYBE_EQ(w, u.which(), "u0f1s32", w->getProto().getName()); 286 EXPECT_EQ(1234567, u.get("u0f1s32").as<int32_t>()); 287 } 288 { 289 auto u = dynamic.get("union1").as<DynamicStruct>(); 290 EXPECT_MAYBE_EQ(w, u.which(), "u1f1sp", w->getProto().getName()); 291 EXPECT_EQ("foo", u.get("u1f1sp").as<Text>()); 292 } 293 { 294 auto u = dynamic.get("union2").as<DynamicStruct>(); 295 EXPECT_MAYBE_EQ(w, u.which(), "u2f0s1", w->getProto().getName()); 296 EXPECT_TRUE(u.get("u2f0s1").as<bool>()); 297 } 298 { 299 auto u = dynamic.get("union3").as<DynamicStruct>(); 300 EXPECT_MAYBE_EQ(w, u.which(), "u3f0s64", w->getProto().getName()); 301 EXPECT_EQ(1234567890123456789ll, u.get("u3f0s64").as<int64_t>()); 302 } 303 } 304 305 { 306 // Again as a builder. 307 auto dynamic = toDynamic(root); 308 { 309 auto u = dynamic.get("union0").as<DynamicStruct>(); 310 EXPECT_MAYBE_EQ(w, u.which(), "u0f1s32", w->getProto().getName()); 311 EXPECT_EQ(1234567, u.get("u0f1s32").as<int32_t>()); 312 } 313 { 314 auto u = dynamic.get("union1").as<DynamicStruct>(); 315 EXPECT_MAYBE_EQ(w, u.which(), "u1f1sp", w->getProto().getName()); 316 EXPECT_EQ("foo", u.get("u1f1sp").as<Text>()); 317 } 318 { 319 auto u = dynamic.get("union2").as<DynamicStruct>(); 320 EXPECT_MAYBE_EQ(w, u.which(), "u2f0s1", w->getProto().getName()); 321 EXPECT_TRUE(u.get("u2f0s1").as<bool>()); 322 } 323 { 324 auto u = dynamic.get("union3").as<DynamicStruct>(); 325 EXPECT_MAYBE_EQ(w, u.which(), "u3f0s64", w->getProto().getName()); 326 EXPECT_EQ(1234567890123456789ll, u.get("u3f0s64").as<int64_t>()); 327 } 328 } 329 } 330 331 TEST(DynamicApi, UnionsWrite) { 332 MallocMessageBuilder builder; 333 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestUnion>()); 334 335 root.get("union0").as<DynamicStruct>().set("u0f1s32", 1234567); 336 root.get("union1").as<DynamicStruct>().set("u1f1sp", "foo"); 337 root.get("union2").as<DynamicStruct>().set("u2f0s1", true); 338 root.get("union3").as<DynamicStruct>().set("u3f0s64", 1234567890123456789ll); 339 340 auto reader = root.asReader().as<TestUnion>(); 341 ASSERT_EQ(TestUnion::Union0::U0F1S32, reader.getUnion0().which()); 342 EXPECT_EQ(1234567, reader.getUnion0().getU0f1s32()); 343 344 ASSERT_EQ(TestUnion::Union1::U1F1SP, reader.getUnion1().which()); 345 EXPECT_EQ("foo", reader.getUnion1().getU1f1sp()); 346 347 ASSERT_EQ(TestUnion::Union2::U2F0S1, reader.getUnion2().which()); 348 EXPECT_TRUE(reader.getUnion2().getU2f0s1()); 349 350 ASSERT_EQ(TestUnion::Union3::U3F0S64, reader.getUnion3().which()); 351 EXPECT_EQ(1234567890123456789ll, reader.getUnion3().getU3f0s64()); 352 353 // Can't access union members by name from the root. 354 EXPECT_ANY_THROW(root.get("u0f1s32")); 355 EXPECT_ANY_THROW(root.set("u0f1s32", 1234567)); 356 } 357 358 TEST(DynamicApi, UnnamedUnion) { 359 MallocMessageBuilder builder; 360 StructSchema schema = Schema::from<test::TestUnnamedUnion>(); 361 auto root = builder.initRoot<DynamicStruct>(schema); 362 363 EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); 364 365 root.set("bar", 321); 366 EXPECT_EQ(schema.getFieldByName("bar"), KJ_ASSERT_NONNULL(root.which())); 367 EXPECT_EQ(321u, root.get("bar").as<uint>()); 368 EXPECT_EQ(321u, root.asReader().get("bar").as<uint>()); 369 EXPECT_ANY_THROW(root.get("foo")); 370 EXPECT_ANY_THROW(root.asReader().get("foo")); 371 372 root.set("foo", 123); 373 EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); 374 EXPECT_EQ(123u, root.get("foo").as<uint>()); 375 EXPECT_EQ(123u, root.asReader().get("foo").as<uint>()); 376 EXPECT_ANY_THROW(root.get("bar")); 377 EXPECT_ANY_THROW(root.asReader().get("bar")); 378 379 root.set("bar", 321); 380 EXPECT_EQ(schema.getFieldByName("bar"), KJ_ASSERT_NONNULL(root.which())); 381 EXPECT_EQ(321u, root.get("bar").as<uint>()); 382 EXPECT_EQ(321u, root.asReader().get("bar").as<uint>()); 383 EXPECT_ANY_THROW(root.get("foo")); 384 EXPECT_ANY_THROW(root.asReader().get("foo")); 385 386 root.set("foo", 123); 387 EXPECT_EQ(schema.getFieldByName("foo"), KJ_ASSERT_NONNULL(root.which())); 388 EXPECT_EQ(123u, root.get("foo").as<uint>()); 389 EXPECT_EQ(123u, root.asReader().get("foo").as<uint>()); 390 EXPECT_ANY_THROW(root.get("bar")); 391 EXPECT_ANY_THROW(root.asReader().get("bar")); 392 } 393 394 TEST(DynamicApi, ConversionFailures) { 395 MallocMessageBuilder builder; 396 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 397 398 root.set("int8Field", 123); 399 EXPECT_NONFATAL_FAILURE(root.set("int8Field", 1234)); 400 401 root.set("uInt32Field", 1); 402 EXPECT_NONFATAL_FAILURE(root.set("uInt32Field", -1)); 403 404 root.set("int16Field", 5); 405 EXPECT_NONFATAL_FAILURE(root.set("int16Field", 0.5)); 406 407 root.set("boolField", true); 408 EXPECT_NONFATAL_FAILURE(root.set("boolField", 1)); 409 } 410 411 TEST(DynamicApi, LateUnion) { 412 MallocMessageBuilder builder; 413 auto root = builder.initRoot<DynamicStruct>(Schema::from<test::TestLateUnion>()); 414 415 root.get("theUnion").as<DynamicStruct>().set("qux", "hello"); 416 EXPECT_EQ("hello", root.as<test::TestLateUnion>().getTheUnion().getQux()); 417 } 418 419 TEST(DynamicApi, Has) { 420 MallocMessageBuilder builder; 421 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestDefaults>()); 422 423 // Primitive fields are always present even if set to default. 424 EXPECT_TRUE(root.has("int32Field")); 425 EXPECT_FALSE(root.has("int32Field", HasMode::NON_DEFAULT)); 426 root.set("int32Field", 123); 427 EXPECT_TRUE(root.has("int32Field")); 428 EXPECT_TRUE(root.has("int32Field", HasMode::NON_DEFAULT)); 429 root.set("int32Field", -12345678); 430 EXPECT_TRUE(root.has("int32Field")); 431 EXPECT_FALSE(root.has("int32Field", HasMode::NON_DEFAULT)); 432 433 // Pointers are absent until initialized. 434 EXPECT_FALSE(root.has("structField")); 435 EXPECT_FALSE(root.has("structField", HasMode::NON_DEFAULT)); 436 root.init("structField"); 437 EXPECT_TRUE(root.has("structField")); 438 EXPECT_TRUE(root.has("structField", HasMode::NON_DEFAULT)); 439 } 440 441 TEST(DynamicApi, HasWhenEmpty) { 442 AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}}; 443 kj::ArrayPtr<const word> segments[1] = {kj::arrayPtr(nullRoot.words, 1)}; 444 SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1)); 445 auto root = reader.getRoot<DynamicStruct>(Schema::from<TestDefaults>()); 446 447 EXPECT_TRUE(root.has("voidField")); 448 EXPECT_TRUE(root.has("int32Field")); 449 EXPECT_FALSE(root.has("structField")); 450 EXPECT_FALSE(root.has("int32List")); 451 452 EXPECT_FALSE(root.has("voidField", HasMode::NON_DEFAULT)); 453 EXPECT_FALSE(root.has("int32Field", HasMode::NON_DEFAULT)); 454 EXPECT_FALSE(root.has("structField", HasMode::NON_DEFAULT)); 455 EXPECT_FALSE(root.has("int32List", HasMode::NON_DEFAULT)); 456 } 457 458 TEST(DynamicApi, SetEnumFromNative) { 459 MallocMessageBuilder builder; 460 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 461 462 root.set("enumField", TestEnum::BAZ); 463 root.set("enumList", {TestEnum::BAR, TestEnum::FOO}); 464 EXPECT_EQ(TestEnum::BAZ, root.get("enumField").as<TestEnum>()); 465 checkList<TestEnum>(root.get("enumList"), {TestEnum::BAR, TestEnum::FOO}); 466 } 467 468 TEST(DynamicApi, SetDataFromText) { 469 MallocMessageBuilder builder; 470 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 471 472 root.set("dataField", "foo"); 473 EXPECT_EQ(data("foo"), root.get("dataField").as<Data>()); 474 } 475 476 TEST(DynamicApi, BuilderAssign) { 477 MallocMessageBuilder builder; 478 auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>()); 479 480 // Declare upfront, assign later. 481 // Note that the Python implementation requires defaulted constructors. Do not delete them! 482 DynamicValue::Builder value; 483 DynamicStruct::Builder structValue; 484 DynamicList::Builder listValue; 485 486 value = root.get("structField"); 487 structValue = value.as<DynamicStruct>(); 488 structValue.set("int32Field", 123); 489 490 value = root.init("int32List", 1); 491 listValue = value.as<DynamicList>(); 492 listValue.set(0, 123); 493 } 494 495 } // namespace 496 } // namespace _ (private) 497 } // namespace capnp