Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
Line
Count
Source (jump to first uncovered line)
1
/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef mozilla_devtools_gtest_DevTools__
7
#define mozilla_devtools_gtest_DevTools__
8
9
#include "CoreDump.pb.h"
10
#include "jsapi.h"
11
#include "jspubtd.h"
12
#include "nsCRTGlue.h"
13
14
#include "gtest/gtest.h"
15
#include "gmock/gmock.h"
16
#include "mozilla/devtools/HeapSnapshot.h"
17
#include "mozilla/dom/ChromeUtils.h"
18
#include "mozilla/CycleCollectedJSContext.h"
19
#include "mozilla/Move.h"
20
#include "js/Principals.h"
21
#include "js/UbiNode.h"
22
#include "js/UniquePtr.h"
23
24
using namespace mozilla;
25
using namespace mozilla::devtools;
26
using namespace mozilla::dom;
27
using namespace testing;
28
29
// GTest fixture class that all of our tests derive from.
30
struct DevTools : public ::testing::Test {
31
  bool                       _initialized;
32
  JSContext*                 cx;
33
  JS::Compartment*           compartment;
34
  JS::Zone*                  zone;
35
  JS::PersistentRootedObject global;
36
37
  DevTools()
38
    : _initialized(false),
39
      cx(nullptr)
40
0
  { }
41
42
0
  virtual void SetUp() {
43
0
    MOZ_ASSERT(!_initialized);
44
0
45
0
    cx = getContext();
46
0
    if (!cx)
47
0
      return;
48
0
49
0
    global.init(cx, createGlobal());
50
0
    if (!global)
51
0
      return;
52
0
    JS::EnterRealm(cx, global);
53
0
54
0
    compartment = js::GetContextCompartment(cx);
55
0
    zone = js::GetContextZone(cx);
56
0
57
0
    _initialized = true;
58
0
  }
59
60
0
  JSContext* getContext() {
61
0
    return CycleCollectedJSContext::Get()->Context();
62
0
  }
63
64
0
  static void reportError(JSContext* cx, const char* message, JSErrorReport* report) {
65
0
    fprintf(stderr, "%s:%u:%s\n",
66
0
            report->filename ? report->filename : "<no filename>",
67
0
            (unsigned int) report->lineno,
68
0
            message);
69
0
  }
70
71
0
  static const JSClass* getGlobalClass() {
72
0
    static const JSClassOps globalClassOps = {
73
0
      nullptr, nullptr, nullptr, nullptr,
74
0
      nullptr, nullptr, nullptr, nullptr,
75
0
      nullptr, nullptr,
76
0
      JS_GlobalObjectTraceHook
77
0
    };
78
0
    static const JSClass globalClass = {
79
0
      "global", JSCLASS_GLOBAL_FLAGS,
80
0
      &globalClassOps
81
0
    };
82
0
    return &globalClass;
83
0
  }
84
85
  JSObject* createGlobal()
86
0
  {
87
0
    /* Create the global object. */
88
0
    JS::RootedObject newGlobal(cx);
89
0
    JS::RealmOptions options;
90
0
    newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
91
0
                                   JS::FireOnNewGlobalHook, options);
92
0
    if (!newGlobal)
93
0
      return nullptr;
94
0
95
0
    JSAutoRealm ar(cx, newGlobal);
96
0
97
0
    /* Populate the global object with the standard globals, like Object and
98
0
       Array. */
99
0
    if (!JS::InitRealmStandardClasses(cx))
100
0
      return nullptr;
101
0
102
0
    return newGlobal;
103
0
  }
104
105
0
  virtual void TearDown() {
106
0
    _initialized = false;
107
0
108
0
    if (global) {
109
0
      JS::LeaveRealm(cx, nullptr);
110
0
      global = nullptr;
111
0
    }
112
0
  }
113
};
114
115
116
// Helper to define a test and ensure that the fixture is initialized properly.
117
#define DEF_TEST(name, body)                    \
118
0
  TEST_F(DevTools, name) {                      \
119
0
    ASSERT_TRUE(_initialized);                  \
120
0
    body                                        \
121
0
  }
