Coverage Report

Created: 2018-09-25 14:53

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