1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include <canvas/OpBuffer.h>
20 
21 using namespace android;
22 using namespace android::uirenderer;
23 
24 enum MockTypes {
25     Lifecycle,
26     NoOp,
27     IntHolder,
28     COUNT
29 };
30 
31 using Op = MockTypes;
32 
33 template<MockTypes T>
34 struct MockOp;
35 
36 template<MockTypes T>
37 struct MockOpContainer {
38     OpBufferItemHeader<MockTypes> header;
39     MockOp<T> impl;
40 
MockOpContainerMockOpContainer41     MockOpContainer(MockOp<T>&& impl) : impl(std::move(impl)) {}
42 };
43 
44 struct LifecycleTracker {
45     int ctor_count = 0;
46     int dtor_count = 0;
47 
aliveLifecycleTracker48     int alive() { return ctor_count - dtor_count; }
49 };
50 
51 template<>
52 struct MockOp<MockTypes::Lifecycle> {
53     MockOp() = delete;
54     void operator=(const MockOp&) = delete;
55 
MockOpMockOp56     MockOp(LifecycleTracker* tracker) : tracker(tracker) {
57         tracker->ctor_count += 1;
58     }
59 
MockOpMockOp60     MockOp(const MockOp& other) {
61         tracker = other.tracker;
62         tracker->ctor_count += 1;
63     }
64 
~MockOpMockOp65     ~MockOp() {
66         tracker->dtor_count += 1;
67     }
68 
69     LifecycleTracker* tracker = nullptr;
70 };
71 
72 template<>
73 struct MockOp<MockTypes::NoOp> {};
74 
75 template<>
76 struct MockOp<MockTypes::IntHolder> {
77     int value = -1;
78 };
79 
80 struct MockBuffer : public OpBuffer<MockTypes, MockOpContainer> {
81     template <MockTypes T>
pushMockBuffer82     void push(MockOp<T>&& op) {
83         push_container(MockOpContainer<T>{std::move(op)});
84     }
85 };
86 
87 template<typename T>
countItems(const T & t)88 static int countItems(const T& t) {
89     int count = 0;
90     t.for_each([&](auto i) {
91         count++;
92     });
93     return count;
94 }
95 
TEST(OpBuffer,lifecycleCheck)96 TEST(OpBuffer, lifecycleCheck) {
97     LifecycleTracker tracker;
98     {
99         MockBuffer buffer;
100         buffer.push_container(MockOpContainer<Op::Lifecycle> {
101             MockOp<MockTypes::Lifecycle>{&tracker}
102         });
103         EXPECT_EQ(tracker.alive(), 1);
104         buffer.clear();
105         EXPECT_EQ(tracker.alive(), 0);
106     }
107     EXPECT_EQ(tracker.alive(), 0);
108 }
109 
TEST(OpBuffer,lifecycleCheckMove)110 TEST(OpBuffer, lifecycleCheckMove) {
111     LifecycleTracker tracker;
112     {
113         MockBuffer buffer;
114         buffer.push_container(MockOpContainer<Op::Lifecycle> {
115             MockOp<MockTypes::Lifecycle>{&tracker}
116         });
117         EXPECT_EQ(tracker.alive(), 1);
118         {
119             MockBuffer other(std::move(buffer));
120             EXPECT_EQ(tracker.alive(), 1);
121             EXPECT_EQ(buffer.size(), 0);
122             EXPECT_GT(other.size(), 0);
123             EXPECT_EQ(1, countItems(other));
124             EXPECT_EQ(0, countItems(buffer));
125 
126             other.push_container(MockOpContainer<MockTypes::Lifecycle> {
127                 MockOp<MockTypes::Lifecycle>{&tracker}
128             });
129 
130             EXPECT_EQ(2, countItems(other));
131             EXPECT_EQ(2, tracker.alive());
132 
133             buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
134                 MockOp<MockTypes::Lifecycle>{&tracker}
135             });
136             EXPECT_EQ(1, countItems(buffer));
137             EXPECT_EQ(3, tracker.alive());
138 
139             buffer = std::move(other);
140             EXPECT_EQ(2, countItems(buffer));
141             EXPECT_EQ(2, tracker.alive());
142         }
143         EXPECT_EQ(2, countItems(buffer));
144         EXPECT_EQ(2, tracker.alive());
145         buffer.clear();
146         EXPECT_EQ(0, countItems(buffer));
147         EXPECT_EQ(0, tracker.alive());
148     }
149     EXPECT_EQ(tracker.alive(), 0);
150 }
151 
TEST(OpBuffer,verifyConst)152 TEST(OpBuffer, verifyConst) {
153     MockBuffer buffer;
154     buffer.push<Op::IntHolder>({42});
155     buffer.for_each([](auto op) {
156         static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>,
157                 "Expected container to be const");
158     });
159 }
160 
TEST(OpBuffer,filterView)161 TEST(OpBuffer, filterView) {
162     MockBuffer buffer;
163     buffer.push<Op::NoOp>({});
164     buffer.push<Op::IntHolder>({0});
165     buffer.push<Op::IntHolder>({1});
166     buffer.push<Op::NoOp>({});
167     buffer.push<Op::NoOp>({});
168     buffer.push<Op::IntHolder>({2});
169     buffer.push<Op::NoOp>({});
170     buffer.push<Op::NoOp>({});
171     buffer.push<Op::NoOp>({});
172     buffer.push<Op::NoOp>({});
173 
174 
175     int index = 0;
176     for (const auto& it : buffer.filter<Op::IntHolder>()) {
177         ASSERT_EQ(Op::IntHolder, it.header.type);
178         EXPECT_EQ(index, it.impl.value);
179         index++;
180     }
181     EXPECT_EQ(index, 3);
182 
183     int count = 0;
184     for (const auto& it : buffer.filter<Op::NoOp>()) {
185         ASSERT_EQ(Op::NoOp, it.header.type);
186         count++;
187     }
188     EXPECT_EQ(count, 7);
189 }
190 
191