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 : // RAII-like Isolate instance wrapper.
26 : class IsolateWrapper final {
27 : public:
28 : // When enforce_pointer_compression is true the Isolate is created with
29 : // enabled pointer compression. When it's false then the Isolate is created
30 : // with the default pointer compression state for current build.
31 : explicit IsolateWrapper(bool enforce_pointer_compression = false);
32 : ~IsolateWrapper();
33 :
34 : v8::Isolate* isolate() const { return isolate_; }
35 :
36 : private:
37 : v8::ArrayBuffer::Allocator* array_buffer_allocator_;
38 : v8::Isolate* isolate_;
39 :
40 : DISALLOW_COPY_AND_ASSIGN(IsolateWrapper);
41 : };
42 :
43 : class SharedIsolateHolder final {
44 : public:
45 800988 : static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); }
46 :
47 1246 : static void CreateIsolate() {
48 1246 : CHECK_NULL(isolate_wrapper_);
49 1246 : isolate_wrapper_ = new IsolateWrapper();
50 1246 : }
51 :
52 1246 : static void DeleteIsolate() {
53 1246 : CHECK_NOT_NULL(isolate_wrapper_);
54 1246 : delete isolate_wrapper_;
55 1246 : isolate_wrapper_ = nullptr;
56 1246 : }
57 :
58 : private:
59 : static v8::IsolateWrapper* isolate_wrapper_;
60 :
61 : DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateHolder);
62 : };
63 :
64 : //
65 : // A set of mixins from which the test fixtures will be constructed.
66 : //
67 : template <typename TMixin>
68 1 : class WithPrivateIsolateMixin : public TMixin {
69 : public:
70 : explicit WithPrivateIsolateMixin(bool enforce_pointer_compression = false)
71 1 : : isolate_wrapper_(enforce_pointer_compression) {}
72 :
73 7 : v8::Isolate* v8_isolate() const { return isolate_wrapper_.isolate(); }
74 :
75 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
76 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
77 :
78 : private:
79 : v8::IsolateWrapper isolate_wrapper_;
80 :
81 : DISALLOW_COPY_AND_ASSIGN(WithPrivateIsolateMixin);
82 : };
83 :
84 : template <typename TMixin>
85 1246 : class WithSharedIsolateMixin : public TMixin {
86 : public:
87 1246 : WithSharedIsolateMixin() = default;
88 :
89 : v8::Isolate* v8_isolate() const { return SharedIsolateHolder::isolate(); }
90 :
91 : static void SetUpTestCase() {
92 : TMixin::SetUpTestCase();
93 1246 : SharedIsolateHolder::CreateIsolate();
94 : }
95 :
96 : static void TearDownTestCase() {
97 1246 : SharedIsolateHolder::DeleteIsolate();
98 : TMixin::TearDownTestCase();
99 : }
100 :
101 : private:
102 : DISALLOW_COPY_AND_ASSIGN(WithSharedIsolateMixin);
103 : };
104 :
105 : template <typename TMixin>
106 1 : class WithPointerCompressionIsolateMixin
107 : : public WithPrivateIsolateMixin<TMixin> {
108 : public:
109 1 : WithPointerCompressionIsolateMixin()
110 1 : : WithPrivateIsolateMixin<TMixin>(true) {}
111 :
112 : private:
113 : DISALLOW_COPY_AND_ASSIGN(WithPointerCompressionIsolateMixin);
114 : };
115 :
116 : template <typename TMixin>
117 2494 : class WithIsolateScopeMixin : public TMixin {
118 : public:
119 1247 : WithIsolateScopeMixin()
120 2494 : : isolate_scope_(v8_isolate()), handle_scope_(v8_isolate()) {}
121 :
122 : v8::Isolate* isolate() const { return v8_isolate(); }
123 : v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }
124 :
125 : v8::internal::Isolate* i_isolate() const {
126 : return reinterpret_cast<v8::internal::Isolate*>(v8_isolate());
127 : }
128 :
129 162 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
130 162 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
131 :
132 : private:
133 : v8::Isolate::Scope isolate_scope_;
134 : v8::HandleScope handle_scope_;
135 :
136 : DISALLOW_COPY_AND_ASSIGN(WithIsolateScopeMixin);
137 : };
138 :
139 : template <typename TMixin>
140 1650 : class WithContextMixin : public TMixin {
141 : public:
142 825 : WithContextMixin()
143 2475 : : context_(Context::New(v8_isolate())), context_scope_(context_) {}
144 :
145 : v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }
146 :
147 : const Local<Context>& context() const { return v8_context(); }
148 : const Local<Context>& v8_context() const { return context_; }
149 :
150 39 : Local<Value> RunJS(const char* source) {
151 : return RunJS(v8::String::NewFromUtf8(v8_isolate(), source,
152 : v8::NewStringType::kNormal)
153 78 : .ToLocalChecked());
154 : }
155 :
156 6 : Local<Value> RunJS(v8::String::ExternalOneByteStringResource* source) {
157 : return RunJS(
158 12 : v8::String::NewExternalOneByte(v8_isolate(), source).ToLocalChecked());
159 : }
160 :
161 4 : v8::Local<v8::String> NewString(const char* string) {
162 : return v8::String::NewFromUtf8(v8_isolate(), string,
163 : v8::NewStringType::kNormal)
164 8 : .ToLocalChecked();
165 : }
166 :
167 3 : void SetGlobalProperty(const char* name, v8::Local<v8::Value> value) {
168 15 : CHECK(v8_context()
169 : ->Global()
170 : ->Set(v8_context(), NewString(name), value)
171 : .FromJust());
172 3 : }
173 :
174 65 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
175 65 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
176 :
177 : private:
178 45 : Local<Value> RunJS(Local<String> source) {
179 45 : auto context = v8_isolate()->GetCurrentContext();
180 : Local<Script> script =
181 45 : v8::Script::Compile(context, source).ToLocalChecked();
182 90 : return script->Run(context).ToLocalChecked();
183 : }
184 :
185 : v8::Local<v8::Context> context_;
186 : v8::Context::Scope context_scope_;
187 :
188 : DISALLOW_COPY_AND_ASSIGN(WithContextMixin);
189 : };
190 :
191 : // Use v8::internal::TestWithIsolate if you are testing internals,
192 : // aka. directly work with Handles.
193 : using TestWithIsolate = //
194 : WithIsolateScopeMixin< //
195 : WithSharedIsolateMixin< //
196 : ::testing::Test>>;
197 :
198 : // Use v8::internal::TestWithNativeContext if you are testing internals,
199 : // aka. directly work with Handles.
200 : using TestWithContext = //
201 : WithContextMixin< //
202 : WithIsolateScopeMixin< //
203 : WithSharedIsolateMixin< //
204 : ::testing::Test>>>;
205 :
206 : using TestWithIsolateAndPointerCompression = //
207 : WithContextMixin< //
208 : WithIsolateScopeMixin< //
209 : WithPointerCompressionIsolateMixin< //
210 : ::testing::Test>>>;
211 :
212 : namespace internal {
213 :
214 : // Forward declarations.
215 : class Factory;
216 :
217 : template <typename TMixin>
218 1909 : class WithInternalIsolateMixin : public TMixin {
219 : public:
220 1117 : WithInternalIsolateMixin() = default;
221 :
222 : Factory* factory() const { return isolate()->factory(); }
223 : Isolate* isolate() const { return TMixin::i_isolate(); }
224 :
225 : Handle<NativeContext> native_context() const {
226 9 : return isolate()->native_context();
227 : }
228 :
229 : template <typename T = Object>
230 38 : Handle<T> RunJS(const char* source) {
231 38 : return Handle<T>::cast(RunJSInternal(source));
232 : }
233 :
234 : Handle<Object> RunJSInternal(const char* source) {
235 76 : return Utils::OpenHandle(*TMixin::RunJS(source));
236 : }
237 :
238 : template <typename T = Object>
239 6 : Handle<T> RunJS(::v8::String::ExternalOneByteStringResource* source) {
240 6 : return Handle<T>::cast(RunJSInternal(source));
241 : }
242 :
243 : Handle<Object> RunJSInternal(
244 : ::v8::String::ExternalOneByteStringResource* source) {
245 12 : return Utils::OpenHandle(*TMixin::RunJS(source));
246 : }
247 :
248 : base::RandomNumberGenerator* random_number_generator() const {
249 319 : return isolate()->random_number_generator();
250 : }
251 :
252 644 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
253 644 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
254 :
255 : private:
256 : DISALLOW_COPY_AND_ASSIGN(WithInternalIsolateMixin);
257 : };
258 :
259 : template <typename TMixin>
260 1982 : class WithZoneMixin : public TMixin {
261 : public:
262 2730 : WithZoneMixin() : zone_(&allocator_, ZONE_NAME) {}
263 :
264 : Zone* zone() { return &zone_; }
265 :
266 2435 : static void SetUpTestCase() { TMixin::SetUpTestCase(); }
267 2435 : static void TearDownTestCase() { TMixin::TearDownTestCase(); }
268 :
269 : private:
270 : v8::internal::AccountingAllocator allocator_;
271 : Zone zone_;
272 :
273 : DISALLOW_COPY_AND_ASSIGN(WithZoneMixin);
274 : };
275 :
276 : using TestWithIsolate = //
277 : WithInternalIsolateMixin< //
278 : WithIsolateScopeMixin< //
279 : WithSharedIsolateMixin< //
280 : ::testing::Test>>>;
281 :
282 : using TestWithZone = WithZoneMixin<::testing::Test>;
283 :
284 : using TestWithIsolateAndZone = //
285 : WithInternalIsolateMixin< //
286 : WithIsolateScopeMixin< //
287 : WithSharedIsolateMixin< //
288 : WithZoneMixin< //
289 : ::testing::Test>>>>;
290 :
291 : using TestWithNativeContext = //
292 : WithInternalIsolateMixin< //
293 : WithContextMixin< //
294 : WithIsolateScopeMixin< //
295 : WithSharedIsolateMixin< //
296 : ::testing::Test>>>>;
297 :
298 : using TestWithNativeContextAndZone = //
299 : WithZoneMixin< //
300 : WithInternalIsolateMixin< //
301 : WithContextMixin< //
302 : WithIsolateScopeMixin< //
303 : WithSharedIsolateMixin< //
304 : ::testing::Test>>>>>;
305 :
306 : class SaveFlags {
307 : public:
308 : SaveFlags();
309 : ~SaveFlags();
310 :
311 : private:
312 : std::vector<const char*>* non_default_flags_;
313 :
314 : DISALLOW_COPY_AND_ASSIGN(SaveFlags);
315 : };
316 :
317 : // For GTest.
318 : inline void PrintTo(Object o, ::std::ostream* os) {
319 0 : *os << reinterpret_cast<void*>(o.ptr());
320 : }
321 : inline void PrintTo(Smi o, ::std::ostream* os) {
322 0 : *os << reinterpret_cast<void*>(o.ptr());
323 : }
324 :
325 : } // namespace internal
326 : } // namespace v8
327 :
328 : #endif // V8_UNITTESTS_TEST_UTILS_H_
|