summaryrefslogtreecommitdiffstats
path: root/gfx/tests/gtest/TestArena.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /gfx/tests/gtest/TestArena.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'gfx/tests/gtest/TestArena.cpp')
-rw-r--r--gfx/tests/gtest/TestArena.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/gfx/tests/gtest/TestArena.cpp b/gfx/tests/gtest/TestArena.cpp
new file mode 100644
index 000000000..4822b32f9
--- /dev/null
+++ b/gfx/tests/gtest/TestArena.cpp
@@ -0,0 +1,188 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "mozilla/gfx/IterableArena.h"
+#include <string>
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+#ifdef A
+#undef A
+#endif
+
+#ifdef B
+#undef B
+#endif
+
+// to avoid having symbols that collide easily like A and B in the global namespace
+namespace test_arena {
+
+class A;
+class B;
+
+class Base {
+public:
+ virtual ~Base() {}
+ virtual A* AsA() { return nullptr; }
+ virtual B* AsB() { return nullptr; }
+};
+
+static int sDtorItemA = 0;
+static int sDtorItemB = 0;
+
+class A : public Base {
+public:
+ virtual A* AsA() override { return this; }
+
+ explicit A(uint64_t val) : mVal(val) {}
+ ~A() { ++sDtorItemA; }
+
+ uint64_t mVal;
+};
+
+class B : public Base {
+public:
+ virtual B* AsB() override { return this; }
+
+ explicit B(const string& str) : mVal(str) {}
+ ~B() { ++sDtorItemB; }
+
+ std::string mVal;
+};
+
+struct BigStruct {
+ uint64_t mVal;
+ uint8_t data[120];
+
+ explicit BigStruct(uint64_t val) : mVal(val) {}
+};
+
+void TestArenaAlloc(IterableArena::ArenaType aType)
+{
+ sDtorItemA = 0;
+ sDtorItemB = 0;
+ IterableArena arena(aType, 256);
+
+ // An empty arena has no items to iterate over.
+ {
+ int iterations = 0;
+ arena.ForEach([&](void* item){
+ iterations++;
+ });
+ ASSERT_EQ(iterations, 0);
+ }
+
+ auto a1 = arena.Alloc<A>(42);
+ auto b1 = arena.Alloc<B>("Obladi oblada");
+ auto a2 = arena.Alloc<A>(1337);
+ auto b2 = arena.Alloc<B>("Yellow submarine");
+ auto b3 = arena.Alloc<B>("She's got a ticket to ride");
+
+ // Alloc returns a non-negative offset if the allocation succeeded.
+ ASSERT_TRUE(a1 >= 0);
+ ASSERT_TRUE(a2 >= 0);
+ ASSERT_TRUE(b1 >= 0);
+ ASSERT_TRUE(b2 >= 0);
+ ASSERT_TRUE(b3 >= 0);
+
+ ASSERT_TRUE(arena.GetStorage(a1) != nullptr);
+ ASSERT_TRUE(arena.GetStorage(a2) != nullptr);
+ ASSERT_TRUE(arena.GetStorage(b1) != nullptr);
+ ASSERT_TRUE(arena.GetStorage(b2) != nullptr);
+ ASSERT_TRUE(arena.GetStorage(b3) != nullptr);
+
+ ASSERT_TRUE(((Base*)arena.GetStorage(a1))->AsA() != nullptr);
+ ASSERT_TRUE(((Base*)arena.GetStorage(a2))->AsA() != nullptr);
+
+ ASSERT_TRUE(((Base*)arena.GetStorage(b1))->AsB() != nullptr);
+ ASSERT_TRUE(((Base*)arena.GetStorage(b2))->AsB() != nullptr);
+ ASSERT_TRUE(((Base*)arena.GetStorage(b3))->AsB() != nullptr);
+
+ ASSERT_EQ(((Base*)arena.GetStorage(a1))->AsA()->mVal, (uint64_t)42);
+ ASSERT_EQ(((Base*)arena.GetStorage(a2))->AsA()->mVal, (uint64_t)1337);
+
+ ASSERT_EQ(((Base*)arena.GetStorage(b1))->AsB()->mVal, std::string("Obladi oblada"));
+ ASSERT_EQ(((Base*)arena.GetStorage(b2))->AsB()->mVal, std::string("Yellow submarine"));
+ ASSERT_EQ(((Base*)arena.GetStorage(b3))->AsB()->mVal, std::string("She's got a ticket to ride"));
+
+ {
+ int iterations = 0;
+ arena.ForEach([&](void* item){
+ iterations++;
+ });
+ ASSERT_EQ(iterations, 5);
+ }
+
+ // Typically, running the destructors of the elements in the arena will is done
+ // manually like this:
+ arena.ForEach([](void* item){
+ ((Base*)item)->~Base();
+ });
+ arena.Clear();
+ ASSERT_EQ(sDtorItemA, 2);
+ ASSERT_EQ(sDtorItemB, 3);
+
+ // An empty arena has no items to iterate over (we just cleared it).
+ {
+ int iterations = 0;
+ arena.ForEach([&](void* item){
+ iterations++;
+ });
+ ASSERT_EQ(iterations, 0);
+ }
+
+}
+
+void TestArenaLimit(IterableArena::ArenaType aType, bool aShouldReachLimit)
+{
+ IterableArena arena(aType, 128);
+
+ // A non-growable arena should return a negative offset when running out
+ // of space, without crashing.
+ // We should not run out of space with a growable arena (unless the os is
+ // running out of memory but this isn't expected for this test).
+ bool reachedLimit = false;
+ for (int i = 0; i < 100; ++i) {
+ auto offset = arena.Alloc<A>(42);
+ if (offset < 0) {
+ reachedLimit = true;
+ break;
+ }
+ }
+ ASSERT_EQ(reachedLimit, aShouldReachLimit);
+}
+
+} // namespace test_arena
+
+using namespace test_arena;
+
+TEST(Moz2D, FixedArena) {
+ TestArenaAlloc(IterableArena::FIXED_SIZE);
+ TestArenaLimit(IterableArena::FIXED_SIZE, true);
+}
+
+TEST(Moz2D, GrowableArena) {
+ TestArenaAlloc(IterableArena::GROWABLE);
+ TestArenaLimit(IterableArena::GROWABLE, false);
+
+ IterableArena arena(IterableArena::GROWABLE, 16);
+ // sizeof(BigStruct) is more than twice the initial capacity, make sure that
+ // this doesn't blow everything up, since the arena doubles its storage size each
+ // time it grows (until it finds a size that fits).
+ auto a = arena.Alloc<BigStruct>(1);
+ auto b = arena.Alloc<BigStruct>(2);
+ auto c = arena.Alloc<BigStruct>(3);
+
+ // Offsets should also still point to the appropriate values after reallocation.
+ ASSERT_EQ(((BigStruct*)arena.GetStorage(a))->mVal, (uint64_t)1);
+ ASSERT_EQ(((BigStruct*)arena.GetStorage(b))->mVal, (uint64_t)2);
+ ASSERT_EQ(((BigStruct*)arena.GetStorage(c))->mVal, (uint64_t)3);
+
+ arena.Clear();
+}