Add a way to iterate over a specific op type

Also split the OpBuffer tests out from CanvasOpTests

Test: this
Change-Id: I0fbc726d108bfa4333c01daf7aedacca8716e6ae
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index 033a587..a09e742 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -36,50 +36,6 @@
 // We lazy
 using Op = CanvasOpType;
 
-enum MockTypes {
-    Lifecycle,
-    COUNT
-};
-
-template<MockTypes T>
-struct MockOp;
-
-template<MockTypes T>
-struct MockOpContainer {
-    OpBufferItemHeader<MockTypes> header;
-    MockOp<T> 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;
-};
-
-using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
-
 class CanvasOpCountingReceiver {
 public:
     template <CanvasOpType T>
@@ -104,62 +60,6 @@
     return count;
 }
 
-TEST(CanvasOp, lifecycleCheck) {
-    LifecycleTracker tracker;
-    {
-        MockBuffer buffer;
-        buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
-            .impl = MockOp<MockTypes::Lifecycle>{&tracker}
-        });
-        EXPECT_EQ(tracker.alive(), 1);
-        buffer.clear();
-        EXPECT_EQ(tracker.alive(), 0);
-    }
-    EXPECT_EQ(tracker.alive(), 0);
-}
-
-TEST(CanvasOp, lifecycleCheckMove) {
-    LifecycleTracker tracker;
-    {
-        MockBuffer buffer;
-        buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
-            .impl = 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> {
-                .impl = MockOp<MockTypes::Lifecycle>{&tracker}
-            });
-
-            EXPECT_EQ(2, countItems(other));
-            EXPECT_EQ(2, tracker.alive());
-
-            buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
-                .impl = 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(CanvasOp, verifyConst) {
     CanvasOpBuffer buffer;
     buffer.push<Op::DrawColor>({
@@ -708,7 +608,3 @@
     EXPECT_EQ(1, receiver[Op::Save]);
     EXPECT_EQ(1, receiver[Op::Restore]);
 }
-
-TEST(CanvasOp, frontendTransform) {
-
-}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/OpBufferTests.cpp b/libs/hwui/tests/unit/OpBufferTests.cpp
new file mode 100644
index 0000000..c0ae943
--- /dev/null
+++ b/libs/hwui/tests/unit/OpBufferTests.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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);
+}
+