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