test-utils.h 10.7 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_UNITTESTS_TEST_UTILS_H_
#define V8_UNITTESTS_TEST_UTILS_H_
7

8 9
#include <vector>

10
#include "include/v8.h"
11
#include "src/api/api-inl.h"
12
#include "src/base/macros.h"
13
#include "src/base/utils/random-number-generator.h"
14
#include "src/handles/handles.h"
15 16
#include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
17 18
#include "src/zone/accounting-allocator.h"
#include "src/zone/zone.h"
19 20 21 22
#include "testing/gtest-support.h"

namespace v8 {

23 24
class ArrayBufferAllocator;

25
using CounterMap = std::map<std::string, int>;
26

27 28
// RAII-like Isolate instance wrapper.
class IsolateWrapper final {
29
 public:
30 31 32
  // When enforce_pointer_compression is true the Isolate is created with
  // enabled pointer compression. When it's false then the Isolate is created
  // with the default pointer compression state for current build.
33 34
  explicit IsolateWrapper(CounterLookupCallback counter_lookup_callback,
                          bool enforce_pointer_compression = false);
35
  ~IsolateWrapper();
36

37
  v8::Isolate* isolate() const { return isolate_; }
38

39 40 41
 private:
  v8::ArrayBuffer::Allocator* array_buffer_allocator_;
  v8::Isolate* isolate_;
42

43 44 45 46 47 48 49 50 51
  DISALLOW_COPY_AND_ASSIGN(IsolateWrapper);
};

class SharedIsolateHolder final {
 public:
  static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); }

  static void CreateIsolate() {
    CHECK_NULL(isolate_wrapper_);
52 53
    isolate_wrapper_ =
        new IsolateWrapper([](const char* name) -> int* { return nullptr; });
54 55 56 57 58 59 60 61 62 63 64 65 66 67
  }

  static void DeleteIsolate() {
    CHECK_NOT_NULL(isolate_wrapper_);
    delete isolate_wrapper_;
    isolate_wrapper_ = nullptr;
  }

 private:
  static v8::IsolateWrapper* isolate_wrapper_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateHolder);
};

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
class SharedIsolateAndCountersHolder final {
 public:
  static v8::Isolate* isolate() { return isolate_wrapper_->isolate(); }

  static void CreateIsolate() {
    CHECK_NULL(counter_map_);
    CHECK_NULL(isolate_wrapper_);
    counter_map_ = new CounterMap();
    isolate_wrapper_ = new IsolateWrapper(LookupCounter);
  }

  static void DeleteIsolate() {
    CHECK_NOT_NULL(counter_map_);
    CHECK_NOT_NULL(isolate_wrapper_);
    delete isolate_wrapper_;
    isolate_wrapper_ = nullptr;
    delete counter_map_;
    counter_map_ = nullptr;
  }

 private:
  static int* LookupCounter(const char* name);
  static CounterMap* counter_map_;
  static v8::IsolateWrapper* isolate_wrapper_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(SharedIsolateAndCountersHolder);
};

96 97 98
//
// A set of mixins from which the test fixtures will be constructed.
//
99 100 101 102
template <typename TMixin>
class WithPrivateIsolateMixin : public TMixin {
 public:
  explicit WithPrivateIsolateMixin(bool enforce_pointer_compression = false)
103 104
      : isolate_wrapper_([](const char* name) -> int* { return nullptr; },
                         enforce_pointer_compression) {}
105 106 107 108 109 110 111 112 113 114 115 116

  v8::Isolate* v8_isolate() const { return isolate_wrapper_.isolate(); }

  static void SetUpTestCase() { TMixin::SetUpTestCase(); }
  static void TearDownTestCase() { TMixin::TearDownTestCase(); }

 private:
  v8::IsolateWrapper isolate_wrapper_;

  DISALLOW_COPY_AND_ASSIGN(WithPrivateIsolateMixin);
};

117
template <typename TMixin, typename TSharedIsolateHolder = SharedIsolateHolder>
118 119 120 121
class WithSharedIsolateMixin : public TMixin {
 public:
  WithSharedIsolateMixin() = default;

122
  v8::Isolate* v8_isolate() const { return TSharedIsolateHolder::isolate(); }
123 124 125

  static void SetUpTestCase() {
    TMixin::SetUpTestCase();
126
    TSharedIsolateHolder::CreateIsolate();
127 128 129
  }

