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 "JSGlobalObject.h"
27 #include "UStringBuilder.h"
41 #if COMPILER(MSVC) && !OS(WINCE)
48 #include <QCoreApplication>
52 const int MaxLineLength
= 100 * 1024;
66 Vector
<UString
> arguments
;
67 Vector
<UString
> files
;
74 long getElapsedMS(); // call stop() first
81 void StopWatch::start()
83 m_startTime
= currentTime();
86 void StopWatch::stop()
88 m_stopTime
= currentTime();
91 long StopWatch::getElapsedMS()
93 return static_cast<long>((m_stopTime
- m_startTime
) * 1000);
106 Vector
<int, 32> expectVector
;
109 class GlobalObject
: public JSGlobalObject
{
111 GlobalObject(JSGlobalData
&, Structure
*, const Vector
<UString
>& arguments
);
114 typedef JSGlobalObject Base
;
116 static GlobalObject
* create(JSGlobalData
& globalData
, Structure
* structure
, const Vector
<UString
>& arguments
)
118 return new (NotNull
, allocateCell
<GlobalObject
>(globalData
.heap
)) GlobalObject(globalData
, structure
, arguments
);
121 static const ClassInfo s_info
;
123 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue prototype
)
125 return Structure::create(globalData
, 0, prototype
, TypeInfo(GlobalObjectType
, StructureFlags
), &s_info
);
129 void finishCreation(JSGlobalData
& globalData
, const Vector
<UString
>& arguments
)
131 Base::finishCreation(globalData
);
132 UNUSED_PARAM(arguments
);
136 COMPILE_ASSERT(!IsInteger
<GlobalObject
>::value
, WTF_IsInteger_GlobalObject_false
);
137 ASSERT_CLASS_FITS_IN_CELL(GlobalObject
);
139 const ClassInfo
GlobalObject::s_info
= { "global", &JSGlobalObject::s_info
, 0, ExecState::globalObjectTable
, CREATE_METHOD_TABLE(GlobalObject
) };
141 GlobalObject::GlobalObject(JSGlobalData
& globalData
, Structure
* structure
, const Vector
<UString
>& arguments
)
142 : JSGlobalObject(globalData
, structure
)
144 finishCreation(globalData
, arguments
);
147 // Use SEH for Release builds only to get rid of the crash report dialog
148 // (luckily the same tests fail in Release and Debug builds so far). Need to
149 // be in a separate main function because the realMain function requires object
152 #if COMPILER(MSVC) && !COMPILER(INTEL) && !defined(_DEBUG) && !OS(WINCE)
154 #define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
160 int realMain(int argc
, char** argv
);
162 int main(int argc
, char** argv
)
166 // Cygwin calls ::SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for
167 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the
168 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>.
173 _CrtSetReportFile(_CRT_WARN
, _CRTDBG_FILE_STDERR
);
174 _CrtSetReportMode(_CRT_WARN
, _CRTDBG_MODE_FILE
);
175 _CrtSetReportFile(_CRT_ERROR
, _CRTDBG_FILE_STDERR
);
176 _CrtSetReportMode(_CRT_ERROR
, _CRTDBG_MODE_FILE
);
177 _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
);
178 _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
);
185 QCoreApplication
app(argc
, argv
);
188 // Initialize JSC before getting JSGlobalData.
189 JSC::initializeThreading();
191 // We can't use destructors in the following code because it uses Windows
192 // Structured Exception Handling
195 res
= realMain(argc
, argv
);
200 static bool testOneRegExp(JSGlobalData
& globalData
, RegExp
* regexp
, RegExpTest
* regExpTest
, bool verbose
, unsigned int lineNumber
)
203 Vector
<int, 32> outVector
;
204 outVector
.resize(regExpTest
->expectVector
.size());
205 int matchResult
= regexp
->match(globalData
, regExpTest
->subject
, regExpTest
->offset
, outVector
);
207 if (matchResult
!= regExpTest
->result
) {
210 printf("Line %d: results mismatch - expected %d got %d\n", lineNumber
, regExpTest
->result
, matchResult
);
211 } else if (matchResult
!= -1) {
212 if (outVector
.size() != regExpTest
->expectVector
.size()) {
215 printf("Line %d: output vector size mismatch - expected %lu got %lu\n", lineNumber
, regExpTest
->expectVector
.size(), outVector
.size());
216 } else if (outVector
.size() % 2) {
219 printf("Line %d: output vector size is odd (%lu), should be even\n", lineNumber
, outVector
.size());
221 // Check in pairs since the first value of the pair could be -1 in which case the second doesn't matter.
222 size_t pairCount
= outVector
.size() / 2;
223 for (size_t i
= 0; i
< pairCount
; ++i
) {
224 size_t startIndex
= i
*2;
225 if (outVector
[startIndex
] != regExpTest
->expectVector
[startIndex
]) {
228 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber
, startIndex
, regExpTest
->expectVector
[startIndex
], outVector
[startIndex
]);
230 if ((i
> 0) && (regExpTest
->expectVector
[startIndex
] != -1) && (outVector
[startIndex
+1] != regExpTest
->expectVector
[startIndex
+1])) {
233 printf("Line %d: output vector mismatch at index %lu - expected %d got %d\n", lineNumber
, startIndex
+1, regExpTest
->expectVector
[startIndex
+1], outVector
[startIndex
+1]);
242 static int scanString(char* buffer
, int bufferLength
, UStringBuilder
& builder
, char termChar
)
246 for (int i
= 0; i
< bufferLength
; ++i
) {
282 if ((i
+ 4) >= bufferLength
)
284 unsigned int charValue
;
285 if (sscanf(buffer
+i
+1, "%04x", &charValue
) != 1)
287 c
= static_cast<UChar
>(charValue
);
308 static RegExp
* parseRegExpLine(JSGlobalData
& globalData
, char* line
, int lineLength
)
310 UStringBuilder pattern
;
315 int i
= scanString(line
+ 1, lineLength
- 1, pattern
, '/') + 1;
317 if ((i
>= lineLength
) || (line
[i
] != '/'))
322 return RegExp::create(globalData
, pattern
.toUString(), regExpFlags(line
+ i
));
325 static RegExpTest
* parseTestLine(char* line
, int lineLength
)
327 UStringBuilder subjectString
;
329 if ((line
[0] != ' ') || (line
[1] != '"'))
332 int i
= scanString(line
+ 2, lineLength
- 2, subjectString
, '"') + 2;
334 if ((i
>= (lineLength
- 2)) || (line
[i
] != '"') || (line
[i
+1] != ',') || (line
[i
+2] != ' '))
341 if (sscanf(line
+ i
, "%d, ", &offset
) != 1)
344 while (line
[i
] && line
[i
] != ' ')
351 if (sscanf(line
+ i
, "%d, ", &matchResult
) != 1)
354 while (line
[i
] && line
[i
] != ' ')
359 if (line
[i
++] != '(')
364 RegExpTest
* result
= new RegExpTest();
366 result
->subject
= subjectString
.toUString();
367 result
->offset
= offset
;
368 result
->result
= matchResult
;
370 while (line
[i
] && line
[i
] != ')') {
371 if (sscanf(line
+ i
, "%d, %d", &start
, &end
) != 2) {
376 result
->expectVector
.append(start
);
377 result
->expectVector
.append(end
);
379 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
382 while (line
[i
] && (line
[i
] != ',') && (line
[i
] != ')'))
387 if (!line
[i
] || (line
[i
] != ',')) {
397 static bool runFromFiles(GlobalObject
* globalObject
, const Vector
<UString
>& files
, bool verbose
)
401 Vector
<char> scriptBuffer
;
403 unsigned failures
= 0;
404 char* lineBuffer
= new char[MaxLineLength
+ 1];
406 JSGlobalData
& globalData
= globalObject
->globalData();
409 for (size_t i
= 0; i
< files
.size(); i
++) {
410 FILE* testCasesFile
= fopen(files
[i
].utf8().data(), "rb");
412 if (!testCasesFile
) {
413 printf("Unable to open test data file \"%s\"\n", files
[i
].utf8().data());
418 size_t lineLength
= 0;
420 unsigned int lineNumber
= 0;
422 while ((linePtr
= fgets(&lineBuffer
[0], MaxLineLength
, testCasesFile
))) {
423 lineLength
= strlen(linePtr
);
424 if (linePtr
[lineLength
- 1] == '\n') {
425 linePtr
[lineLength
- 1] = '\0';
430 if (linePtr
[0] == '#')
433 if (linePtr
[0] == '/') {
434 regexp
= parseRegExpLine(globalData
, linePtr
, lineLength
);
435 } else if (linePtr
[0] == ' ') {
436 RegExpTest
* regExpTest
= parseTestLine(linePtr
, lineLength
);
438 if (regexp
&& regExpTest
) {
440 if (!testOneRegExp(globalData
, regexp
, regExpTest
, verbose
, lineNumber
)) {
442 printf("Failure on line %u\n", lineNumber
);
451 fclose(testCasesFile
);
455 printf("%u tests run, %u failures\n", tests
, failures
);
457 printf("%u tests passed\n", tests
);
461 globalData
.dumpSampleData(globalObject
->globalExec());
462 #if ENABLE(REGEXP_TRACING)
463 globalData
.dumpRegExpTrace();
468 #define RUNNING_FROM_XCODE 0
470 static NO_RETURN
void printUsageStatement(bool help
= false)
472 fprintf(stderr
, "Usage: regexp_test [options] file\n");
473 fprintf(stderr
, " -h|--help Prints this help message\n");
474 fprintf(stderr
, " -v|--verbose Verbose output\n");
476 exit(help
? EXIT_SUCCESS
: EXIT_FAILURE
);
479 static void parseArguments(int argc
, char** argv
, CommandLine
& options
)
482 for (; i
< argc
; ++i
) {
483 const char* arg
= argv
[i
];
484 if (!strcmp(arg
, "-h") || !strcmp(arg
, "--help"))
485 printUsageStatement(true);
486 if (!strcmp(arg
, "-v") || !strcmp(arg
, "--verbose"))
487 options
.verbose
= true;
489 options
.files
.append(argv
[i
]);
492 for (; i
< argc
; ++i
)
493 options
.arguments
.append(argv
[i
]);
496 int realMain(int argc
, char** argv
)
498 RefPtr
<JSGlobalData
> globalData
= JSGlobalData::create(ThreadStackTypeLarge
, LargeHeap
);
499 JSLockHolder
lock(globalData
.get());
502 parseArguments(argc
, argv
, options
);
504 GlobalObject
* globalObject
= GlobalObject::create(*globalData
, GlobalObject::createStructure(*globalData
, jsNull()), options
.arguments
);
505 bool success
= runFromFiles(globalObject
, options
.files
, options
.verbose
);
507 return success
? 0 : 3;