binderUnitTest: Parcel::appendFrom

Coverage from this exists elsewhere and in Java, but
it's helpful to have these tests easily accessible when
working on C++ code here.

Bug: 287093457
Test: binderUnitTest
Change-Id: If393c90f972cacff36e1a04614635c1597d419f4
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 359c783..0a0dae0 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -29,6 +29,7 @@
 using android::status_t;
 using android::String16;
 using android::String8;
+using android::base::unique_fd;
 using android::binder::Status;
 
 TEST(Parcel, NonNullTerminatedString8) {
@@ -112,6 +113,166 @@
     EXPECT_EQ(ret[1], STDIN_FILENO);
 }
 
+TEST(Parcel, AppendFromEmpty) {
+    Parcel p1;
+    Parcel p2;
+    p2.writeInt32(2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(2, p1.readInt32());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendPlainData) {
+    Parcel p1;
+    p1.writeInt32(1);
+    Parcel p2;
+    p2.writeInt32(2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(2, p1.readInt32());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendPlainDataPartial) {
+    Parcel p1;
+    p1.writeInt32(1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeInt32(3);
+    p2.writeInt32(4);
+
+    // only copy 8 bytes (two int32's worth)
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(3, p1.readInt32());
+    ASSERT_EQ(0, p1.readInt32()); // not 4, end of Parcel
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendWithBinder) {
+    sp<IBinder> b1 = sp<BBinder>::make();
+    sp<IBinder> b2 = sp<BBinder>::make();
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeStrongBinder(b1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeStrongBinder(b2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(b1, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(b2, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_EQ(b2, p2.readStrongBinder());
+}
+
+TEST(Parcel, AppendWithBinderPartial) {
+    sp<IBinder> b1 = sp<BBinder>::make();
+    sp<IBinder> b2 = sp<BBinder>::make();
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeStrongBinder(b1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeStrongBinder(b2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into strong binder
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(b1, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(1935813253, p1.readInt32()); // whatever garbage that is there (ABI)
+    ASSERT_EQ(1, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_EQ(b2, p2.readStrongBinder());
+}
+
+TEST(Parcel, AppendWithFd) {
+    unique_fd fd1 = unique_fd(dup(0));
+    unique_fd fd2 = unique_fd(dup(0));
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeDupFileDescriptor(0);      // with ownership
+    p1.writeFileDescriptor(fd1.get()); // without ownership
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeDupFileDescriptor(0);      // with ownership
+    p2.writeFileDescriptor(fd2.get()); // without ownership
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(4, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+}
+
+TEST(Parcel, AppendWithFdPartial) {
+    unique_fd fd1 = unique_fd(dup(0));
+    unique_fd fd2 = unique_fd(dup(0));
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeDupFileDescriptor(0);      // with ownership
+    p1.writeFileDescriptor(fd1.get()); // without ownership
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeDupFileDescriptor(0);      // with ownership
+    p2.writeFileDescriptor(fd2.get()); // without ownership
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into binder
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(1717840517, p1.readInt32()); // whatever garbage that is there (ABI)
+    ASSERT_EQ(2, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+}
+
 // Tests a second operation results in a parcel at the same location as it
 // started.
 void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {