// Copyright (c) 2013, Kenton Varda <temporal@gmail.com> // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "message.h" #include <kj/debug.h> #include <gtest/gtest.h> #include "test-util.h" namespace capnp { namespace _ { // private namespace { TEST(Orphans, Structs) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); initTestMessage(root.initStructField()); EXPECT_TRUE(root.hasStructField()); Orphan<TestAllTypes> orphan = root.disownStructField(); EXPECT_FALSE(orphan == nullptr); checkTestMessage(orphan.getReader()); checkTestMessage(orphan.get()); EXPECT_FALSE(root.hasStructField()); root.adoptStructField(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasStructField()); checkTestMessage(root.asReader().getStructField()); } TEST(Orphans, Lists) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); root.setUInt32List({12, 34, 56}); EXPECT_TRUE(root.hasUInt32List()); Orphan<List<uint32_t>> orphan = root.disownUInt32List(); EXPECT_FALSE(orphan == nullptr); checkList(orphan.getReader(), {12u, 34u, 56u}); checkList(orphan.get(), {12u, 34u, 56u}); EXPECT_FALSE(root.hasUInt32List()); root.adoptUInt32List(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasUInt32List()); checkList(root.asReader().getUInt32List(), {12u, 34u, 56u}); } TEST(Orphans, StructLists) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); auto list = root.initStructList(2); list[0].setTextField("foo"); list[1].setTextField("bar"); EXPECT_TRUE(root.hasStructList()); Orphan<List<TestAllTypes>> orphan = root.disownStructList(); EXPECT_FALSE(orphan == nullptr); ASSERT_EQ(2u, orphan.getReader().size()); EXPECT_EQ("foo", orphan.getReader()[0].getTextField()); EXPECT_EQ("bar", orphan.getReader()[1].getTextField()); ASSERT_EQ(2u, orphan.get().size()); EXPECT_EQ("foo", orphan.get()[0].getTextField()); EXPECT_EQ("bar", orphan.get()[1].getTextField()); EXPECT_FALSE(root.hasStructList()); root.adoptStructList(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasStructList()); ASSERT_EQ(2u, root.asReader().getStructList().size()); EXPECT_EQ("foo", root.asReader().getStructList()[0].getTextField()); EXPECT_EQ("bar", root.asReader().getStructList()[1].getTextField()); } TEST(Orphans, Text) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); root.setTextField("foo"); EXPECT_TRUE(root.hasTextField()); Orphan<Text> orphan = root.disownTextField(); EXPECT_FALSE(orphan == nullptr); EXPECT_EQ("foo", orphan.getReader()); EXPECT_EQ("foo", orphan.get()); EXPECT_FALSE(root.hasTextField()); root.adoptTextField(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasTextField()); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, Data) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); root.setDataField(data("foo")); EXPECT_TRUE(root.hasDataField()); Orphan<Data> orphan = root.disownDataField(); EXPECT_FALSE(orphan == nullptr); EXPECT_EQ(data("foo"), orphan.getReader()); EXPECT_EQ(data("foo"), orphan.get()); EXPECT_FALSE(root.hasDataField()); root.adoptDataField(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasDataField()); EXPECT_EQ(data("foo"), root.getDataField()); } #if KJ_NO_EXCEPTIONS #undef EXPECT_ANY_THROW #define EXPECT_ANY_THROW(code) EXPECT_DEATH(code, ".") #define EXPECT_NONFATAL_FAILURE(code) code #else #define EXPECT_NONFATAL_FAILURE EXPECT_ANY_THROW #endif TEST(Orphans, NoCrossMessageTransfers) { MallocMessageBuilder builder1; MallocMessageBuilder builder2; auto root1 = builder1.initRoot<TestAllTypes>(); auto root2 = builder2.initRoot<TestAllTypes>(); initTestMessage(root1.initStructField()); EXPECT_ANY_THROW(root2.adoptStructField(root1.disownStructField())); } TEST(Orphans, OrphanageStruct) { MallocMessageBuilder builder; Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>(); initTestMessage(orphan.get()); checkTestMessage(orphan.getReader()); auto root = builder.initRoot<TestAllTypes>(); root.adoptStructField(kj::mv(orphan)); } TEST(Orphans, OrphanageList) { MallocMessageBuilder builder; Orphan<List<uint32_t>> orphan = builder.getOrphanage().newOrphan<List<uint32_t>>(2); orphan.get().set(0, 123); orphan.get().set(1, 456); List<uint32_t>::Reader reader = orphan.getReader(); ASSERT_EQ(2u, reader.size()); EXPECT_EQ(123u, reader[0]); EXPECT_EQ(456u, reader[1]); auto root = builder.initRoot<TestAllTypes>(); root.adoptUInt32List(kj::mv(orphan)); } TEST(Orphans, OrphanageText) { MallocMessageBuilder builder; Orphan<Text> orphan = builder.getOrphanage().newOrphan<Text>(8); ASSERT_EQ(8u, orphan.get().size()); memcpy(orphan.get().begin(), "12345678", 8); auto root = builder.initRoot<TestAllTypes>(); root.adoptTextField(kj::mv(orphan)); EXPECT_EQ("12345678", root.getTextField()); } TEST(Orphans, OrphanageData) { MallocMessageBuilder builder; Orphan<Data> orphan = builder.getOrphanage().newOrphan<Data>(2); ASSERT_EQ(2u, orphan.get().size()); orphan.get()[0] = 123; orphan.get()[1] = 45; auto root = builder.initRoot<TestAllTypes>(); root.adoptDataField(kj::mv(orphan)); ASSERT_EQ(2u, root.getDataField().size()); EXPECT_EQ(123u, root.getDataField()[0]); EXPECT_EQ(45u, root.getDataField()[1]); } TEST(Orphans, OrphanageStructCopy) { MallocMessageBuilder builder1; MallocMessageBuilder builder2; auto root1 = builder1.initRoot<TestAllTypes>(); initTestMessage(root1); Orphan<TestAllTypes> orphan = builder2.getOrphanage().newOrphanCopy(root1.asReader()); checkTestMessage(orphan.getReader()); auto root2 = builder2.initRoot<TestAllTypes>(); root2.adoptStructField(kj::mv(orphan)); } TEST(Orphans, OrphanageListCopy) { MallocMessageBuilder builder1; MallocMessageBuilder builder2; auto root1 = builder1.initRoot<TestAllTypes>(); root1.setUInt32List({12, 34, 56}); Orphan<List<uint32_t>> orphan = builder2.getOrphanage().newOrphanCopy( root1.asReader().getUInt32List()); checkList(orphan.getReader(), {12u, 34u, 56u}); auto root2 = builder2.initRoot<TestAllTypes>(); root2.adoptUInt32List(kj::mv(orphan)); } TEST(Orphans, OrphanageTextCopy) { MallocMessageBuilder builder; Orphan<Text> orphan = builder.getOrphanage().newOrphanCopy(Text::Reader("foobarba")); EXPECT_EQ("foobarba", orphan.getReader()); auto root = builder.initRoot<TestAllTypes>(); root.adoptTextField(kj::mv(orphan)); } TEST(Orphans, OrphanageDataCopy) { MallocMessageBuilder builder; Orphan<Data> orphan = builder.getOrphanage().newOrphanCopy(data("foo")); EXPECT_EQ(data("foo"), orphan.getReader()); auto root = builder.initRoot<TestAllTypes>(); root.adoptDataField(kj::mv(orphan)); } TEST(Orphans, ZeroOut) { MallocMessageBuilder builder; TestAllTypes::Reader orphanReader; { Orphan<TestAllTypes> orphan = builder.getOrphanage().newOrphan<TestAllTypes>(); orphanReader = orphan.getReader(); initTestMessage(orphan.get()); checkTestMessage(orphan.getReader()); } // Once the Orphan destructor is called, the message should be zero'd out. checkTestMessageAllZero(orphanReader); } TEST(Orphans, StructObject) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); initTestMessage(root.getObjectField().initAs<TestAllTypes>()); EXPECT_TRUE(root.hasObjectField()); Orphan<TestAllTypes> orphan = root.getObjectField().disownAs<TestAllTypes>(); EXPECT_FALSE(orphan == nullptr); checkTestMessage(orphan.getReader()); EXPECT_FALSE(root.hasObjectField()); root.getObjectField().adopt(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasObjectField()); checkTestMessage(root.asReader().getObjectField().getAs<TestAllTypes>()); } TEST(Orphans, ListObject) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); root.getObjectField().setAs<List<uint32_t>>({12, 34, 56}); EXPECT_TRUE(root.hasObjectField()); Orphan<List<uint32_t>> orphan = root.getObjectField().disownAs<List<uint32_t>>(); EXPECT_FALSE(orphan == nullptr); checkList(orphan.getReader(), {12u, 34u, 56u}); EXPECT_FALSE(root.hasObjectField()); root.getObjectField().adopt(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasObjectField()); checkList(root.asReader().getObjectField().getAs<List<uint32_t>>(), {12u, 34u, 56u}); } TEST(Orphans, DynamicStruct) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); initTestMessage(root.getObjectField().initAs<TestAllTypes>()); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicStruct> orphan = root.getObjectField().disownAs<DynamicStruct>(Schema::from<TestAllTypes>()); EXPECT_FALSE(orphan == nullptr); EXPECT_TRUE(orphan.get().getSchema() == Schema::from<TestAllTypes>()); checkDynamicTestMessage(orphan.getReader()); EXPECT_FALSE(root.hasObjectField()); root.getObjectField().adopt(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasObjectField()); checkTestMessage(root.asReader().getObjectField().getAs<TestAllTypes>()); Orphan<DynamicStruct> orphan2 = root.getObjectField().disownAs<TestAllTypes>(); EXPECT_FALSE(orphan2 == nullptr); EXPECT_TRUE(orphan2.get().getSchema() == Schema::from<TestAllTypes>()); checkDynamicTestMessage(orphan2.getReader()); } TEST(Orphans, DynamicList) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); root.getObjectField().setAs<List<uint32_t>>({12, 34, 56}); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicList> orphan = root.getObjectField().disownAs<DynamicList>(Schema::from<List<uint32_t>>()); EXPECT_FALSE(orphan == nullptr); checkList<uint32_t>(orphan.getReader(), {12, 34, 56}); EXPECT_FALSE(root.hasObjectField()); root.getObjectField().adopt(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasObjectField()); checkList(root.asReader().getObjectField().getAs<List<uint32_t>>(), {12u, 34u, 56u}); Orphan<DynamicList> orphan2 = root.getObjectField().disownAs<List<uint32_t>>(); EXPECT_FALSE(orphan2 == nullptr); checkList<uint32_t>(orphan2.getReader(), {12, 34, 56}); } TEST(Orphans, DynamicStructList) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); auto list = root.getObjectField().initAs<List<TestAllTypes>>(2); list[0].setTextField("foo"); list[1].setTextField("bar"); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicList> orphan = root.getObjectField().disownAs<DynamicList>(Schema::from<List<TestAllTypes>>()); EXPECT_FALSE(orphan == nullptr); ASSERT_EQ(2u, orphan.get().size()); EXPECT_EQ("foo", orphan.get()[0].as<TestAllTypes>().getTextField()); EXPECT_EQ("bar", orphan.get()[1].as<TestAllTypes>().getTextField()); EXPECT_FALSE(root.hasObjectField()); root.getObjectField().adopt(kj::mv(orphan)); EXPECT_TRUE(orphan == nullptr); EXPECT_TRUE(root.hasObjectField()); ASSERT_EQ(2u, root.asReader().getObjectField().getAs<List<TestAllTypes>>().size()); EXPECT_EQ("foo", root.asReader().getObjectField().getAs<List<TestAllTypes>>()[0].getTextField()); EXPECT_EQ("bar", root.asReader().getObjectField().getAs<List<TestAllTypes>>()[1].getTextField()); } TEST(Orphans, OrphanageDynamicStruct) { MallocMessageBuilder builder; Orphan<DynamicStruct> orphan = builder.getOrphanage().newOrphan(Schema::from<TestAllTypes>()); initDynamicTestMessage(orphan.get()); checkDynamicTestMessage(orphan.getReader()); auto root = builder.initRoot<test::TestObject>(); root.getObjectField().adopt(kj::mv(orphan)); checkTestMessage(root.asReader().getObjectField().getAs<TestAllTypes>()); } TEST(Orphans, OrphanageDynamicList) { MallocMessageBuilder builder; Orphan<DynamicList> orphan = builder.getOrphanage().newOrphan(Schema::from<List<uint32_t>>(), 2); orphan.get().set(0, 123); orphan.get().set(1, 456); checkList<uint32_t>(orphan.getReader(), {123, 456}); auto root = builder.initRoot<test::TestObject>(); root.getObjectField().adopt(kj::mv(orphan)); checkList(root.getObjectField().getAs<List<uint32_t>>(), {123u, 456u}); } TEST(Orphans, OrphanageDynamicStructCopy) { MallocMessageBuilder builder1; MallocMessageBuilder builder2; auto root1 = builder1.initRoot<test::TestObject>(); initTestMessage(root1.getObjectField().initAs<TestAllTypes>()); Orphan<DynamicStruct> orphan = builder2.getOrphanage().newOrphanCopy( root1.asReader().getObjectField().getAs<DynamicStruct>(Schema::from<TestAllTypes>())); checkDynamicTestMessage(orphan.getReader()); auto root2 = builder2.initRoot<test::TestObject>(); root2.getObjectField().adopt(kj::mv(orphan)); checkTestMessage(root2.asReader().getObjectField().getAs<TestAllTypes>()); } TEST(Orphans, OrphanageDynamicListCopy) { MallocMessageBuilder builder1; MallocMessageBuilder builder2; auto root1 = builder1.initRoot<test::TestObject>(); root1.getObjectField().setAs<List<uint32_t>>({12, 34, 56}); Orphan<DynamicList> orphan = builder2.getOrphanage().newOrphanCopy( root1.asReader().getObjectField().getAs<DynamicList>(Schema::from<List<uint32_t>>())); checkList<uint32_t>(orphan.getReader(), {12, 34, 56}); auto root2 = builder2.initRoot<test::TestObject>(); root2.getObjectField().adopt(kj::mv(orphan)); checkList(root2.getObjectField().getAs<List<uint32_t>>(), {12u, 34u, 56u}); } TEST(Orphans, DynamicStructAs) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); initTestMessage(root.getObjectField().initAs<TestAllTypes>()); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicValue> orphan = root.getObjectField().disownAs<DynamicStruct>(Schema::from<TestAllTypes>()); EXPECT_EQ(DynamicValue::STRUCT, orphan.getType()); checkTestMessage(orphan.getReader().as<TestAllTypes>()); checkTestMessage(orphan.get().as<TestAllTypes>()); { Orphan<DynamicStruct> structOrphan = orphan.releaseAs<DynamicStruct>(); EXPECT_EQ(DynamicValue::UNKNOWN, orphan.getType()); EXPECT_FALSE(structOrphan == nullptr); checkDynamicTestMessage(structOrphan.getReader()); checkDynamicTestMessage(structOrphan.get()); checkTestMessage(structOrphan.getReader().as<TestAllTypes>()); checkTestMessage(structOrphan.get().as<TestAllTypes>()); { Orphan<TestAllTypes> typedOrphan = structOrphan.releaseAs<TestAllTypes>(); EXPECT_TRUE(structOrphan == nullptr); EXPECT_FALSE(typedOrphan == nullptr); checkTestMessage(typedOrphan.getReader()); checkTestMessage(typedOrphan.get()); orphan = kj::mv(typedOrphan); EXPECT_EQ(DynamicValue::STRUCT, orphan.getType()); EXPECT_TRUE(typedOrphan == nullptr); } } { Orphan<TestAllTypes> typedOrphan = orphan.releaseAs<TestAllTypes>(); checkTestMessage(typedOrphan.getReader()); checkTestMessage(typedOrphan.get()); } } TEST(Orphans, DynamicListAs) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); root.getObjectField().setAs<List<uint32_t>>({12, 34, 56}); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicValue> orphan = root.getObjectField().disownAs<DynamicList>(Schema::from<List<uint32_t>>()); EXPECT_EQ(DynamicValue::LIST, orphan.getType()); checkList(orphan.getReader().as<List<uint32_t>>(), {12, 34, 56}); checkList(orphan.get().as<List<uint32_t>>(), {12, 34, 56}); { Orphan<DynamicList> listOrphan = orphan.releaseAs<DynamicList>(); EXPECT_EQ(DynamicValue::UNKNOWN, orphan.getType()); EXPECT_FALSE(listOrphan == nullptr); checkList<uint32_t>(listOrphan.getReader(), {12, 34, 56}); checkList<uint32_t>(listOrphan.get(), {12, 34, 56}); checkList(listOrphan.getReader().as<List<uint32_t>>(), {12, 34, 56}); checkList(listOrphan.get().as<List<uint32_t>>(), {12, 34, 56}); { Orphan<List<uint32_t>> typedOrphan = listOrphan.releaseAs<List<uint32_t>>(); EXPECT_TRUE(listOrphan == nullptr); EXPECT_FALSE(typedOrphan == nullptr); checkList(typedOrphan.getReader(), {12, 34, 56}); checkList(typedOrphan.get(), {12, 34, 56}); orphan = kj::mv(typedOrphan); EXPECT_EQ(DynamicValue::LIST, orphan.getType()); EXPECT_TRUE(typedOrphan == nullptr); } } { Orphan<List<uint32_t>> typedOrphan = orphan.releaseAs<List<uint32_t>>(); checkList(typedOrphan.getReader(), {12, 34, 56}); checkList(typedOrphan.get(), {12, 34, 56}); } } TEST(Orphans, DynamicObject) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); initTestMessage(root.getObjectField().initAs<TestAllTypes>()); EXPECT_TRUE(root.hasObjectField()); Orphan<DynamicValue> orphan = root.getObjectField().disown(); EXPECT_EQ(DynamicValue::OBJECT, orphan.getType()); Orphan<ObjectPointer> objectOrphan = orphan.releaseAs<ObjectPointer>(); checkTestMessage(objectOrphan.getAs<TestAllTypes>()); checkDynamicTestMessage(objectOrphan.getAs<DynamicStruct>(Schema::from<TestAllTypes>())); } TEST(Orphans, DynamicDisown) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); initTestMessage(root); Orphan<TestAllTypes> dstOrphan = Orphanage::getForMessageContaining(root).newOrphan<TestAllTypes>(); auto dst = dstOrphan.get(); DynamicStruct::Builder dynamic = root; DynamicStruct::Builder dynamicDst = dst; for (auto field: dynamic.getSchema().getFields()) { dynamicDst.adopt(field, dynamic.disown(field)); } checkTestMessageAllZero(root.asReader()); checkTestMessage(dst.asReader()); for (auto field: dynamic.getSchema().getFields()) { dynamicDst.adopt(field, dynamic.disown(field)); } checkTestMessageAllZero(root.asReader()); checkTestMessageAllZero(dst.asReader()); } TEST(Orphans, DynamicDisownGroup) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestGroups>(); auto bar = root.initGroups().initBar(); bar.setCorge(123); bar.setGrault("foo"); bar.setGarply(9876543210987ll); Orphan<test::TestGroups> dstOrphan = Orphanage::getForMessageContaining(root).newOrphan<test::TestGroups>(); auto dst = dstOrphan.get(); toDynamic(dst).adopt("groups", toDynamic(root).disown("groups")); EXPECT_EQ(test::TestGroups::Groups::FOO, root.getGroups().which()); EXPECT_EQ(test::TestGroups::Groups::BAR, dst.getGroups().which()); auto newBar = dst.getGroups().getBar(); EXPECT_EQ(123, newBar.getCorge()); EXPECT_EQ("foo", newBar.getGrault()); EXPECT_EQ(9876543210987ll, newBar.getGarply()); } TEST(Orphans, OrphanageFromBuilder) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); { Orphanage orphanage = Orphanage::getForMessageContaining(root); Orphan<TestAllTypes> orphan = orphanage.newOrphan<TestAllTypes>(); initTestMessage(orphan.get()); root.adoptStructField(kj::mv(orphan)); checkTestMessage(root.asReader().getStructField()); } { Orphanage orphanage = Orphanage::getForMessageContaining(root.initBoolList(3)); Orphan<TestAllTypes> orphan = orphanage.newOrphan<TestAllTypes>(); initTestMessage(orphan.get()); root.adoptStructField(kj::mv(orphan)); checkTestMessage(root.asReader().getStructField()); } { Orphanage orphanage = Orphanage::getForMessageContaining(toDynamic(root)); Orphan<TestAllTypes> orphan = orphanage.newOrphan<TestAllTypes>(); initTestMessage(orphan.get()); root.adoptStructField(kj::mv(orphan)); checkTestMessage(root.asReader().getStructField()); } { Orphanage orphanage = Orphanage::getForMessageContaining(toDynamic(root.initBoolList(3))); Orphan<TestAllTypes> orphan = orphanage.newOrphan<TestAllTypes>(); initTestMessage(orphan.get()); root.adoptStructField(kj::mv(orphan)); checkTestMessage(root.asReader().getStructField()); } } static bool allZero(const word* begin, const word* end) { for (const byte* pos = reinterpret_cast<const byte*>(begin); pos < reinterpret_cast<const byte*>(end); ++pos) { if (*pos != 0) return false; } return true; } TEST(Orphans, StructsZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); initTestMessage(root.initStructField()); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownStructField(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, ListsZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); root.setUInt32List({12, 34, 56}); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownUInt32List(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, EmptyListsZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); root.initUInt32List(0); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownUInt32List(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, StructListsZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); { auto list = root.initStructList(2); initTestMessage(list[0]); initTestMessage(list[1]); } const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownStructList(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, EmptyStructListsZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); root.initStructList(0); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownStructList(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, TextZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); root.setTextField("abcd123"); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setDataField(data("foo")); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownTextField(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ(data("foo"), root.getDataField()); } TEST(Orphans, DataZerodAfterUse) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); const word* zerosStart = builder.getSegmentsForOutput()[0].end(); root.setDataField(data("abcd123")); const word* zerosEnd = builder.getSegmentsForOutput()[0].end(); root.setTextField("foo"); // guard against overruns EXPECT_EQ(1u, builder.getSegmentsForOutput().size()); // otherwise test is invalid root.disownDataField(); EXPECT_TRUE(allZero(zerosStart, zerosEnd)); EXPECT_EQ("foo", root.getTextField()); } TEST(Orphans, FarPointer) { MallocMessageBuilder builder(0, AllocationStrategy::FIXED_SIZE); auto root = builder.initRoot<TestAllTypes>(); auto child = root.initStructField(); initTestMessage(child); auto orphan = root.disownStructField(); EXPECT_FALSE(root.hasStructField()); EXPECT_TRUE(orphan != nullptr); EXPECT_FALSE(orphan == nullptr); checkTestMessage(orphan.getReader()); checkTestMessage(orphan.get()); } TEST(Orphans, UpgradeStruct) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); auto old = root.getObjectField().initAs<test::TestOldVersion>(); old.setOld1(1234); old.setOld2("foo"); auto orphan = root.getObjectField().disownAs<test::TestNewVersion>(); // Relocation has not occurred yet. old.setOld1(12345); EXPECT_EQ(12345, orphan.getReader().getOld1()); EXPECT_EQ("foo", old.getOld2()); // This will relocate the struct. auto newVersion = orphan.get(); EXPECT_EQ(0, old.getOld1()); EXPECT_EQ("", old.getOld2()); EXPECT_EQ(12345, newVersion.getOld1()); EXPECT_EQ("foo", newVersion.getOld2()); } TEST(Orphans, UpgradeStructList) { MallocMessageBuilder builder; auto root = builder.initRoot<test::TestObject>(); auto old = root.getObjectField().initAs<List<test::TestOldVersion>>(2); old[0].setOld1(1234); old[0].setOld2("foo"); old[1].setOld1(4321); old[1].setOld2("bar"); auto orphan = root.getObjectField().disownAs<List<test::TestNewVersion>>(); // Relocation has not occurred yet. old[0].setOld1(12345); EXPECT_EQ(12345, orphan.getReader()[0].getOld1()); EXPECT_EQ("foo", old[0].getOld2()); // This will relocate the struct. auto newVersion = orphan.get(); EXPECT_EQ(0, old[0].getOld1()); EXPECT_EQ("", old[0].getOld2()); EXPECT_EQ(12345, newVersion[0].getOld1()); EXPECT_EQ("foo", newVersion[0].getOld2()); EXPECT_EQ(4321, newVersion[1].getOld1()); EXPECT_EQ("bar", newVersion[1].getOld2()); } TEST(Orphans, DisownNull) { MallocMessageBuilder builder; auto root = builder.initRoot<TestAllTypes>(); { Orphan<TestAllTypes> orphan = root.disownStructField(); EXPECT_TRUE(orphan == nullptr); checkTestMessageAllZero(orphan.getReader()); EXPECT_TRUE(orphan == nullptr); // get()ing the orphan allocates an object, for security reasons. checkTestMessageAllZero(orphan.get()); EXPECT_FALSE(orphan == nullptr); } { Orphan<List<int32_t>> orphan = root.disownInt32List(); EXPECT_TRUE(orphan == nullptr); EXPECT_EQ(0, orphan.getReader().size()); EXPECT_TRUE(orphan == nullptr); EXPECT_EQ(0, orphan.get().size()); EXPECT_TRUE(orphan == nullptr); } { Orphan<List<TestAllTypes>> orphan = root.disownStructList(); EXPECT_TRUE(orphan == nullptr); EXPECT_EQ(0, orphan.getReader().size()); EXPECT_TRUE(orphan == nullptr); EXPECT_EQ(0, orphan.get().size()); EXPECT_TRUE(orphan == nullptr); } } } // namespace } // namespace _ (private) } // namespace capnp