| /* | |
| * 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 <gtest/gtest.h> | |
| #include <canvas/OpBuffer.h> | |
| using namespace android; | |
| using namespace android::uirenderer; | |
| enum MockTypes { | |
| Lifecycle, | |
| NoOp, | |
| IntHolder, | |
| COUNT | |
| }; | |
| using Op = MockTypes; | |
| template<MockTypes T> | |
| struct MockOp; | |
| template<MockTypes T> | |
| struct MockOpContainer { | |
| OpBufferItemHeader<MockTypes> header; | |
| MockOp<T> impl; | |
| MockOpContainer(MockOp<T>&& impl) : impl(std::move(impl)) {} | |
| }; | |
| struct LifecycleTracker { | |
| int ctor_count = 0; | |
| int dtor_count = 0; | |
| int alive() { return ctor_count - dtor_count; } | |
| }; | |
| template<> | |
| struct MockOp<MockTypes::Lifecycle> { | |
| MockOp() = delete; | |
| void operator=(const MockOp&) = delete; | |
| MockOp(LifecycleTracker* tracker) : tracker(tracker) { | |
| tracker->ctor_count += 1; | |
| } | |
| MockOp(const MockOp& other) { | |
| tracker = other.tracker; | |
| tracker->ctor_count += 1; | |
| } | |
| ~MockOp() { | |
| tracker->dtor_count += 1; | |
| } | |
| LifecycleTracker* tracker = nullptr; | |
| }; | |
| template<> | |
| struct MockOp<MockTypes::NoOp> {}; | |
| template<> | |
| struct MockOp<MockTypes::IntHolder> { | |
| int value = -1; | |
| }; | |
| struct MockBuffer : public OpBuffer<MockTypes, MockOpContainer> { | |
| template <MockTypes T> | |
| void push(MockOp<T>&& op) { | |
| push_container(MockOpContainer<T>{std::move(op)}); | |
| } | |
| }; | |
| template<typename T> | |
| static int countItems(const T& t) { | |
| int count = 0; | |
| t.for_each([&](auto i) { | |
| count++; | |
| }); | |
| return count; | |
| } | |
| TEST(OpBuffer, lifecycleCheck) { | |
| LifecycleTracker tracker; | |
| { | |
| MockBuffer buffer; | |
| buffer.push_container(MockOpContainer<Op::Lifecycle> { | |
| MockOp<MockTypes::Lifecycle>{&tracker} | |
| }); | |
| EXPECT_EQ(tracker.alive(), 1); | |
| buffer.clear(); | |
| EXPECT_EQ(tracker.alive(), 0); | |
| } | |
| EXPECT_EQ(tracker.alive(), 0); | |
| } | |
| TEST(OpBuffer, lifecycleCheckMove) { | |
| LifecycleTracker tracker; | |
| { | |
| MockBuffer buffer; | |
| buffer.push_container(MockOpContainer<Op::Lifecycle> { | |
| MockOp<MockTypes::Lifecycle>{&tracker} | |
| }); | |
| EXPECT_EQ(tracker.alive(), 1); | |
| { | |
| MockBuffer other(std::move(buffer)); | |
| EXPECT_EQ(tracker.alive(), 1); | |
| EXPECT_EQ(buffer.size(), 0); | |
| EXPECT_GT(other.size(), 0); | |
| EXPECT_EQ(1, countItems(other)); | |
| EXPECT_EQ(0, countItems(buffer)); | |
| other.push_container(MockOpContainer<MockTypes::Lifecycle> { | |
| MockOp<MockTypes::Lifecycle>{&tracker} | |
| }); | |
| EXPECT_EQ(2, countItems(other)); | |
| EXPECT_EQ(2, tracker.alive()); | |
| buffer.push_container(MockOpContainer<MockTypes::Lifecycle> { | |
| MockOp<MockTypes::Lifecycle>{&tracker} | |
| }); | |
| EXPECT_EQ(1, countItems(buffer)); | |
| EXPECT_EQ(3, tracker.alive()); | |
| buffer = std::move(other); | |
| EXPECT_EQ(2, countItems(buffer)); | |
| EXPECT_EQ(2, tracker.alive()); | |
| } | |
| EXPECT_EQ(2, countItems(buffer)); | |
| EXPECT_EQ(2, tracker.alive()); | |
| buffer.clear(); | |
| EXPECT_EQ(0, countItems(buffer)); | |
| EXPECT_EQ(0, tracker.alive()); | |
| } | |
| EXPECT_EQ(tracker.alive(), 0); | |
| } | |
| TEST(OpBuffer, verifyConst) { | |
| MockBuffer buffer; | |
| buffer.push<Op::IntHolder>({42}); | |
| buffer.for_each([](auto op) { | |
| static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>, | |
| "Expected container to be const"); | |
| }); | |
| } | |
| TEST(OpBuffer, filterView) { | |
| MockBuffer buffer; | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::IntHolder>({0}); | |
| buffer.push<Op::IntHolder>({1}); | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::IntHolder>({2}); | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::NoOp>({}); | |
| buffer.push<Op::NoOp>({}); | |
| int index = 0; | |
| for (const auto& it : buffer.filter<Op::IntHolder>()) { | |
| ASSERT_EQ(Op::IntHolder, it.header.type); | |
| EXPECT_EQ(index, it.impl.value); | |
| index++; | |
| } | |
| EXPECT_EQ(index, 3); | |
| int count = 0; | |
| for (const auto& it : buffer.filter<Op::NoOp>()) { | |
| ASSERT_EQ(Op::NoOp, it.header.type); | |
| count++; | |
| } | |
| EXPECT_EQ(count, 7); | |
| } | |