  static void TearDownTestCase() {
130
    TSharedIsolateHolder::DeleteIsolate();
131
    TMixin::TearDownTestCase();
132 133
  }

134 135 136 137
 private:
  DISALLOW_COPY_AND_ASSIGN(WithSharedIsolateMixin);
};

138 139 140 141 142 143 144 145 146 147 148
template <typename TMixin>
class WithPointerCompressionIsolateMixin
    : public WithPrivateIsolateMixin<TMixin> {
 public:
  WithPointerCompressionIsolateMixin()
      : WithPrivateIsolateMixin<TMixin>(true) {}

 private:
  DISALLOW_COPY_AND_ASSIGN(WithPointerCompressionIsolateMixin);
};

149 150 151 152 153 154 155 156 157 158 159 160
template <typename TMixin>
class WithIsolateScopeMixin : public TMixin {
 public:
  WithIsolateScopeMixin()
      : isolate_scope_(v8_isolate()), handle_scope_(v8_isolate()) {}

  v8::Isolate* isolate() const { return v8_isolate(); }
  v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }

  v8::internal::Isolate* i_isolate() const {
    return reinterpret_cast<v8::internal::Isolate*>(v8_isolate());
  }
161

162 163
  static void SetUpTestCase() { TMixin::SetUpTestCase(); }
  static void TearDownTestCase() { TMixin::TearDownTestCase(); }
164 165

 private:
166 167
  v8::Isolate::Scope isolate_scope_;
  v8::HandleScope handle_scope_;
168

169
  DISALLOW_COPY_AND_ASSIGN(WithIsolateScopeMixin);
170 171
};

172 173
template <typename TMixin>
class WithContextMixin : public TMixin {
174
 public:
175 176 177 178
  WithContextMixin()
      : context_(Context::New(v8_isolate())), context_scope_(context_) {}

  v8::Isolate* v8_isolate() const { return TMixin::v8_isolate(); }
179

180 181 182
  const Local<Context>& context() const { return v8_context(); }
  const Local<Context>& v8_context() const { return context_; }

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  Local<Value> RunJS(const char* source) {
    return RunJS(v8::String::NewFromUtf8(v8_isolate(), source,
                                         v8::NewStringType::kNormal)
                     .ToLocalChecked());
  }

  Local<Value> RunJS(v8::String::ExternalOneByteStringResource* source) {
    return RunJS(
        v8::String::NewExternalOneByte(v8_isolate(), source).ToLocalChecked());
  }

  v8::Local<v8::String> NewString(const char* string) {
    return v8::String::NewFromUtf8(v8_isolate(), string,
                                   v8::NewStringType::kNormal)
        .ToLocalChecked();
  }

  void SetGlobalProperty(const char* name, v8::Local<v8::Value> value) {
    CHECK(v8_context()
              ->Global()
              ->Set(v8_context(), NewString(name), value)
              .FromJust());
  }

  static void SetUpTestCase() { TMixin::SetUpTestCase(); }
  static void TearDownTestCase() { TMixin::TearDownTestCase(); }
209 210

 private:
211 212 213 214 215 216 217 218
  Local<Value> RunJS(Local<String> source) {
    auto context = v8_isolate()->GetCurrentContext();
    Local<Script> script =
        v8::Script::Compile(context, source).ToLocalChecked();
    return script->Run(context).ToLocalChecked();
  }

  v8::Local<v8::Context> context_;
219
  v8::Context::Scope context_scope_;
220

221
  DISALLOW_COPY_AND_ASSIGN(WithContextMixin);
222 223
};

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
// Use v8::internal::TestWithIsolate if you are testing internals,
// aka. directly work with Handles.
using TestWithIsolate =          //
    WithIsolateScopeMixin<       //
        WithSharedIsolateMixin<  //
            ::testing::Test>>;

// Use v8::internal::TestWithNativeContext if you are testing internals,
// aka. directly work with Handles.
using TestWithContext =              //
    WithContextMixin<                //
        WithIsolateScopeMixin<       //
            WithSharedIsolateMixin<  //
                ::testing::Test>>>;

239 240 241 242 243 244
using TestWithIsolateAndPointerCompression =     //
    WithContextMixin<                            //
        WithIsolateScopeMixin<                   //
            WithPointerCompressionIsolateMixin<  //
                ::testing::Test>>>;

245 246 247 248 249
namespace internal {

// Forward declarations.
class Factory;

250 251
template <typename TMixin>
class WithInternalIsolateMixin : public TMixin {
252
 public:
253 254 255 256 257
  WithInternalIsolateMixin() = default;

