tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestArena.cpp (5043B)


      1 /* vim:set ts=2 sw=2 sts=2 et: */
      2 /* Any copyright is dedicated to the Public Domain.
      3 * http://creativecommons.org/publicdomain/zero/1.0/
      4 */
      5 
      6 #include "gtest/gtest.h"
      7 #include "gmock/gmock.h"
      8 
      9 #include "mozilla/gfx/IterableArena.h"
     10 #include <string>
     11 
     12 using namespace mozilla;
     13 using namespace mozilla::gfx;
     14 
     15 #ifdef A
     16 #  undef A
     17 #endif
     18 
     19 #ifdef B
     20 #  undef B
     21 #endif
     22 
     23 // to avoid having symbols that collide easily like A and B in the global
     24 // namespace
     25 namespace test_arena {
     26 
     27 class A;
     28 class B;
     29 
     30 class Base {
     31 public:
     32  virtual ~Base() = default;
     33  virtual A* AsA() { return nullptr; }
     34  virtual B* AsB() { return nullptr; }
     35 };
     36 
     37 static int sDtorItemA = 0;
     38 static int sDtorItemB = 0;
     39 
     40 class A : public Base {
     41 public:
     42  virtual A* AsA() override { return this; }
     43 
     44  explicit A(uint64_t val) : mVal(val) {}
     45  ~A() { ++sDtorItemA; }
     46 
     47  uint64_t mVal;
     48 };
     49 
     50 class B : public Base {
     51 public:
     52  virtual B* AsB() override { return this; }
     53 
     54  explicit B(const std::string& str) : mVal(str) {}
     55  ~B() { ++sDtorItemB; }
     56 
     57  std::string mVal;
     58 };
     59 
     60 struct BigStruct {
     61  uint64_t mVal;
     62  uint8_t data[120];
     63 
     64  explicit BigStruct(uint64_t val) : mVal(val) {}
     65 };
     66 
     67 static void TestArenaAlloc(IterableArena::ArenaType aType) {
     68  sDtorItemA = 0;
     69  sDtorItemB = 0;
     70  IterableArena arena(aType, 256);
     71 
     72  // An empty arena has no items to iterate over.
     73  {
     74    int iterations = 0;
     75    arena.ForEach([&](void* item) { iterations++; });
     76    ASSERT_EQ(iterations, 0);
     77  }
     78 
     79  auto a1 = arena.Alloc<A>(42);
     80  auto b1 = arena.Alloc<B>("Obladi oblada");
     81  auto a2 = arena.Alloc<A>(1337);
     82  auto b2 = arena.Alloc<B>("Yellow submarine");
     83  auto b3 = arena.Alloc<B>("She's got a ticket to ride");
     84 
     85  // Alloc returns a non-negative offset if the allocation succeeded.
     86  ASSERT_TRUE(a1 >= 0);
     87  ASSERT_TRUE(a2 >= 0);
     88  ASSERT_TRUE(b1 >= 0);
     89  ASSERT_TRUE(b2 >= 0);
     90  ASSERT_TRUE(b3 >= 0);
     91 
     92  ASSERT_TRUE(arena.GetStorage(a1) != nullptr);
     93  ASSERT_TRUE(arena.GetStorage(a2) != nullptr);
     94  ASSERT_TRUE(arena.GetStorage(b1) != nullptr);
     95  ASSERT_TRUE(arena.GetStorage(b2) != nullptr);
     96  ASSERT_TRUE(arena.GetStorage(b3) != nullptr);
     97 
     98  ASSERT_TRUE(((Base*)arena.GetStorage(a1))->AsA() != nullptr);
     99  ASSERT_TRUE(((Base*)arena.GetStorage(a2))->AsA() != nullptr);
    100 
    101  ASSERT_TRUE(((Base*)arena.GetStorage(b1))->AsB() != nullptr);
    102  ASSERT_TRUE(((Base*)arena.GetStorage(b2))->AsB() != nullptr);
    103  ASSERT_TRUE(((Base*)arena.GetStorage(b3))->AsB() != nullptr);
    104 
    105  ASSERT_EQ(((Base*)arena.GetStorage(a1))->AsA()->mVal, (uint64_t)42);
    106  ASSERT_EQ(((Base*)arena.GetStorage(a2))->AsA()->mVal, (uint64_t)1337);
    107 
    108  ASSERT_EQ(((Base*)arena.GetStorage(b1))->AsB()->mVal,
    109            std::string("Obladi oblada"));
    110  ASSERT_EQ(((Base*)arena.GetStorage(b2))->AsB()->mVal,
    111            std::string("Yellow submarine"));
    112  ASSERT_EQ(((Base*)arena.GetStorage(b3))->AsB()->mVal,
    113            std::string("She's got a ticket to ride"));
    114 
    115  {
    116    int iterations = 0;
    117    arena.ForEach([&](void* item) { iterations++; });
    118    ASSERT_EQ(iterations, 5);
    119  }
    120 
    121  // Typically, running the destructors of the elements in the arena will is
    122  // done manually like this:
    123  arena.ForEach([](void* item) { ((Base*)item)->~Base(); });
    124  arena.Clear();
    125  ASSERT_EQ(sDtorItemA, 2);
    126  ASSERT_EQ(sDtorItemB, 3);
    127 
    128  // An empty arena has no items to iterate over (we just cleared it).
    129  {
    130    int iterations = 0;
    131    arena.ForEach([&](void* item) { iterations++; });
    132    ASSERT_EQ(iterations, 0);
    133  }
    134 }
    135 
    136 static void TestArenaLimit(IterableArena::ArenaType aType,
    137                           bool aShouldReachLimit) {
    138  IterableArena arena(aType, 128);
    139 
    140  // A non-growable arena should return a negative offset when running out
    141  // of space, without crashing.
    142  // We should not run out of space with a growable arena (unless the os is
    143  // running out of memory but this isn't expected for this test).
    144  bool reachedLimit = false;
    145  for (int i = 0; i < 100; ++i) {
    146    auto offset = arena.Alloc<A>(42);
    147    if (offset < 0) {
    148      reachedLimit = true;
    149      break;
    150    }
    151  }
    152  ASSERT_EQ(reachedLimit, aShouldReachLimit);
    153 }
    154 
    155 }  // namespace test_arena
    156 
    157 using namespace test_arena;
    158 
    159 TEST(Moz2D, FixedArena)
    160 {
    161  TestArenaAlloc(IterableArena::FIXED_SIZE);
    162  TestArenaLimit(IterableArena::FIXED_SIZE, true);
    163 }
    164 
    165 TEST(Moz2D, GrowableArena)
    166 {
    167  TestArenaAlloc(IterableArena::GROWABLE);
    168  TestArenaLimit(IterableArena::GROWABLE, false);
    169 
    170  IterableArena arena(IterableArena::GROWABLE, 16);
    171  // sizeof(BigStruct) is more than twice the initial capacity, make sure that
    172  // this doesn't blow everything up, since the arena doubles its storage size
    173  // each time it grows (until it finds a size that fits).
    174  auto a = arena.Alloc<BigStruct>(1);
    175  auto b = arena.Alloc<BigStruct>(2);
    176  auto c = arena.Alloc<BigStruct>(3);
    177 
    178  // Offsets should also still point to the appropriate values after
    179  // reallocation.
    180  ASSERT_EQ(((BigStruct*)arena.GetStorage(a))->mVal, (uint64_t)1);
    181  ASSERT_EQ(((BigStruct*)arena.GetStorage(b))->mVal, (uint64_t)2);
    182  ASSERT_EQ(((BigStruct*)arena.GetStorage(c))->mVal, (uint64_t)3);
    183 
    184  arena.Clear();
    185 }