Unexecuted instantiation: DevTools_DeserializedNodeUbiNodes_Test::TestBody()
Unexecuted instantiation: DevTools_DeserializedStackFrameUbiStackFrames_Test::TestBody()
Unexecuted instantiation: DevTools_DoesCrossCompartmentBoundaries_Test::TestBody()
Unexecuted instantiation: DevTools_DoesntCrossCompartmentBoundaries_Test::TestBody()
Unexecuted instantiation: DevTools_SerializesEdgeNames_Test::TestBody()
Unexecuted instantiation: DevTools_SerializesEverythingInHeapGraphOnce_Test::TestBody()
Unexecuted instantiation: DevTools_SerializesTypeNames_Test::TestBody()
122
123
124
// Fake JS::ubi::Node implementation
125
class MOZ_STACK_CLASS FakeNode
126
{
127
public:
128
  JS::ubi::EdgeVector edges;
129
  JS::Compartment*    compartment;
130
  JS::Zone*           zone;
131
  size_t              size;
132
133
  explicit FakeNode()
134
    : edges(),
135
    compartment(nullptr),
136
    zone(nullptr),
137
    size(1)
138
0
  { }
139
};
140
141
namespace JS {
142
namespace ubi {
143
144
template<>
145
class Concrete<FakeNode> : public Base
146
{
147
0
  const char16_t* typeName() const override {
148
0
    return concreteTypeName;
149
0
  }
150
151
0
  js::UniquePtr<EdgeRange> edges(JSContext*, bool) const override {
152
0
    return js::UniquePtr<EdgeRange>(js_new<PreComputedEdgeRange>(get().edges));
153
0
  }
154
155
0
  Size size(mozilla::MallocSizeOf) const override {
156
0
    return get().size;
157
0
  }
158
159
0
  JS::Zone* zone() const override {
160
0
    return get().zone;
161
0
  }
162
163
0
  JS::Compartment* compartment() const override {
164
0
    return get().compartment;
165
0
  }
166
167
protected:
168
0
  explicit Concrete(FakeNode* ptr) : Base(ptr) { }
169
0
  FakeNode& get() const { return *static_cast<FakeNode*>(ptr); }
170
171
public:
172
  static const char16_t concreteTypeName[];
173
0
  static void construct(void* storage, FakeNode* ptr) {
174
0
    new (storage) Concrete(ptr);
175
0
  }
176
};
177
178
const char16_t Concrete<FakeNode>::concreteTypeName[] = u"FakeNode";
179
180
} // namespace ubi
181
} // namespace JS
182
183
0
void AddEdge(FakeNode& node, FakeNode& referent, const char16_t* edgeName = nullptr) {
184
0
  char16_t* ownedEdgeName = nullptr;
185
0
  if (edgeName) {
186
0
    ownedEdgeName = NS_xstrdup(edgeName);
187
0
  }
188
0
189
0
  JS::ubi::Edge edge(ownedEdgeName, &referent);
190
0
  ASSERT_TRUE(node.edges.append(std::move(edge)));
191
0
}
192
193
194
// Custom GMock Matchers
195
196
// Use the testing namespace to avoid static analysis failures in the gmock
197
// matcher classes that get generated from MATCHER_P macros.
198
namespace testing {
199
200
// Ensure that given node has the expected number of edges.
201
0
MATCHER_P2(EdgesLength, cx, expectedLength, "") {
202
0
  auto edges = arg.edges(cx);
203
0
  if (!edges)
204
0
    return false;
205
0
206
0
  int actualLength = 0;
207
0
  for ( ; !edges->empty(); edges->popFront())
208
0
    actualLength++;
209
0
210
0
  return Matcher<int>(Eq(expectedLength))
211
0
    .MatchAndExplain(actualLength, result_listener);
212
0
}
213
214
// Get the nth edge and match it with the given matcher.
215
0
MATCHER_P3(Edge, cx, n, matcher, "") {
216
0
  auto edges = arg.edges(cx);
217
0
  if (!edges)
218
0
    return false;
219
0
220
0
  int i = 0;
221
0
  for ( ; !edges->empty(); edges->popFront()) {
222
0
    if (i == n) {
223
0
      return Matcher<const JS::ubi::Edge&>(matcher)
224
0
        .MatchAndExplain(edges->front(), result_listener);
225
0
    }
226
0
227
0
    i++;
228
0
  }
229
0
230
0
  return false;
231
0
}
232
233
// Ensures that two char16_t* strings are equal.
234
0
MATCHER_P(UTF16StrEq, str, "") {
235
0
  return NS_strcmp(arg, str) == 0;
236
0
}
237
238
0
MATCHER_P(UniqueUTF16StrEq, str, "") {
239
0
  return NS_strcmp(arg.get(), str) == 0;
240
0
}
241
242
0
MATCHER(UniqueIsNull, "") {
243
0
  return arg.get() == nullptr;
244
0
}
245
246
// Matches an edge whose referent is the node with the given id.
247
0
MATCHER_P(EdgeTo, id, "") {
248
0
  return Matcher<const DeserializedEdge&>(Field(&DeserializedEdge::referent, id))
249
0
    .MatchAndExplain(arg, result_listener);
250
0
}
251
252
} // namespace testing
253
254
255
// A mock `Writer` class to be used with testing `WriteHeapGraph`.
256
class MockWriter : public CoreDumpWriter
257
{
258
public:
259
0
  virtual ~MockWriter() override { }
260
  MOCK_METHOD2(writeNode, bool(const JS::ubi::Node&, CoreDumpWriter::EdgePolicy));
261
  MOCK_METHOD1(writeMetadata, bool(uint64_t));
262
};
263
264
0
void ExpectWriteNode(MockWriter& writer, FakeNode& node) {
265
0
  EXPECT_CALL(writer, writeNode(Eq(JS::ubi::Node(&node)), _))
266
0
    .Times(1)
267
0
    .WillOnce(Return(true));
268
0
}
269
270
#endif // mozilla_devtools_gtest_DevTools__