Home | History | Annotate | Download | only in cctest
      1 // Copyright 2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef CCTEST_H_
     29 #define CCTEST_H_
     30 
     31 #include "include/libplatform/libplatform.h"
     32 #include "src/isolate-inl.h"  // TODO(everyone): Make cctest IWYU.
     33 #include "src/objects-inl.h"  // TODO(everyone): Make cctest IWYU.
     34 #include "src/v8.h"
     35 
     36 #ifndef TEST
     37 #define TEST(Name)                                                      \
     38   static void Test##Name();                                             \
     39   CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, true); \
     40   static void Test##Name()
     41 #endif
     42 
     43 #ifndef UNINITIALIZED_TEST
     44 #define UNINITIALIZED_TEST(Name)                                         \
     45   static void Test##Name();                                              \
     46   CcTest register_test_##Name(Test##Name, __FILE__, #Name, true, false); \
     47   static void Test##Name()
     48 #endif
     49 
     50 #ifndef DISABLED_TEST
     51 #define DISABLED_TEST(Name)                                              \
     52   static void Test##Name();                                              \
     53   CcTest register_test_##Name(Test##Name, __FILE__, #Name, false, true); \
     54   static void Test##Name()
     55 #endif
     56 
     57 #define EXTENSION_LIST(V)                                                      \
     58   V(GC_EXTENSION,       "v8/gc")                                               \
     59   V(PRINT_EXTENSION,    "v8/print")                                            \
     60   V(PROFILER_EXTENSION, "v8/profiler")                                         \
     61   V(TRACE_EXTENSION,    "v8/trace")
     62 
     63 #define DEFINE_EXTENSION_ID(Name, Ident) Name##_ID,
     64 enum CcTestExtensionIds {
     65   EXTENSION_LIST(DEFINE_EXTENSION_ID)
     66   kMaxExtensions
     67 };
     68 #undef DEFINE_EXTENSION_ID
     69 
     70 typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags;
     71 #define DEFINE_EXTENSION_FLAG(Name, Ident)                               \
     72   static const CcTestExtensionFlags Name(1 << Name##_ID);
     73   static const CcTestExtensionFlags NO_EXTENSIONS(0);
     74   static const CcTestExtensionFlags ALL_EXTENSIONS((1 << kMaxExtensions) - 1);
     75   EXTENSION_LIST(DEFINE_EXTENSION_FLAG)
     76 #undef DEFINE_EXTENSION_FLAG
     77 
     78 
     79 class CcTest {
     80  public:
     81   typedef void (TestFunction)();
     82   CcTest(TestFunction* callback, const char* file, const char* name,
     83          bool enabled, bool initialize);
     84   ~CcTest() { i::DeleteArray(file_); }
     85   void Run();
     86   static CcTest* last() { return last_; }
     87   CcTest* prev() { return prev_; }
     88   const char* file() { return file_; }
     89   const char* name() { return name_; }
     90   bool enabled() { return enabled_; }
     91 
     92   static v8::Isolate* isolate() {
     93     CHECK(isolate_ != NULL);
     94     v8::base::NoBarrier_Store(&isolate_used_, 1);
     95     return isolate_;
     96   }
     97 
     98   static i::Isolate* InitIsolateOnce() {
     99     if (!initialize_called_) InitializeVM();
    100     return i_isolate();
    101   }
    102 
    103   static i::Isolate* i_isolate() {
    104     return reinterpret_cast<i::Isolate*>(isolate());
    105   }
    106 
    107   static i::Heap* heap() {
    108     return i_isolate()->heap();
    109   }
    110 
    111   static v8::base::RandomNumberGenerator* random_number_generator() {
    112     return InitIsolateOnce()->random_number_generator();
    113   }
    114 
    115   static v8::Local<v8::Object> global() {
    116     return isolate()->GetCurrentContext()->Global();
    117   }
    118 
    119   static v8::ArrayBuffer::Allocator* array_buffer_allocator() {
    120     return allocator_;
    121   }
    122 
    123   static void set_array_buffer_allocator(
    124       v8::ArrayBuffer::Allocator* allocator) {
    125     allocator_ = allocator;
    126   }
    127 
    128   // TODO(dcarney): Remove.
    129   // This must be called first in a test.
    130   static void InitializeVM() {
    131     CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
    132     CHECK(!initialize_called_);
    133     initialize_called_ = true;
    134     v8::HandleScope handle_scope(CcTest::isolate());
    135     v8::Context::New(CcTest::isolate())->Enter();
    136   }
    137 
    138   // Only for UNINITIALIZED_TESTs
    139   static void DisableAutomaticDispose();
    140 
    141   // Helper function to configure a context.
    142   // Must be in a HandleScope.
    143   static v8::Local<v8::Context> NewContext(
    144       CcTestExtensionFlags extensions,
    145       v8::Isolate* isolate = CcTest::isolate());
    146 
    147   static void TearDown() {
    148     if (isolate_ != NULL) isolate_->Dispose();
    149   }
    150 
    151  private:
    152   friend int main(int argc, char** argv);
    153   TestFunction* callback_;
    154   const char* file_;
    155   const char* name_;
    156   bool enabled_;
    157   bool initialize_;
    158   CcTest* prev_;
    159   static CcTest* last_;
    160   static v8::ArrayBuffer::Allocator* allocator_;
    161   static v8::Isolate* isolate_;
    162   static bool initialize_called_;
    163   static v8::base::Atomic32 isolate_used_;
    164 };
    165 
    166 // Switches between all the Api tests using the threading support.
    167 // In order to get a surprising but repeatable pattern of thread
    168 // switching it has extra semaphores to control the order in which
    169 // the tests alternate, not relying solely on the big V8 lock.
    170 //
    171 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
    172 // callbacks.  This will have no effect when we are not running the
    173 // thread fuzzing test.  In the thread fuzzing test it will
    174 // pseudorandomly select a successor thread and switch execution
    175 // to that thread, suspending the current test.
    176 class ApiTestFuzzer: public v8::base::Thread {
    177  public:
    178   void CallTest();
    179 
    180   // The ApiTestFuzzer is also a Thread, so it has a Run method.
    181   virtual void Run();
    182 
    183   enum PartOfTest { FIRST_PART,
    184                     SECOND_PART,
    185                     THIRD_PART,
    186                     FOURTH_PART,
    187                     LAST_PART = FOURTH_PART };
    188 
    189   static void SetUp(PartOfTest part);
    190   static void RunAllTests();
    191   static void TearDown();
    192   // This method switches threads if we are running the Threading test.
    193   // Otherwise it does nothing.
    194   static void Fuzz();
    195 
    196  private:
    197   explicit ApiTestFuzzer(int num)
    198       : Thread(Options("ApiTestFuzzer")),
    199         test_number_(num),
    200         gate_(0),
    201         active_(true) {}
    202   ~ApiTestFuzzer() {}
    203 
    204   static bool fuzzing_;
    205   static int tests_being_run_;
    206   static int current_;
    207   static int active_tests_;
    208   static bool NextThread();
    209   int test_number_;
    210   v8::base::Semaphore gate_;
    211   bool active_;
    212   void ContextSwitch();
    213   static int GetNextTestNumber();
    214   static v8::base::Semaphore all_tests_done_;
    215 };
    216 
    217 
    218 #define THREADED_TEST(Name)                                          \
    219   static void Test##Name();                                          \
    220   RegisterThreadedTest register_##Name(Test##Name, #Name);           \
    221   /* */ TEST(Name)
    222 
    223 
    224 class RegisterThreadedTest {
    225  public:
    226   explicit RegisterThreadedTest(CcTest::TestFunction* callback,
    227                                 const char* name)
    228       : fuzzer_(NULL), callback_(callback), name_(name) {
    229     prev_ = first_;
    230     first_ = this;
    231     count_++;
    232   }
    233   static int count() { return count_; }
    234   static RegisterThreadedTest* nth(int i) {
    235     CHECK(i < count());
    236     RegisterThreadedTest* current = first_;
    237     while (i > 0) {
    238       i--;
    239       current = current->prev_;
    240     }
    241     return current;
    242   }
    243   CcTest::TestFunction* callback() { return callback_; }
    244   ApiTestFuzzer* fuzzer_;
    245   const char* name() { return name_; }
    246 
    247  private:
    248   static RegisterThreadedTest* first_;
    249   static int count_;
    250   CcTest::TestFunction* callback_;
    251   RegisterThreadedTest* prev_;
    252   const char* name_;
    253 };
    254 
    255 // A LocalContext holds a reference to a v8::Context.
    256 class LocalContext {
    257  public:
    258   LocalContext(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
    259                v8::Local<v8::ObjectTemplate> global_template =
    260                    v8::Local<v8::ObjectTemplate>(),
    261                v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
    262     Initialize(isolate, extensions, global_template, global_object);
    263   }
    264 
    265   LocalContext(v8::ExtensionConfiguration* extensions = 0,
    266                v8::Local<v8::ObjectTemplate> global_template =
    267                    v8::Local<v8::ObjectTemplate>(),
    268                v8::Local<v8::Value> global_object = v8::Local<v8::Value>()) {
    269     Initialize(CcTest::isolate(), extensions, global_template, global_object);
    270   }
    271 
    272   virtual ~LocalContext() {
    273     v8::HandleScope scope(isolate_);
    274     v8::Local<v8::Context>::New(isolate_, context_)->Exit();
    275     context_.Reset();
    276   }
    277 
    278   v8::Context* operator->() {
    279     return *reinterpret_cast<v8::Context**>(&context_);
    280   }
    281   v8::Context* operator*() { return operator->(); }
    282   bool IsReady() { return !context_.IsEmpty(); }
    283 
    284   v8::Local<v8::Context> local() {
    285     return v8::Local<v8::Context>::New(isolate_, context_);
    286   }
    287 
    288  private:
    289   void Initialize(v8::Isolate* isolate, v8::ExtensionConfiguration* extensions,
    290                   v8::Local<v8::ObjectTemplate> global_template,
    291                   v8::Local<v8::Value> global_object) {
    292      v8::HandleScope scope(isolate);
    293      v8::Local<v8::Context> context = v8::Context::New(isolate,
    294                                                        extensions,
    295                                                        global_template,
    296                                                        global_object);
    297      context_.Reset(isolate, context);
    298      context->Enter();
    299      // We can't do this later perhaps because of a fatal error.
    300      isolate_ = isolate;
    301   }
    302 
    303   v8::Persistent<v8::Context> context_;
    304   v8::Isolate* isolate_;
    305 };
    306 
    307 
    308 static inline uint16_t* AsciiToTwoByteString(const char* source) {
    309   int array_length = i::StrLength(source) + 1;
    310   uint16_t* converted = i::NewArray<uint16_t>(array_length);
    311   for (int i = 0; i < array_length; i++) converted[i] = source[i];
    312   return converted;
    313 }
    314 
    315 
    316 static inline v8::Local<v8::Value> v8_num(double x) {
    317   return v8::Number::New(v8::Isolate::GetCurrent(), x);
    318 }
    319 
    320 
    321 static inline v8::Local<v8::String> v8_str(const char* x) {
    322   return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
    323                                  v8::NewStringType::kNormal)
    324       .ToLocalChecked();
    325 }
    326 
    327 
    328 static inline v8::Local<v8::String> v8_str(v8::Isolate* isolate,
    329                                            const char* x) {
    330   return v8::String::NewFromUtf8(isolate, x, v8::NewStringType::kNormal)
    331       .ToLocalChecked();
    332 }
    333 
    334 
    335 static inline v8::Local<v8::Symbol> v8_symbol(const char* name) {
    336   return v8::Symbol::New(v8::Isolate::GetCurrent(), v8_str(name));
    337 }
    338 
    339 
    340 static inline v8::Local<v8::Script> v8_compile(v8::Local<v8::String> x) {
    341   v8::Local<v8::Script> result;
    342   if (v8::Script::Compile(v8::Isolate::GetCurrent()->GetCurrentContext(), x)
    343           .ToLocal(&result)) {
    344     return result;
    345   }
    346   return v8::Local<v8::Script>();
    347 }
    348 
    349 
    350 static inline v8::Local<v8::Script> v8_compile(const char* x) {
    351   return v8_compile(v8_str(x));
    352 }
    353 
    354 
    355 static inline int32_t v8_run_int32value(v8::Local<v8::Script> script) {
    356   v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
    357   return script->Run(context).ToLocalChecked()->Int32Value(context).FromJust();
    358 }
    359 
    360 
    361 static inline v8::Local<v8::Script> CompileWithOrigin(
    362     v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
    363   v8::ScriptOrigin origin(origin_url);
    364   v8::ScriptCompiler::Source script_source(source, origin);
    365   return v8::ScriptCompiler::Compile(
    366              v8::Isolate::GetCurrent()->GetCurrentContext(), &script_source)
    367       .ToLocalChecked();
    368 }
    369 
    370 
    371 static inline v8::Local<v8::Script> CompileWithOrigin(
    372     v8::Local<v8::String> source, const char* origin_url) {
    373   return CompileWithOrigin(source, v8_str(origin_url));
    374 }
    375 
    376 
    377 static inline v8::Local<v8::Script> CompileWithOrigin(const char* source,
    378                                                       const char* origin_url) {
    379   return CompileWithOrigin(v8_str(source), v8_str(origin_url));
    380 }
    381 
    382 
    383 // Helper functions that compile and run the source.
    384 static inline v8::MaybeLocal<v8::Value> CompileRun(
    385     v8::Local<v8::Context> context, const char* source) {
    386   return v8::Script::Compile(context, v8_str(source))
    387       .ToLocalChecked()
    388       ->Run(context);
    389 }
    390 
    391 
    392 static inline v8::Local<v8::Value> CompileRunChecked(v8::Isolate* isolate,
    393                                                      const char* source) {
    394   v8::Local<v8::String> source_string =
    395       v8::String::NewFromUtf8(isolate, source, v8::NewStringType::kNormal)
    396           .ToLocalChecked();
    397   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    398   v8::Local<v8::Script> script =
    399       v8::Script::Compile(context, source_string).ToLocalChecked();
    400   return script->Run(context).ToLocalChecked();
    401 }
    402 
    403 
    404 static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
    405   v8::Local<v8::Value> result;
    406   if (v8_compile(source)
    407           ->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
    408           .ToLocal(&result)) {
    409     return result;
    410   }
    411   return v8::Local<v8::Value>();
    412 }
    413 
    414 
    415 // Helper functions that compile and run the source.
    416 static inline v8::Local<v8::Value> CompileRun(const char* source) {
    417   return CompileRun(v8_str(source));
    418 }
    419 
    420 
    421 static inline v8::Local<v8::Value> CompileRun(
    422     v8::Local<v8::Context> context, v8::ScriptCompiler::Source* script_source,
    423     v8::ScriptCompiler::CompileOptions options) {
    424   v8::Local<v8::Value> result;
    425   if (v8::ScriptCompiler::Compile(context, script_source, options)
    426           .ToLocalChecked()
    427           ->Run(context)
    428           .ToLocal(&result)) {
    429     return result;
    430   }
    431   return v8::Local<v8::Value>();
    432 }
    433 
    434 
    435 static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) {
    436   // Compile once just to get the preparse data, then compile the second time
    437   // using the data.
    438   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    439   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    440   v8::ScriptCompiler::Source script_source(v8_str(source));
    441   v8::ScriptCompiler::Compile(context, &script_source,
    442                               v8::ScriptCompiler::kProduceParserCache)
    443       .ToLocalChecked();
    444 
    445   // Check whether we received cached data, and if so use it.
    446   v8::ScriptCompiler::CompileOptions options =
    447       script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache
    448                                     : v8::ScriptCompiler::kNoCompileOptions;
    449 
    450   return CompileRun(context, &script_source, options);
    451 }
    452 
    453 
    454 // Helper functions that compile and run the source with given origin.
    455 static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
    456                                                         const char* origin_url,
    457                                                         int line_number,
    458                                                         int column_number) {
    459   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    460   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    461   v8::ScriptOrigin origin(v8_str(origin_url),
    462                           v8::Integer::New(isolate, line_number),
    463                           v8::Integer::New(isolate, column_number));
    464   v8::ScriptCompiler::Source script_source(v8_str(source), origin);
    465   return CompileRun(context, &script_source,
    466                     v8::ScriptCompiler::CompileOptions());
    467 }
    468 
    469 
    470 static inline v8::Local<v8::Value> CompileRunWithOrigin(
    471     v8::Local<v8::String> source, const char* origin_url) {
    472   v8::Isolate* isolate = v8::Isolate::GetCurrent();
    473   v8::Local<v8::Context> context = isolate->GetCurrentContext();
    474   v8::ScriptCompiler::Source script_source(
    475       source, v8::ScriptOrigin(v8_str(origin_url)));
    476   return CompileRun(context, &script_source,
    477                     v8::ScriptCompiler::CompileOptions());
    478 }
    479 
    480 
    481 static inline v8::Local<v8::Value> CompileRunWithOrigin(
    482     const char* source, const char* origin_url) {
    483   return CompileRunWithOrigin(v8_str(source), origin_url);
    484 }
    485 
    486 
    487 
    488 static inline void ExpectString(const char* code, const char* expected) {
    489   v8::Local<v8::Value> result = CompileRun(code);
    490   CHECK(result->IsString());
    491   v8::String::Utf8Value utf8(result);
    492   CHECK_EQ(0, strcmp(expected, *utf8));
    493 }
    494 
    495 
    496 static inline void ExpectInt32(const char* code, int expected) {
    497   v8::Local<v8::Value> result = CompileRun(code);
    498   CHECK(result->IsInt32());
    499   CHECK_EQ(expected,
    500            result->Int32Value(v8::Isolate::GetCurrent()->GetCurrentContext())
    501                .FromJust());
    502 }
    503 
    504 
    505 static inline void ExpectBoolean(const char* code, bool expected) {
    506   v8::Local<v8::Value> result = CompileRun(code);
    507   CHECK(result->IsBoolean());
    508   CHECK_EQ(expected,
    509            result->BooleanValue(v8::Isolate::GetCurrent()->GetCurrentContext())
    510                .FromJust());
    511 }
    512 
    513 
    514 static inline void ExpectTrue(const char* code) {
    515   ExpectBoolean(code, true);
    516 }
    517 
    518 
    519 static inline void ExpectFalse(const char* code) {
    520   ExpectBoolean(code, false);
    521 }
    522 
    523 
    524 static inline void ExpectObject(const char* code,
    525                                 v8::Local<v8::Value> expected) {
    526   v8::Local<v8::Value> result = CompileRun(code);
    527   CHECK(result->SameValue(expected));
    528 }
    529 
    530 
    531 static inline void ExpectUndefined(const char* code) {
    532   v8::Local<v8::Value> result = CompileRun(code);
    533   CHECK(result->IsUndefined());
    534 }
    535 
    536 
    537 static inline void ExpectNull(const char* code) {
    538   v8::Local<v8::Value> result = CompileRun(code);
    539   CHECK(result->IsNull());
    540 }
    541 
    542 
    543 static inline void CheckDoubleEquals(double expected, double actual) {
    544   const double kEpsilon = 1e-10;
    545   CHECK_LE(expected, actual + kEpsilon);
    546   CHECK_GE(expected, actual - kEpsilon);
    547 }
    548 
    549 
    550 static void DummyDebugEventListener(
    551     const v8::Debug::EventDetails& event_details) {}
    552 
    553 
    554 static inline void EnableDebugger(v8::Isolate* isolate) {
    555   v8::Debug::SetDebugEventListener(isolate, &DummyDebugEventListener);
    556 }
    557 
    558 
    559 static inline void DisableDebugger(v8::Isolate* isolate) {
    560   v8::Debug::SetDebugEventListener(isolate, nullptr);
    561 }
    562 
    563 
    564 static inline void EmptyMessageQueues(v8::Isolate* isolate) {
    565   while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(),
    566                                        isolate)) {
    567   }
    568 }
    569 
    570 
    571 class InitializedHandleScope {
    572  public:
    573   InitializedHandleScope()
    574       : main_isolate_(CcTest::InitIsolateOnce()),
    575         handle_scope_(main_isolate_) {}
    576 
    577   // Prefixing the below with main_ reduces a lot of naming clashes.
    578   i::Isolate* main_isolate() { return main_isolate_; }
    579 
    580  private:
    581   i::Isolate* main_isolate_;
    582   i::HandleScope handle_scope_;
    583 };
    584 
    585 
    586 class HandleAndZoneScope : public InitializedHandleScope {
    587  public:
    588   HandleAndZoneScope() : main_zone_(&allocator_) {}
    589 
    590   // Prefixing the below with main_ reduces a lot of naming clashes.
    591   i::Zone* main_zone() { return &main_zone_; }
    592 
    593  private:
    594   v8::base::AccountingAllocator allocator_;
    595   i::Zone main_zone_;
    596 };
    597 
    598 #endif  // ifndef CCTEST_H_
    599