Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_UNITTESTS_TEST_UTILS_H_
6 : #define V8_UNITTESTS_TEST_UTILS_H_
7 :
8 : #include <vector>
9 :
10 : #include "include/v8.h"
11 : #include "src/api-inl.h"
12 : #include "src/base/macros.h"
13 : #include "src/base/utils/random-number-generator.h"
14 : #include "src/handles.h"
15 : #include "src/objects-inl.h"
16 : #include "src/objects.h"
17 : #include "src/zone/accounting-allocator.h"
18 : #include "src/zone/zone.h"
19 : #include "testing/gtest-support.h"
20 :
21 : namespace v8 {
22 :
23 : class ArrayBufferAllocator;
24 :
25 : typedef std::map<std::string, int> CounterMap;
26 :
27 : // RAII-like Isolate instance wrapper.
28 : class IsolateWrapper final {
29 : public:
30 : // When enforce_pointer_compression is true the Isolate is created with
31 : // enabled pointer compression. When it's false then the Isolate is created
32 : // with the default pointer compression state for current build.
33 : explicit IsolateWrapper(CounterLookupCallback counter_lookup_callback,
34 : bool enforce_pointer_compression = false);
35 : ~IsolateWrapper();
36 :
37 : v8::Isolate* isolate() const { return isolate_; }
38 :
39 : private:
40 : v8::ArrayBuffer::Allocator* array_buffer_allocator_;
41 : v8::Isolate* isolate_;
42 :
43 : DISALLOW_COPY_AND_ASSIGN(IsolateWrapper);
44 : };
45 :
46 : class SharedIsolateHolder final {
47 : public:
48 801246 : static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); }
49 :
50 1267 : static void CreateIsolate() {
51 1267 : CHECK_NULL(isolate_wrapper_);
52 : isolate_wrapper_ =
53 25878 : new IsolateWrapper([](const char* name) -> int* { return nullptr; });
54 1267 : }
55 :
56 1267 : static void DeleteIsolate() {
57 1267 : CHECK_NOT_NULL(isolate_wrapper_);
58 1267 : delete isolate_wrapper_;
59 1267 : isolate_wrapper_ = nullptr;
60 1267 : }
61 :
62 : private:
63 : static v8::IsolateWrapper* isolate_wrapper_;
64 :
65 : DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateHolder);
66 : };
67 :
68 : class SharedIsolateAndCountersHolder final {
69 : public:
70 87 : static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); }
71 :
72 3 : static void CreateIsolate() {
73 3 : CHECK_NULL(counter_map_);
74 3 : CHECK_NULL(isolate_wrapper_);
75 6 : counter_map_ = new CounterMap();
76 3 : isolate_wrapper_ = new IsolateWrapper(LookupCounter);
77 3 : }
78 :
79 3 : static void DeleteIsolate() {
80 3 : CHECK_NOT_NULL(counter_map_);
81 3 : CHECK_NOT_NULL(isolate_wrapper_);
82 3 : delete isolate_wrapper_;
83 3 : isolate_wrapper_ = nullptr;
84 6 : delete counter_map_;
85 3 : counter_map_ = nullptr;
86 3 : }
87 :
88 : private:
89 : static int* LookupCounter(const char* name);
90 : static CounterMap* counter_map_;
91 : static v8::IsolateWrapper* isolate_wrapper_;
92 :
93 : DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateAndCountersHolder);
94 : };
95 :
96 : //
97 : // A set of mixins from which the test fixtures will be constructed.
98 : //
99 : template <typename TMixin>
100 1 : class WithPrivateIsolateMixin : public TMixin {
101 : public:
102 : explicit WithPrivateIsolateMixin(bool enforce_pointer_compression = false)
103 27 : : isolate_wrapper_([](const char* name) -> int* { return nullptr; },
104 1 : enforce_pointer_compression) {}
105 :
106 : v8::Isolate* v8_isolate() const { return isolate_wrapper_.isolate(); }
107 :
108 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
109 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
110 :
111 : private:
112 : v8::IsolateWrapper isolate_wrapper_;
113 :
114 : DISALLOW_COPY_AND_ASSIGN(WithPrivateIsolateMixin);
115 : };
116 :
117 : template <typename TMixin, typename TSharedIsolateHolder = SharedIsolateHolder>
118 1270 : class WithSharedIsolateMixin : public TMixin {
119 : public:
120 1270 : WithSharedIsolateMixin() = default;
121 :
122 : v8::Isolate* v8_isolate() const { return TSharedIsolateHolder::isolate(); }
123 :
124 : static void SetUpTestCase() {
125 : TMixin::SetUpTestCase();
126 1270 : TSharedIsolateHolder::CreateIsolate();
127 : }
128 :
129 : static void TearDownTestCase() {
130 1270 : TSharedIsolateHolder::DeleteIsolate();
131 : TMixin::TearDownTestCase();
132 : }
133 :
134 : private:
135 : DISALLOW_COPY_AND_ASSIGN(WithSharedIsolateMixin);
136 : };
137 :
138 : template <typename TMixin>
139 2 : class WithPointerCompressionIsolateMixin
140 : : public WithPrivateIsolateMixin<TMixin> {
141 : public:
142 1 : WithPointerCompressionIsolateMixin()
143 1 : : WithPrivateIsolateMixin<TMixin>(true) {}
144 :
145 : private:
146 : DISALLOW_COPY_AND_ASSIGN(WithPointerCompressionIsolateMixin);
147 : };
148 :
149 : template <typename TMixin>
150 2542 : class WithIsolateScopeMixin : public TMixin {
151 : public:
152 1271 : WithIsolateScopeMixin()
153 2542 : : isolate_scope_(v8_isolate()), handle_scope_(v8_isolate()) {}
154 :
155 : v8::Isolate* isolate() const { return v8_isolate(); }
156 : v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }
157 :
158 : v8::internal::Isolate* i_isolate() const {
159 : return reinterpret_cast<v8::internal::Isolate*>(v8_isolate());
160 : }
161 :
162 162 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
163 162 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
164 :
165 : private:
166 : v8::Isolate::Scope isolate_scope_;
167 : v8::HandleScope handle_scope_;
168 :
169 : DISALLOW_COPY_AND_ASSIGN(WithIsolateScopeMixin);
170 : };
171 :
172 : template <typename TMixin>
173 1694 : class WithContextMixin : public TMixin {
174 : public:
175 847 : WithContextMixin()
176 2541 : : context_(Context::New(v8_isolate())), context_scope_(context_) {}
177 :
178 : v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }
179 :
180 : const Local<Context>& context() const { return v8_context(); }
181 18 : const Local<Context>& v8_context() const { return context_; }
182 :
183 66 : Local<Value> RunJS(const char* source) {
184 66 : return RunJS(v8::String::NewFromUtf8(v8_isolate(), source,
185 : v8::NewStringType::kNormal)
186 66 : .ToLocalChecked());
187 : }
188 :
189 6 : Local<Value> RunJS(v8::String::ExternalOneByteStringResource* source) {
190 6 : return RunJS(
191 6 : v8::String::NewExternalOneByte(v8_isolate(), source).ToLocalChecked());
192 : }
193 :
194 16 : v8::Local<v8::String> NewString(const char* string) {
195 : return v8::String::NewFromUtf8(v8_isolate(), string,
196 : v8::NewStringType::kNormal)
197 32 : .ToLocalChecked();
198 : }
199 :
200 13 : void SetGlobalProperty(const char* name, v8::Local<v8::Value> value) {
201 52 : CHECK(v8_context()
202 : ->Global()
203 : ->Set(v8_context(), NewString(name), value)
204 : .FromJust());
205 13 : }
206 :
207 78 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
208 78 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
209 :
210 : private:
211 72 : Local<Value> RunJS(Local<String> source) {
212 72 : auto context = v8_isolate()->GetCurrentContext();
213 : Local<Script> script =
214 72 : v8::Script::Compile(context, source).ToLocalChecked();
215 144 : return script->Run(context).ToLocalChecked();
216 : }
217 :
218 : v8::Local<v8::Context> context_;
219 : v8::Context::Scope context_scope_;
220 :
221 : DISALLOW_COPY_AND_ASSIGN(WithContextMixin);
222 : };
223 :
224 : // Use v8::internal::TestWithIsolate if you are testing internals,
225 : // aka. directly work with Handles.
226 : using TestWithIsolate = //
227 : WithIsolateScopeMixin< //
228 : WithSharedIsolateMixin< //
229 : ::testing::Test>>;
230 :
231 : // Use v8::internal::TestWithNativeContext if you are testing internals,
232 : // aka. directly work with Handles.
233 : using TestWithContext = //
234 : WithContextMixin< //
235 : WithIsolateScopeMixin< //
236 : WithSharedIsolateMixin< //
237 : ::testing::Test>>>;
238 :
239 : using TestWithIsolateAndPointerCompression = //
240 : WithContextMixin< //
241 : WithIsolateScopeMixin< //
242 : WithPointerCompressionIsolateMixin< //
243 : ::testing::Test>>>;
244 :
245 : namespace internal {
246 :
247 : // Forward declarations.
248 : class Factory;
249 :
250 : template <typename TMixin>
251 1955 : class WithInternalIsolateMixin : public TMixin {
252 : public:
253 1141 : WithInternalIsolateMixin() = default;
254 :
255 : Factory* factory() const { return isolate()->factory(); }
256 : Isolate* isolate() const { return TMixin::i_isolate(); }
257 :
258 : Handle<NativeContext> native_context() const {
259 19 : return isolate()->native_context();
260 : }
261 :
262 : template <typename T = Object>
263 : Handle<T> RunJS(const char* source) {
264 : return Handle<T>::cast(RunJSInternal(source));
265 : }
266 :
267 : Handle<Object> RunJSInternal(const char* source) {
268 79 : return Utils::OpenHandle(*TMixin::RunJS(source));
269 : }
270 :
271 : template <typename T = Object>
272 : Handle<T> RunJS(::v8::String::ExternalOneByteStringResource* source) {
273 : return Handle<T>::cast(RunJSInternal(source));
274 : }
275 :
276 : Handle<Object> RunJSInternal(
277 : ::v8::String::ExternalOneByteStringResource* source) {
278 12 : return Utils::OpenHandle(*TMixin::RunJS(source));
279 : }
280 :
281 : base::RandomNumberGenerator* random_number_generator() const {
282 319 : return isolate()->random_number_generator();
283 : }
284 :
285 672 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
286 672 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
287 :
288 : private:
289 : DISALLOW_COPY_AND_ASSIGN(WithInternalIsolateMixin);
290 : };
291 :
292 : template <typename TMixin>
293 2763 : class WithZoneMixin : public TMixin {
294 : public:
295 4768 : WithZoneMixin() : zone_(&allocator_, ZONE_NAME) {}
296 :
297 265276 : Zone* zone() { return &zone_; }
298 :
299 2466 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
300 2466 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
301 :
302 : private:
303 : v8::internal::AccountingAllocator allocator_;
304 : Zone zone_;
305 :
306 : DISALLOW_COPY_AND_ASSIGN(WithZoneMixin);
307 : };
308 :
309 : using TestWithIsolate = //
310 : WithInternalIsolateMixin< //
311 : WithIsolateScopeMixin< //
312 : WithSharedIsolateMixin< //
313 : ::testing::Test>>>;
314 :
315 : using TestWithZone = WithZoneMixin<::testing::Test>;
316 :
317 : using TestWithIsolateAndZone = //
318 : WithInternalIsolateMixin< //
319 : WithIsolateScopeMixin< //
320 : WithSharedIsolateMixin< //
321 : WithZoneMixin< //
322 : ::testing::Test>>>>;
323 :
324 : using TestWithNativeContext = //
325 : WithInternalIsolateMixin< //
326 : WithContextMixin< //
327 : WithIsolateScopeMixin< //
328 : WithSharedIsolateMixin< //
329 : ::testing::Test>>>>;
330 :
331 : using TestWithNativeContextAndCounters = //
332 : WithInternalIsolateMixin< //
333 : WithContextMixin< //
334 : WithIsolateScopeMixin< //
335 : WithSharedIsolateMixin< //
336 : ::testing::Test, //
337 : SharedIsolateAndCountersHolder>>>>;
338 :
339 : using TestWithNativeContextAndZone = //
340 : WithZoneMixin< //
341 : WithInternalIsolateMixin< //
342 : WithContextMixin< //
343 : WithIsolateScopeMixin< //
344 : WithSharedIsolateMixin< //
345 : ::testing::Test>>>>>;
346 :
347 : class SaveFlags {
348 : public:
349 : SaveFlags();
350 : ~SaveFlags();
351 :
352 : private:
353 : #define FLAG_MODE_APPLY(ftype, ctype, nam, def, cmt) ctype SAVED_##nam;
354 : #include "src/flag-definitions.h" // NOLINT
355 : #undef FLAG_MODE_APPLY
356 :
357 : DISALLOW_COPY_AND_ASSIGN(SaveFlags);
358 : };
359 :
360 : // For GTest.
361 : inline void PrintTo(Object o, ::std::ostream* os) {
362 0 : *os << reinterpret_cast<void*>(o.ptr());
363 : }
364 : inline void PrintTo(Smi o, ::std::ostream* os) {
365 0 : *os << reinterpret_cast<void*>(o.ptr());
366 : }
367 :
368 : } // namespace internal
369 : } // namespace v8
370 :
371 : #endif // V8_UNITTESTS_TEST_UTILS_H_
|