2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include <wtf/CurrentTime.h>
25 #include "InitializeThreading.h"
26 #include "JSCInlines.h"
27 #include "JSGlobalObject.h"
32 #include <wtf/text/StringBuilder.h>
42 #if COMPILER(MSVC) && !OS(WINCE)
48 const int MaxLineLength
= 100 * 1024;
62 Vector
<String
> arguments
;
70 long getElapsedMS(); // call stop() first
77 void StopWatch::start()
79 m_startTime
= monotonicallyIncreasingTime();
82 void StopWatch::stop()
84 m_stopTime
= monotonicallyIncreasingTime();
87 long StopWatch::getElapsedMS()
89 return static_cast<long>((m_stopTime
- m_startTime
) * 1000);
102 Vector
<int, 32> expectVector
;
105 class GlobalObject
: public JSGlobalObject
{
107 GlobalObject(VM
&, Structure
*, const Vector
<String
>& arguments
);
110 typedef JSGlobalObject Base
;
112 static GlobalObject
* create(VM
& vm
, Structure
* structure
, const Vector
<String
>& arguments
)
114 GlobalObject
* globalObject
= new (NotNull
, allocateCell
<GlobalObject
>(vm
.heap
)) GlobalObject(vm
, structure
, arguments
);
115 vm
.heap
.addFinalizer(globalObject
, destroy
);
121 static const bool needsDestructor
= false;
123 static Structure
* createStructure(VM
& vm
, JSValue prototype
)
125 return Structure::create(vm
, 0, prototype
, TypeInfo(GlobalObjectType
, StructureFlags
), info());
129 void finishCreation(VM
& vm
, const Vector
<String
>& arguments
)
131 Base::finishCreation(vm
);
132 UNUSED_PARAM(arguments
);
136 const ClassInfo
GlobalObject::s_info
= { "global", &JSGlobalObject::s_info
, 0, ExecState::globalObjectTable
, CREATE_METHOD_TABLE(GlobalObject
) };
138 GlobalObject::GlobalObject(VM
& vm
, Structure
* structure
, const Vector
<String
>& arguments
)
139 : JSGlobalObject(vm
, structure
)
141 finishCreation(vm
, arguments
);
144 // Use SEH for Release builds only to get rid of the crash report dialog
145 // (luckily the same tests fail in Release and Debug builds so far). Need to
146 // be in a separate main function because the realMain function requires object
149 #if COMPILER(MSVC) && !defined(_DEBUG) && !OS(WINCE)
151 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
157 int realMain(int argc
, char** argv
);
159 int main(int argc
, char** argv
)
163 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
164 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
165 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
170 _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
);
171 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
172 _CrtSetReportFile(_CRT_ERROR
, _CRTDBG_FILE_STDERR
);
173 _CrtSetReportMode(_CRT_ERROR
, _CRTDBG_MODE_FILE
);
174 _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
);
175 _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
);
181 // Initialize JSC before getting VM.
182 JSC::initializeThreading();
184 // We can't use destructors in the following code because it uses Windows
185 // Structured Exception Handling
188 res
= realMain(argc
, argv
);
193 static bool testOneRegExp(VM
& vm
, RegExp
* regexp
, RegExpTest
* regExpTest
, bool verbose
, unsigned int lineNumber
)
196 Vector
<int, 32> outVector
;
197 outVector
.resize(regExpTest
->expectVector
.size());
198 int matchResult
= regexp
->match(vm
, regExpTest
->subject
, regExpTest
->offset
, outVector
);
200 if (matchResult
!= regExpTest
->result
) {
203 printf("Line %d: results mismatch - expected %d got %d\n", lineNumber
, regExpTest
->result
, matchResult
);
204 } else if (matchResult
!= -1) {
205 if (outVector
.size() != regExpTest
->expectVector
.size()) {
208 printf("Line %d: output vector size mismatch - expected %lu got %lu\n", lineNumber
, regExpTest
->expectVector
.size(), outVector
.size());
209 } else if (outVector
.size() % 2) {
212 printf("Line %d: output vector size is odd (%lu), should be even\n", lineNumber
, outVector
.size());
214 // Check in pairs since the first value of the pair could be -1 in which case the second doesn't matter.
215 size_t pairCount
= outVector
.size() / 2;
216 for (size_t i
= 0; i
< pairCount
; ++i
) {
217 size_t startIndex
= i
*2;
218 if (outVector
[startIndex
] != regExpTest
->expectVector
[startIndex
]) {
221 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber
, startIndex
, regExpTest
->expectVector
[startIndex
], outVector
[startIndex
]);
223 if ((i
> 0) && (regExpTest
->expectVector
[startIndex
] != -1) && (outVector
[startIndex
+1] != regExpTest
->expectVector
[startIndex
+1])) {
226 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber
, startIndex
+1, regExpTest
->expectVector
[startIndex
+1], outVector
[startIndex
+1]);
235 static int scanString(char* buffer
, int bufferLength
, StringBuilder
& builder
, char termChar
)
239 for (int i
= 0; i
< bufferLength
; ++i
) {
275 if ((i
+ 4) >= bufferLength
)
277 unsigned int charValue
;
278 if (sscanf(buffer
+i
+1, "%04x", &charValue
) != 1)
280 c
= static_cast<UChar
>(charValue
);
301 static RegExp
* parseRegExpLine(VM
& vm
, char* line
, int lineLength
)
303 StringBuilder pattern
;
308 int i
= scanString(line
+ 1, lineLength
- 1, pattern
, '/') + 1;
310 if ((i
>= lineLength
) || (line
[i
] != '/'))
315 return RegExp::create(vm
, pattern
.toString(), regExpFlags(line
+ i
));
318 static RegExpTest
* parseTestLine(char* line
, int lineLength
)
320 StringBuilder subjectString
;
322 if ((line
[0] != ' ') || (line
[1] != '"'))
325 int i
= scanString(line
+ 2, lineLength
- 2, subjectString
, '"') + 2;
327 if ((i
>= (lineLength
- 2)) || (line
[i
] != '"') || (line
[i
+1] != ',') || (line
[i
+2] != ' '))
334 if (sscanf(line
+ i
, "%d, ", &offset
) != 1)
337 while (line
[i
] && line
[i
] != ' ')
344 if (sscanf(line
+ i
, "%d, ", &matchResult
) != 1)
347 while (line
[i
] && line
[i
] != ' ')
352 if (line
[i
++] != '(')
357 RegExpTest
* result
= new RegExpTest();
359 result
->subject
= subjectString
.toString();
360 result
->offset
= offset
;
361 result
->result
= matchResult
;
363 while (line
[i
] && line
[i
] != ')') {
364 if (sscanf(line
+ i
, "%d, %d", &start
, &end
) != 2) {
369 result
->expectVector
.append(start
);
370 result
->expectVector
.append(end
);
372 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
375 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
380 if (!line
[i
] || (line
[i
] != ',')) {
390 static bool runFromFiles(GlobalObject
* globalObject
, const Vector
<String
>& files
, bool verbose
)
394 Vector
<char> scriptBuffer
;
396 unsigned failures
= 0;
397 char* lineBuffer
= new char[MaxLineLength
+ 1];
399 VM
& vm
= globalObject
->vm();
402 for (size_t i
= 0; i
< files
.size(); i
++) {
403 FILE* testCasesFile
= fopen(files
[i
].utf8().data(), "rb");
405 if (!testCasesFile
) {
406 printf("Unable to open test data file \"%s\"\n", files
[i
].utf8().data());
411 size_t lineLength
= 0;
413 unsigned int lineNumber
= 0;
415 while ((linePtr
= fgets(&lineBuffer
[0], MaxLineLength
, testCasesFile
))) {
416 lineLength
= strlen(linePtr
);
417 if (linePtr
[lineLength
- 1] == '\n') {
418 linePtr
[lineLength
- 1] = '\0';
423 if (linePtr
[0] == '#')
426 if (linePtr
[0] == '/') {
427 regexp
= parseRegExpLine(vm
, linePtr
, lineLength
);
428 } else if (linePtr
[0] == ' ') {
429 RegExpTest
* regExpTest
= parseTestLine(linePtr
, lineLength
);
431 if (regexp
&& regExpTest
) {
433 if (!testOneRegExp(vm
, regexp
, regExpTest
, verbose
, lineNumber
)) {
435 printf("Failure on line %u\n", lineNumber
);
444 fclose(testCasesFile
);
448 printf("%u tests run, %u failures\n", tests
, failures
);
450 printf("%u tests passed\n", tests
);
454 vm
.dumpSampleData(globalObject
->globalExec());
455 #if ENABLE(REGEXP_TRACING)
456 vm
.dumpRegExpTrace();
461 #define RUNNING_FROM_XCODE 0
463 static NO_RETURN
void printUsageStatement(bool help
= false)
465 fprintf(stderr
, "Usage: regexp_test [options] file\n");
466 fprintf(stderr
, " -h|--help Prints this help message\n");
467 fprintf(stderr
, " -v|--verbose Verbose output\n");
469 exit(help
? EXIT_SUCCESS
: EXIT_FAILURE
);
472 static void parseArguments(int argc
, char** argv
, CommandLine
& options
)
475 for (; i
< argc
; ++i
) {
476 const char* arg
= argv
[i
];
477 if (!strcmp(arg
, "-h") || !strcmp(arg
, "--help"))
478 printUsageStatement(true);
479 if (!strcmp(arg
, "-v") || !strcmp(arg
, "--verbose"))
480 options
.verbose
= true;
482 options
.files
.append(argv
[i
]);
485 for (; i
< argc
; ++i
)
486 options
.arguments
.append(argv
[i
]);
489 int realMain(int argc
, char** argv
)
491 VM
* vm
= VM::create(LargeHeap
).leakRef();
492 JSLockHolder
locker(vm
);
495 parseArguments(argc
, argv
, options
);
497 GlobalObject
* globalObject
= GlobalObject::create(*vm
, GlobalObject::createStructure(*vm
, jsNull()), options
.arguments
);
498 bool success
= runFromFiles(globalObject
, options
.files
, options
.verbose
);
500 return success
? 0 : 3;