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 "v8.h"
     32 
     33 #ifndef TEST
     34 #define TEST(Name)                                                       \
     35   static void Test##Name();                                              \
     36   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true);  \
     37   static void Test##Name()
     38 #endif
     39 
     40 #ifndef DEPENDENT_TEST
     41 #define DEPENDENT_TEST(Name, Dep)                                        \
     42   static void Test##Name();                                              \
     43   CcTest register_test_##Name(Test##Name, __FILE__, #Name, #Dep, true);  \
     44   static void Test##Name()
     45 #endif
     46 
     47 #ifndef DISABLED_TEST
     48 #define DISABLED_TEST(Name)                                              \
     49   static void Test##Name();                                              \
     50   CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, false); \
     51   static void Test##Name()
     52 #endif
     53 
     54 class CcTest {
     55  public:
     56   typedef void (TestFunction)();
     57   CcTest(TestFunction* callback, const char* file, const char* name,
     58          const char* dependency, bool enabled);
     59   void Run() { callback_(); }
     60   static int test_count();
     61   static CcTest* last() { return last_; }
     62   CcTest* prev() { return prev_; }
     63   const char* file() { return file_; }
     64   const char* name() { return name_; }
     65   const char* dependency() { return dependency_; }
     66   bool enabled() { return enabled_; }
     67  private:
     68   TestFunction* callback_;
     69   const char* file_;
     70   const char* name_;
     71   const char* dependency_;
     72   bool enabled_;
     73   static CcTest* last_;
     74   CcTest* prev_;
     75 };
     76 
     77 // Switches between all the Api tests using the threading support.
     78 // In order to get a surprising but repeatable pattern of thread
     79 // switching it has extra semaphores to control the order in which
     80 // the tests alternate, not relying solely on the big V8 lock.
     81 //
     82 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
     83 // callbacks.  This will have no effect when we are not running the
     84 // thread fuzzing test.  In the thread fuzzing test it will
     85 // pseudorandomly select a successor thread and switch execution
     86 // to that thread, suspending the current test.
     87 class ApiTestFuzzer: public v8::internal::Thread {
     88  public:
     89   void CallTest();
     90   explicit ApiTestFuzzer(v8::internal::Isolate* isolate, int num)
     91       : Thread(isolate, "ApiTestFuzzer"),
     92         test_number_(num),
     93         gate_(v8::internal::OS::CreateSemaphore(0)),
     94         active_(true) {
     95   }
     96   ~ApiTestFuzzer() { delete gate_; }
     97 
     98   // The ApiTestFuzzer is also a Thread, so it has a Run method.
     99   virtual void Run();
    100 
    101   enum PartOfTest { FIRST_PART, SECOND_PART };
    102 
    103   static void Setup(PartOfTest part);
    104   static void RunAllTests();
    105   static void TearDown();
    106   // This method switches threads if we are running the Threading test.
    107   // Otherwise it does nothing.
    108   static void Fuzz();
    109  private:
    110   static bool fuzzing_;
    111   static int tests_being_run_;
    112   static int current_;
    113   static int active_tests_;
    114   static bool NextThread();
    115   int test_number_;
    116   v8::internal::Semaphore* gate_;
    117   bool active_;
    118   void ContextSwitch();
    119   static int GetNextTestNumber();
    120   static v8::internal::Semaphore* all_tests_done_;
    121 };
    122 
    123 
    124 #define THREADED_TEST(Name)                                          \
    125   static void Test##Name();                                          \
    126   RegisterThreadedTest register_##Name(Test##Name, #Name);           \
    127   /* */ TEST(Name)
    128 
    129 
    130 class RegisterThreadedTest {
    131  public:
    132   explicit RegisterThreadedTest(CcTest::TestFunction* callback,
    133                                 const char* name)
    134       : fuzzer_(NULL), callback_(callback), name_(name) {
    135     prev_ = first_;
    136     first_ = this;
    137     count_++;
    138   }
    139   static int count() { return count_; }
    140   static RegisterThreadedTest* nth(int i) {
    141     CHECK(i < count());
    142     RegisterThreadedTest* current = first_;
    143     while (i > 0) {
    144       i--;
    145       current = current->prev_;
    146     }
    147     return current;
    148   }
    149   CcTest::TestFunction* callback() { return callback_; }
    150   ApiTestFuzzer* fuzzer_;
    151   const char* name() { return name_; }
    152 
    153  private:
    154   static RegisterThreadedTest* first_;
    155   static int count_;
    156   CcTest::TestFunction* callback_;
    157   RegisterThreadedTest* prev_;
    158   const char* name_;
    159 };
    160 
    161 
    162 // A LocalContext holds a reference to a v8::Context.
    163 class LocalContext {
    164  public:
    165   LocalContext(v8::ExtensionConfiguration* extensions = 0,
    166                v8::Handle<v8::ObjectTemplate> global_template =
    167                    v8::Handle<v8::ObjectTemplate>(),
    168                v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
    169     : context_(v8::Context::New(extensions, global_template, global_object)) {
    170     context_->Enter();
    171   }
    172 
    173   virtual ~LocalContext() {
    174     context_->Exit();
    175     context_.Dispose();
    176   }
    177 
    178   v8::Context* operator->() { return *context_; }
    179   v8::Context* operator*() { return *context_; }
    180   bool IsReady() { return !context_.IsEmpty(); }
    181 
    182   v8::Local<v8::Context> local() {
    183     return v8::Local<v8::Context>::New(context_);
    184   }
    185 
    186  private:
    187   v8::Persistent<v8::Context> context_;
    188 };
    189 
    190 
    191 static inline v8::Local<v8::Value> v8_num(double x) {
    192   return v8::Number::New(x);
    193 }
    194 
    195 
    196 static inline v8::Local<v8::String> v8_str(const char* x) {
    197   return v8::String::New(x);
    198 }
    199 
    200 
    201 static inline v8::Local<v8::Script> v8_compile(const char* x) {
    202   return v8::Script::Compile(v8_str(x));
    203 }
    204 
    205 
    206 // Helper function that compiles and runs the source.
    207 static inline v8::Local<v8::Value> CompileRun(const char* source) {
    208   return v8::Script::Compile(v8::String::New(source))->Run();
    209 }
    210 
    211 
    212 #endif  // ifndef CCTEST_H_
    213