  Factory* factory() const { return isolate()->factory(); }
  Isolate* isolate() const { return TMixin::i_isolate(); }

258 259 260
  Handle<NativeContext> native_context() const {
    return isolate()->native_context();
  }
261

262 263
  template <typename T = Object>
  Handle<T> RunJS(const char* source) {
Marja Hölttä's avatar
Marja Hölttä committed
264
    return Handle<T>::cast(RunJSInternal(source));
265
  }
266 267 268 269 270

  Handle<Object> RunJSInternal(const char* source) {
    return Utils::OpenHandle(*TMixin::RunJS(source));
  }

271 272 273 274
  template <typename T = Object>
  Handle<T> RunJS(::v8::String::ExternalOneByteStringResource* source) {
    return Handle<T>::cast(RunJSInternal(source));
  }
275

276 277 278 279
  Handle<Object> RunJSInternal(
      ::v8::String::ExternalOneByteStringResource* source) {
    return Utils::OpenHandle(*TMixin::RunJS(source));
  }
280

281 282 283
  base::RandomNumberGenerator* random_number_generator() const {
    return isolate()->random_number_generator();
  }
284

285 286
  static void SetUpTestCase() { TMixin::SetUpTestCase(); }
  static void TearDownTestCase() { TMixin::TearDownTestCase(); }
287 288

 private:
289
  DISALLOW_COPY_AND_ASSIGN(WithInternalIsolateMixin);
290 291
};

292 293
template <typename TMixin>
class WithZoneMixin : public TMixin {
294
 public:
295
  WithZoneMixin() : zone_(&allocator_, ZONE_NAME) {}
296 297 298

  Zone* zone() { return &zone_; }

299 300 301
  static void SetUpTestCase() { TMixin::SetUpTestCase(); }
  static void TearDownTestCase() { TMixin::TearDownTestCase(); }

302
 private:
303
  v8::internal::AccountingAllocator allocator_;
304 305
  Zone zone_;

306
  DISALLOW_COPY_AND_ASSIGN(WithZoneMixin);
307 308
};

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
using TestWithIsolate =              //
    WithInternalIsolateMixin<        //
        WithIsolateScopeMixin<       //
            WithSharedIsolateMixin<  //
                ::testing::Test>>>;

using TestWithZone = WithZoneMixin<::testing::Test>;

using TestWithIsolateAndZone =       //
    WithInternalIsolateMixin<        //
        WithIsolateScopeMixin<       //
            WithSharedIsolateMixin<  //
                WithZoneMixin<       //
                    ::testing::Test>>>>;

using TestWithNativeContext =            //
    WithInternalIsolateMixin<            //
        WithContextMixin<                //
            WithIsolateScopeMixin<       //
                WithSharedIsolateMixin<  //
                    ::testing::Test>>>>;

331 332 333 334 335 336 337 338
using TestWithNativeContextAndCounters =  //
    WithInternalIsolateMixin<             //
        WithContextMixin<                 //
            WithIsolateScopeMixin<        //
                WithSharedIsolateMixin<   //
                    ::testing::Test,      //
                    SharedIsolateAndCountersHolder>>>>;

339 340 341 342 343 344 345
using TestWithNativeContextAndZone =         //
    WithZoneMixin<                           //
        WithInternalIsolateMixin<            //
            WithContextMixin<                //
                WithIsolateScopeMixin<       //
                    WithSharedIsolateMixin<  //
                        ::testing::Test>>>>>;
346

347 348 349 350 351 352
class SaveFlags {
 public:
  SaveFlags();
  ~SaveFlags();

 private:
353
#define FLAG_MODE_APPLY(ftype, ctype, nam, def, cmt) ctype SAVED_##nam;
354
#include "src/flags/flag-definitions.h"  // NOLINT
355
#undef FLAG_MODE_APPLY
356 357 358 359

  DISALLOW_COPY_AND_ASSIGN(SaveFlags);
};

360
// For GTest.
361
inline void PrintTo(Object o, ::std::ostream* os) {
362 363 364 365 366 367
  *os << reinterpret_cast<void*>(o.ptr());
}
inline void PrintTo(Smi o, ::std::ostream* os) {
  *os << reinterpret_cast<void*>(o.ptr());
}

368 369 370
}  // namespace internal
}  // namespace v8

371
#endif  // V8_UNITTESTS_TEST_UTILS_H_