From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- gfx/tests/gtest/TestArena.cpp | 188 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 gfx/tests/gtest/TestArena.cpp (limited to 'gfx/tests/gtest/TestArena.cpp') 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 + +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(42); + auto b1 = arena.Alloc("Obladi oblada"); + auto a2 = arena.Alloc(1337); + auto b2 = arena.Alloc("Yellow submarine"); + auto b3 = arena.Alloc("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(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(1); + auto b = arena.Alloc(2); + auto c = arena.Alloc(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(); +} -- cgit v1.2.3