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