test-utils.h 8.11 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
#include <memory>
9 10
#include <vector>

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

namespace v8 {

24 25
class ArrayBufferAllocator;

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

28 29 30 31 32 33 34 35 36 37 38
enum CountersMode { kNoCounters, kEnableCounters };

// When PointerCompressionMode is kEnforcePointerCompression, the Isolate is
// created with pointer compression force enabled. When it's
// kDefaultPointerCompression then the Isolate is created with the default
// pointer compression state for the current build.
enum PointerCompressionMode {
  kDefaultPointerCompression,
  kEnforcePointerCompression
};

39 40
// RAII-like Isolate instance wrapper.
class IsolateWrapper final {
41
 public:
42 43
  explicit IsolateWrapper(CountersMode counters_mode,
                          PointerCompressionMode pointer_compression_mode);
44
  ~IsolateWrapper();
45

46
  v8::Isolate* isolate() const { return isolate_; }
47

48
 private:
49 50
  std::unique_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator_;
  std::unique_ptr<CounterMap> counter_map_;
51
  v8::Isolate* isolate_;
52

53 54 55 56 57 58
  DISALLOW_COPY_AND_ASSIGN(IsolateWrapper);
};

//
// A set of mixins from which the test fixtures will be constructed.
//
59 60 61 62
template <typename TMixin, CountersMode kCountersMode = kNoCounters,
          PointerCompressionMode kPointerCompressionMode =
              kDefaultPointerCompression>
class WithIsolateMixin : public TMixin {
63
 public:
64 65
  WithIsolateMixin()
      : isolate_wrapper_(kCountersMode, kPointerCompressionMode) {}
66 67 68 69 70 71 72

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

 private:
  v8::IsolateWrapper isolate_wrapper_;
};

73 74 75
template <typename TMixin, CountersMode kCountersMode = kNoCounters>
using WithPointerCompressionIsolateMixin =
    WithIsolateMixin<TMixin, kCountersMode, kEnforcePointerCompression>;
76

77 78 79 80
template <typename TMixin>
class WithIsolateScopeMixin : public TMixin {
 public:
  WithIsolateScopeMixin()
81
      : isolate_scope_(this->v8_isolate()), handle_scope_(this->v8_isolate()) {}
82

83
  v8::Isolate* isolate() const { return this->v8_isolate(); }
84 85

  v8::internal::Isolate* i_isolate() const {
86
    return reinterpret_cast<v8::internal::Isolate*>(this->v8_isolate());
87
  }
88

89
 private:
90 91
  v8::Isolate::Scope isolate_scope_;
  v8::HandleScope handle_scope_;
92

93
  DISALLOW_COPY_AND_ASSIGN(WithIsolateScopeMixin);
94 95
};

96 97
template <typename TMixin>
class WithContextMixin : public TMixin {
98
 public:
99
  WithContextMixin()
100
      : context_(Context::New(this->v8_isolate())), context_scope_(context_) {}
101

102 103 104
  const Local<Context>& context() const { return v8_context(); }
  const Local<Context>& v8_context() const { return context_; }

105
  Local<Value> RunJS(const char* source) {
106
    return RunJS(
107
        v8::String::NewFromUtf8(this->v8_isolate(), source).ToLocalChecked());
108 109 110
  }

  Local<Value> RunJS(v8::String::ExternalOneByteStringResource* source) {
111 112
    return RunJS(v8::String::NewExternalOneByte(this->v8_isolate(), source)
                     .ToLocalChecked());
113 114 115
  }

  v8::Local<v8::String> NewString(const char* string) {
116
    return v8::String::NewFromUtf8(this->v8_isolate(), string).ToLocalChecked();
117 118 119 120 121 122 123 124 125
  }

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

126
 private:
127
  Local<Value> RunJS(Local<String> source) {
128
    auto context = this->v8_isolate()->GetCurrentContext();
129 130 131 132 133 134
    Local<Script> script =
        v8::Script::Compile(context, source).ToLocalChecked();
    return script->Run(context).ToLocalChecked();
  }

