diff options
Diffstat (limited to 'libs/ui/tests/FlattenableHelpers_test.cpp')
-rw-r--r-- | libs/ui/tests/FlattenableHelpers_test.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp new file mode 100644 index 0000000000..44e20b504d --- /dev/null +++ b/libs/ui/tests/FlattenableHelpers_test.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "FlattenableHelpersTest" + +#include <ui/FlattenableHelpers.h> + +#include <gtest/gtest.h> +#include <utils/Flattenable.h> +#include <cstdint> +#include <memory> +#include <optional> +#include <string> +#include <vector> + +namespace android { + +namespace { + +struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> { + std::unique_ptr<int32_t> ptr; + + bool isFixedSize() const { return true; } + size_t getFlattenedSize() const { return sizeof(int32_t); } + + status_t flatten(void* buffer, size_t size) const { + FlattenableUtils::write(buffer, size, *ptr); + return OK; + } + + status_t unflatten(void const* buffer, size_t size) { + int32_t value; + FlattenableUtils::read(buffer, size, value); + ptr = std::make_unique<int32_t>(value); + return OK; + } +}; + +class FlattenableHelpersTest : public testing::Test { +public: + template <class T> + void testWriteThenRead(const T& value, size_t bufferSize) { + std::vector<int8_t> buffer(bufferSize); + auto rawBuffer = reinterpret_cast<void*>(buffer.data()); + size_t size = buffer.size(); + ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value)); + + auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data()); + size = buffer.size(); + T valueRead; + ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead)); + EXPECT_EQ(value, valueRead); + } + + template <class T> + void testTriviallyCopyable(const T& value) { + testWriteThenRead(value, sizeof(T)); + } + + template <class T> + void testWriteThenRead(const T& value) { + testWriteThenRead(value, FlattenableHelpers::getFlattenedSize(value)); + } +}; + +TEST_F(FlattenableHelpersTest, TriviallyCopyable) { + testTriviallyCopyable(42); + testTriviallyCopyable(1LL << 63); + testTriviallyCopyable(false); + testTriviallyCopyable(true); + testTriviallyCopyable(std::optional<int>()); + testTriviallyCopyable(std::optional<int>(4)); +} + +TEST_F(FlattenableHelpersTest, String) { + testWriteThenRead(std::string("Android")); + testWriteThenRead(std::string()); +} + +TEST_F(FlattenableHelpersTest, Vector) { + testWriteThenRead(std::vector<int>({1, 2, 3})); + testWriteThenRead(std::vector<int>()); +} + +TEST_F(FlattenableHelpersTest, OptionalOfLightFlattenable) { + std::vector<size_t> buffer; + constexpr int kInternalValue = 16; + { + std::optional<TestLightFlattenable> value = + TestLightFlattenable{.ptr = std::make_unique<int32_t>(kInternalValue)}; + buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0); + void* rawBuffer = reinterpret_cast<void*>(buffer.data()); + size_t size = buffer.size(); + ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value)); + } + + const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data()); + size_t size = buffer.size(); + std::optional<TestLightFlattenable> valueRead; + ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead)); + ASSERT_TRUE(valueRead.has_value()); + EXPECT_EQ(kInternalValue, *valueRead->ptr); +} + +TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) { + std::vector<size_t> buffer; + { + std::optional<TestLightFlattenable> value; + buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0); + void* rawBuffer = reinterpret_cast<void*>(buffer.data()); + size_t size = buffer.size(); + ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value)); + } + + const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data()); + size_t size = buffer.size(); + std::optional<TestLightFlattenable> valueRead; + ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead)); + ASSERT_FALSE(valueRead.has_value()); +} + +// If a struct is both trivially copyable and light flattenable we should treat it +// as LigthFlattenable. +TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) { + static constexpr int32_t kSizeTag = 1234567; + static constexpr int32_t kFlattenTag = 987654; + static constexpr int32_t kUnflattenTag = 5926582; + + struct LightFlattenableAndTriviallyCopyable + : LightFlattenable<LightFlattenableAndTriviallyCopyable> { + int32_t value; + + bool isFixedSize() const { return true; } + size_t getFlattenedSize() const { return kSizeTag; } + + status_t flatten(void* buffer, size_t size) const { + FlattenableUtils::write(buffer, size, kFlattenTag); + return OK; + } + + status_t unflatten(void const*, size_t) { + value = kUnflattenTag; + return OK; + } + }; + + { + // Verify that getFlattenedSize uses the LightFlattenable overload + LightFlattenableAndTriviallyCopyable foo; + EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo)); + } + + { + // Verify that flatten uses the LightFlattenable overload + std::vector<int8_t> buffer(sizeof(int32_t)); + auto rawBuffer = reinterpret_cast<void*>(buffer.data()); + size_t size = buffer.size(); + LightFlattenableAndTriviallyCopyable foo; + ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo)); + + auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data()); + int32_t value; + FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value); + EXPECT_EQ(kFlattenTag, value); + } + + { + // Verify that unflatten uses the LightFlattenable overload + std::vector<int8_t> buffer(sizeof(int32_t)); + auto rawBuffer = reinterpret_cast<void*>(buffer.data()); + size_t size = buffer.size(); + int32_t value = 4; + ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value)); + + auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data()); + + LightFlattenableAndTriviallyCopyable foo; + FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo); + EXPECT_EQ(kUnflattenTag, foo.value); + } +} + +} // namespace +} // namespace android |