/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using android::IPCThreadState; using android::OK; using android::Parcel; using android::String16; using android::String8; using android::status_t; TEST(Parcel, NonNullTerminatedString8) { String8 kTestString = String8("test-is-good"); // write non-null terminated string Parcel p; p.writeString8(kTestString); p.setDataPosition(0); // BAD! assumption of wire format for test // write over length of string p.writeInt32(kTestString.size() - 2); p.setDataPosition(0); String8 output; EXPECT_NE(OK, p.readString8(&output)); EXPECT_EQ(output.size(), 0); } TEST(Parcel, NonNullTerminatedString16) { String16 kTestString = String16("test-is-good"); // write non-null terminated string Parcel p; p.writeString16(kTestString); p.setDataPosition(0); // BAD! assumption of wire format for test // write over length of string p.writeInt32(kTestString.size() - 2); p.setDataPosition(0); String16 output; EXPECT_NE(OK, p.readString16(&output)); EXPECT_EQ(output.size(), 0); } // Tests a second operation results in a parcel at the same location as it // started. void parcelOpSameLength(const std::function& a, const std::function& b) { Parcel p; a(&p); size_t end = p.dataPosition(); p.setDataPosition(0); b(&p); EXPECT_EQ(end, p.dataPosition()); } TEST(Parcel, InverseInterfaceToken) { const String16 token = String16("asdf"); parcelOpSameLength([&] (Parcel* p) { p->writeInterfaceToken(token); }, [&] (Parcel* p) { EXPECT_TRUE(p->enforceInterface(token, IPCThreadState::self())); }); } TEST(Parcel, Utf8FromUtf16Read) { const char* token = "asdf"; parcelOpSameLength([&] (Parcel* p) { p->writeString16(String16(token)); }, [&] (Parcel* p) { std::string s; EXPECT_EQ(OK, p->readUtf8FromUtf16(&s)); EXPECT_EQ(token, s); }); } TEST(Parcel, Utf8AsUtf16Write) { std::string token = "asdf"; parcelOpSameLength([&] (Parcel* p) { p->writeUtf8AsUtf16(token); }, [&] (Parcel* p) { String16 s; EXPECT_EQ(OK, p->readString16(&s)); EXPECT_EQ(s, String16(token.c_str())); }); } template using readFunc = status_t (Parcel::*)(T* out) const; template using writeFunc = status_t (Parcel::*)(const T& in); template using copyWriteFunc = status_t (Parcel::*)(T in); template void readWriteInverse(std::vector&& ts, readFunc r, WRITE_FUNC w) { for (const T& value : ts) { parcelOpSameLength([&] (Parcel* p) { (*p.*w)(value); }, [&] (Parcel* p) { T outValue; EXPECT_EQ(OK, (*p.*r)(&outValue)); EXPECT_EQ(value, outValue); }); } } template void readWriteInverse(std::vector&& ts, readFunc r, writeFunc w) { readWriteInverse>(std::move(ts), r, w); } template void readWriteInverse(std::vector&& ts, readFunc r, copyWriteFunc w) { readWriteInverse>(std::move(ts), r, w); } #define TEST_READ_WRITE_INVERSE(type, name, ...) \ TEST(Parcel, Inverse##name) { \ readWriteInverse(__VA_ARGS__, &Parcel::read##name, &Parcel::write##name); \ } TEST_READ_WRITE_INVERSE(int32_t, Int32, {-2, -1, 0, 1, 2}); TEST_READ_WRITE_INVERSE(uint32_t, Uint32, {0, 1, 2}); TEST_READ_WRITE_INVERSE(int64_t, Int64, {-2, -1, 0, 1, 2}); TEST_READ_WRITE_INVERSE(uint64_t, Uint64, {0, 1, 2}); TEST_READ_WRITE_INVERSE(float, Float, {-1.0f, 0.0f, 3.14f}); TEST_READ_WRITE_INVERSE(double, Double, {-1.0, 0.0, 3.14}); TEST_READ_WRITE_INVERSE(bool, Bool, {true, false}); TEST_READ_WRITE_INVERSE(char16_t, Char, {u'a', u'\0'}); TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1}); TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")}); TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});