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#include "include/v8.h"
29#include "test/cctest/cctest.h"
30
31#include "include/libplatform/libplatform.h"
32#include "src/debug/debug.h"
33#include "test/cctest/print-extension.h"
34#include "test/cctest/profiler-extension.h"
35#include "test/cctest/trace-extension.h"
36
37#if V8_OS_WIN
38#include <windows.h>  // NOLINT
39#if V8_CC_MSVC
40#include <crtdbg.h>
41#endif
42#endif
43
44enum InitializationState {kUnset, kUnintialized, kInitialized};
45static InitializationState initialization_state_  = kUnset;
46static bool disable_automatic_dispose_ = false;
47
48CcTest* CcTest::last_ = NULL;
49bool CcTest::initialize_called_ = false;
50v8::base::Atomic32 CcTest::isolate_used_ = 0;
51v8::ArrayBuffer::Allocator* CcTest::allocator_ = NULL;
52v8::Isolate* CcTest::isolate_ = NULL;
53
54CcTest::CcTest(TestFunction* callback, const char* file, const char* name,
55               bool enabled, bool initialize)
56    : callback_(callback),
57      name_(name),
58      enabled_(enabled),
59      initialize_(initialize),
60      prev_(last_) {
61  // Find the base name of this test (const_cast required on Windows).
62  char *basename = strrchr(const_cast<char *>(file), '/');
63  if (!basename) {
64    basename = strrchr(const_cast<char *>(file), '\\');
65  }
66  if (!basename) {
67    basename = v8::internal::StrDup(file);
68  } else {
69    basename = v8::internal::StrDup(basename + 1);
70  }
71  // Drop the extension, if there is one.
72  char *extension = strrchr(basename, '.');
73  if (extension) *extension = 0;
74  // Install this test in the list of tests
75  file_ = basename;
76  prev_ = last_;
77  last_ = this;
78}
79
80
81void CcTest::Run() {
82  if (!initialize_) {
83    CHECK(initialization_state_ != kInitialized);
84    initialization_state_ = kUnintialized;
85    CHECK(CcTest::isolate_ == NULL);
86  } else {
87    CHECK(initialization_state_ != kUnintialized);
88    initialization_state_ = kInitialized;
89    if (isolate_ == NULL) {
90      v8::Isolate::CreateParams create_params;
91      create_params.array_buffer_allocator = allocator_;
92      isolate_ = v8::Isolate::New(create_params);
93    }
94    isolate_->Enter();
95  }
96  callback_();
97  if (initialize_) {
98    if (v8::Locker::IsActive()) {
99      v8::Locker locker(isolate_);
100      EmptyMessageQueues(isolate_);
101    } else {
102      EmptyMessageQueues(isolate_);
103    }
104    isolate_->Exit();
105  }
106}
107
108
109v8::Local<v8::Context> CcTest::NewContext(CcTestExtensionFlags extensions,
110                                          v8::Isolate* isolate) {
111    const char* extension_names[kMaxExtensions];
112    int extension_count = 0;
113  #define CHECK_EXTENSION_FLAG(Name, Id) \
114    if (extensions.Contains(Name##_ID)) extension_names[extension_count++] = Id;
115    EXTENSION_LIST(CHECK_EXTENSION_FLAG)
116  #undef CHECK_EXTENSION_FLAG
117    v8::ExtensionConfiguration config(extension_count, extension_names);
118    v8::Local<v8::Context> context = v8::Context::New(isolate, &config);
119    CHECK(!context.IsEmpty());
120    return context;
121}
122
123
124void CcTest::DisableAutomaticDispose() {
125  CHECK_EQ(kUnintialized, initialization_state_);
126  disable_automatic_dispose_ = true;
127}
128
129
130static void PrintTestList(CcTest* current) {
131  if (current == NULL) return;
132  PrintTestList(current->prev());
133  printf("%s/%s\n", current->file(), current->name());
134}
135
136
137class CcTestArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
138  virtual void* Allocate(size_t length) {
139    void* data = AllocateUninitialized(length == 0 ? 1 : length);
140    return data == NULL ? data : memset(data, 0, length);
141  }
142  virtual void* AllocateUninitialized(size_t length) {
143    return malloc(length == 0 ? 1 : length);
144  }
145  virtual void Free(void* data, size_t length) { free(data); }
146  // TODO(dslomov): Remove when v8:2823 is fixed.
147  virtual void Free(void* data) { UNREACHABLE(); }
148};
149
150
151static void SuggestTestHarness(int tests) {
152  if (tests == 0) return;
153  printf("Running multiple tests in sequence is deprecated and may cause "
154         "bogus failure.  Consider using tools/run-tests.py instead.\n");
155}
156
157
158int main(int argc, char* argv[]) {
159#if V8_OS_WIN
160  UINT new_flags =
161      SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
162  UINT existing_flags = SetErrorMode(new_flags);
163  SetErrorMode(existing_flags | new_flags);
164#if V8_CC_MSVC
165  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
166  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
167  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
168  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
169  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
170  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
171  _set_error_mode(_OUT_TO_STDERR);
172#endif  // V8_CC_MSVC
173#endif  // V8_OS_WIN
174
175  // hack to print cctest specific flags
176  for (int i = 1; i < argc; i++) {
177    char* arg = argv[i];
178    if ((strcmp(arg, "--help") == 0) || (strcmp(arg, "-h") == 0)) {
179      printf("Usage: %s [--list] [[V8_FLAGS] CCTEST]\n", argv[0]);
180      printf("\n");
181      printf("Options:\n");
182      printf("  --list:   list all cctests\n");
183      printf("  CCTEST:   cctest identfier returned by --list\n");
184      printf("  D8_FLAGS: see d8 output below\n");
185      printf("\n\n");
186    }
187  }
188
189  v8::V8::InitializeICUDefaultLocation(argv[0]);
190  v8::Platform* platform = v8::platform::CreateDefaultPlatform();
191  v8::V8::InitializePlatform(platform);
192  v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
193  v8::V8::Initialize();
194  v8::V8::InitializeExternalStartupData(argv[0]);
195
196  CcTestArrayBufferAllocator array_buffer_allocator;
197  CcTest::set_array_buffer_allocator(&array_buffer_allocator);
198
199  i::PrintExtension print_extension;
200  v8::RegisterExtension(&print_extension);
201  i::ProfilerExtension profiler_extension;
202  v8::RegisterExtension(&profiler_extension);
203  i::TraceExtension trace_extension;
204  v8::RegisterExtension(&trace_extension);
205
206  int tests_run = 0;
207  bool print_run_count = true;
208  for (int i = 1; i < argc; i++) {
209    char* arg = argv[i];
210    if (strcmp(arg, "--list") == 0) {
211      PrintTestList(CcTest::last());
212      print_run_count = false;
213
214    } else {
215      char* arg_copy = v8::internal::StrDup(arg);
216      char* testname = strchr(arg_copy, '/');
217      if (testname) {
218        // Split the string in two by nulling the slash and then run
219        // exact matches.
220        *testname = 0;
221        char* file = arg_copy;
222        char* name = testname + 1;
223        CcTest* test = CcTest::last();
224        while (test != NULL) {
225          if (test->enabled()
226              && strcmp(test->file(), file) == 0
227              && strcmp(test->name(), name) == 0) {
228            SuggestTestHarness(tests_run++);
229            test->Run();
230          }
231          test = test->prev();
232        }
233
234      } else {
235        // Run all tests with the specified file or test name.
236        char* file_or_name = arg_copy;
237        CcTest* test = CcTest::last();
238        while (test != NULL) {
239          if (test->enabled()
240              && (strcmp(test->file(), file_or_name) == 0
241                  || strcmp(test->name(), file_or_name) == 0)) {
242            SuggestTestHarness(tests_run++);
243            test->Run();
244          }
245          test = test->prev();
246        }
247      }
248      v8::internal::DeleteArray<char>(arg_copy);
249    }
250  }
251  if (print_run_count && tests_run != 1)
252    printf("Ran %i tests.\n", tests_run);
253  CcTest::TearDown();
254  // TODO(svenpanne) See comment above.
255  // if (!disable_automatic_dispose_) v8::V8::Dispose();
256  v8::V8::ShutdownPlatform();
257  delete platform;
258  return 0;
259}
260
261RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
262int RegisterThreadedTest::count_ = 0;
263