  v8::Local<v8::Context> context_;
135
  v8::Context::Scope context_scope_;
136

137
  DISALLOW_COPY_AND_ASSIGN(WithContextMixin);
138 139
};

140 141
// Use v8::internal::TestWithIsolate if you are testing internals,
// aka. directly work with Handles.
142 143 144
using TestWithIsolate =     //
    WithIsolateScopeMixin<  //
        WithIsolateMixin<   //
145 146 147 148
            ::testing::Test>>;

// Use v8::internal::TestWithNativeContext if you are testing internals,
// aka. directly work with Handles.
149 150 151 152
using TestWithContext =         //
    WithContextMixin<           //
        WithIsolateScopeMixin<  //
            WithIsolateMixin<   //
153 154
                ::testing::Test>>>;

155 156 157 158 159 160
using TestWithIsolateAndPointerCompression =     //
    WithContextMixin<                            //
        WithIsolateScopeMixin<                   //
            WithPointerCompressionIsolateMixin<  //
                ::testing::Test>>>;

161 162 163 164 165
namespace internal {

// Forward declarations.
class Factory;

166 167
template <typename TMixin>
class WithInternalIsolateMixin : public TMixin {
168
 public:
169 170 171 172 173
  WithInternalIsolateMixin() = default;

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

174 175 176
  Handle<NativeContext> native_context() const {
    return isolate()->native_context();
  }
177

178 179
  template <typename T = Object>
  Handle<T> RunJS(const char* source) {
Marja Hölttä's avatar
Marja Hölttä committed
180
    return Handle<T>::cast(RunJSInternal(source));
181
  }
182 183 184 185 186

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

187 188 189 190
  template <typename T = Object>
  Handle<T> RunJS(::v8::String::ExternalOneByteStringResource* source) {
    return Handle<T>::cast(RunJSInternal(source));
  }
191

192 193 194 195
  Handle<Object> RunJSInternal(
      ::v8::String::ExternalOneByteStringResource* source) {
    return Utils::OpenHandle(*TMixin::RunJS(source));
  }
196

197 198 199
  base::RandomNumberGenerator* random_number_generator() const {
    return isolate()->random_number_generator();
  }
200 201

 private:
202
  DISALLOW_COPY_AND_ASSIGN(WithInternalIsolateMixin);
203 204
};

205 206
template <typename TMixin>
class WithZoneMixin : public TMixin {
207
 public:
208 209
  explicit WithZoneMixin(bool support_zone_compression = false)
      : zone_(&allocator_, ZONE_NAME, support_zone_compression) {}
210 211 212 213

  Zone* zone() { return &zone_; }

 private:
214
  v8::internal::AccountingAllocator allocator_;
215 216
  Zone zone_;

217
  DISALLOW_COPY_AND_ASSIGN(WithZoneMixin);
218 219
};

220 221 222 223
using TestWithIsolate =         //
    WithInternalIsolateMixin<   //
        WithIsolateScopeMixin<  //
            WithIsolateMixin<   //
224 225 226 227
                ::testing::Test>>>;

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

228 229 230 231 232
using TestWithIsolateAndZone =      //
    WithZoneMixin<                  //
        WithInternalIsolateMixin<   //
            WithIsolateScopeMixin<  //
                WithIsolateMixin<   //
233 234
                    ::testing::Test>>>>;

235 236 237 238 239
using TestWithNativeContext =       //
    WithInternalIsolateMixin<       //
        WithContextMixin<           //
            WithIsolateScopeMixin<  //
                WithIsolateMixin<   //
240 241
                    ::testing::Test>>>>;

242 243 244 245
using TestWithNativeContextAndCounters =  //
    WithInternalIsolateMixin<             //
        WithContextMixin<                 //
            WithIsolateScopeMixin<        //
246 247 248 249 250 251 252 253 254
                WithIsolateMixin<         //
                    ::testing::Test, kEnableCounters>>>>;

using TestWithNativeContextAndZone =    //
    WithZoneMixin<                      //
        WithInternalIsolateMixin<       //
            WithContextMixin<           //
                WithIsolateScopeMixin<  //
                    WithIsolateMixin<   //
255
                        ::testing::Test>>>>>;
256

257 258 259 260 261 262
class SaveFlags {
 public:
  SaveFlags();
  ~SaveFlags();

 private:
263
#define FLAG_MODE_APPLY(ftype, ctype, nam, def, cmt) ctype SAVED_##nam;
264
#include "src/flags/flag-definitions.h"  // NOLINT
265
#undef FLAG_MODE_APPLY
266 267 268 269

  DISALLOW_COPY_AND_ASSIGN(SaveFlags);
};

270
// For GTest.
271
inline void PrintTo(Object o, ::std::ostream* os) {
272 273 274 275 276 277
  *os << reinterpret_cast<void*>(o.ptr());
}
inline void PrintTo(Smi o, ::std::ostream* os) {
  *os << reinterpret_cast<void*>(o.ptr());
}

278 279 280
}  // namespace internal
}  // namespace v8

281
#endif  // V8_UNITTESTS_TEST_UTILS_H_