/* * 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 using namespace android; using namespace android::uirenderer; enum MockTypes { Lifecycle, NoOp, IntHolder, COUNT }; using Op = MockTypes; template struct MockOp; template struct MockOpContainer { OpBufferItemHeader header; MockOp impl; MockOpContainer(MockOp&& 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 { 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 {}; template<> struct MockOp { int value = -1; }; struct MockBuffer : public OpBuffer { template void push(MockOp&& op) { push_container(MockOpContainer{std::move(op)}); } }; template 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 { MockOp{&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 { MockOp{&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 { MockOp{&tracker} }); EXPECT_EQ(2, countItems(other)); EXPECT_EQ(2, tracker.alive()); buffer.push_container(MockOpContainer { MockOp{&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({42}); buffer.for_each([](auto op) { static_assert(std::is_const_v>, "Expected container to be const"); }); } TEST(OpBuffer, filterView) { MockBuffer buffer; buffer.push({}); buffer.push({0}); buffer.push({1}); buffer.push({}); buffer.push({}); buffer.push({2}); buffer.push({}); buffer.push({}); buffer.push({}); buffer.push({}); int index = 0; for (const auto& it : buffer.filter()) { 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()) { ASSERT_EQ(Op::NoOp, it.header.type); count++; } EXPECT_EQ(count, 7); }