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(int num)
     91       : Thread("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,
    102                     SECOND_PART,
    103                     THIRD_PART,
    104                     FOURTH_PART,
    105                     LAST_PART = FOURTH_PART };
    106 
    107   static void SetUp(PartOfTest part);
    108   static void RunAllTests();
    109   static void TearDown();
    110   // This method switches threads if we are running the Threading test.
    111   // Otherwise it does nothing.
    112   static void Fuzz();
    113 
    114  private:
    115   static bool fuzzing_;
    116   static int tests_being_run_;
    117   static int current_;
    118   static int active_tests_;
    119   static bool NextThread();
    120   int test_number_;
    121   v8::internal::Semaphore* gate_;
    122   bool active_;
    123   void ContextSwitch();
    124   static int GetNextTestNumber();
    125   static v8::internal::Semaphore* all_tests_done_;
    126 };
    127 
    128 
    129 #define THREADED_TEST(Name)                                          \
    130   static void Test##Name();                                          \
    131   RegisterThreadedTest register_##Name(Test##Name, #Name);           \
    132   /* */ TEST(Name)
    133 
    134 
    135 class RegisterThreadedTest {
    136  public:
    137   explicit RegisterThreadedTest(CcTest::TestFunction* callback,
    138                                 const char* name)
    139       : fuzzer_(NULL), callback_(callback), name_(name) {
    140     prev_ = first_;
    141     first_ = this;
    142     count_++;
    143   }
    144   static int count() { return count_; }
    145   static RegisterThreadedTest* nth(int i) {
    146     CHECK(i < count());
    147     RegisterThreadedTest* current = first_;
    148     while (i > 0) {
    149       i--;
    150       current = current->prev_;
    151     }
    152     return current;
    153   }
    154   CcTest::TestFunction* callback() { return callback_; }
    155   ApiTestFuzzer* fuzzer_;
    156   const char* name() { return name_; }
    157 
    158  private:
    159   static RegisterThreadedTest* first_;
    160   static int count_;
    161   CcTest::TestFunction* callback_;
    162   RegisterThreadedTest* prev_;
    163   const char* name_;
    164 };
    165 
    166 
    167 // A LocalContext holds a reference to a v8::Context.
    168 class LocalContext {
    169  public:
    170   LocalContext(v8::ExtensionConfiguration* extensions = 0,
    171                v8::Handle<v8::ObjectTemplate> global_template =
    172                    v8::Handle<v8::ObjectTemplate>(),
    173                v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
    174     : context_(v8::Context::New(extensions, global_template, global_object)) {
    175     context_->Enter();
    176   }
    177 
    178   virtual ~LocalContext() {
    179     context_->Exit();
    180     context_.Dispose();
    181   }
    182 
    183   v8::Context* operator->() { return *context_; }
    184   v8::Context* operator*() { return *context_; }
    185   bool IsReady() { return !context_.IsEmpty(); }
    186 
    187   v8::Local<v8::Context> local() {
    188     return v8::Local<v8::Context>::New(context_);
    189   }
    190 
    191  private:
    192   v8::Persistent<v8::Context> context_;
    193 };
    194 
    195 
    196 static inline v8::Local<v8::Value> v8_num(double x) {
    197   return v8::Number::New(x);
    198 }
    199 
    200 
    201 static inline v8::Local<v8::String> v8_str(const char* x) {
    202   return v8::String::New(x);
    203 }
    204 
    205 
    206 static inline v8::Local<v8::Script> v8_compile(const char* x) {
    207   return v8::Script::Compile(v8_str(x));
    208 }
    209 
    210 
    211 // Helper function that compiles and runs the source.
    212 static inline v8::Local<v8::Value> CompileRun(const char* source) {
    213   return v8::Script::Compile(v8::String::New(source))->Run();
    214 }
    215 
    216 
    217 #endif  // ifndef CCTEST_H_
    218