source: webkit/trunk/JavaScriptCore/kjs/testkjs.cpp@ 30102

Last change on this file since 30102 was 29293, checked in by [email protected], 17 years ago

Turn testIsInteger assertions into compile-time asserts and move them into HashTraits.h where possible.

Reviewed by Maciej Stachowiak.

  • kjs/testkjs.cpp:
  • wtf/HashTraits.h:
  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * Copyright (C) 1999-2000 Harri Porten ([email protected])
4 * Copyright (C) 2004-2007 Apple Inc.
5 * Copyright (C) 2006 Bjoern Graf ([email protected])
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25
26#include "JSGlobalObject.h"
27#include "JSLock.h"
28#include "Parser.h"
29#include "collector.h"
30#include "interpreter.h"
31#include "nodes.h"
32#include "object.h"
33#include "protect.h"
34#include <math.h>
35#include <stdio.h>
36#include <string.h>
37#include <wtf/Assertions.h>
38#include <wtf/HashTraits.h>
39
40#if HAVE(SYS_TIME_H)
41#include <sys/time.h>
42#endif
43
44#if PLATFORM(WIN_OS)
45#include <crtdbg.h>
46#include <windows.h>
47#endif
48
49#if PLATFORM(QT)
50#include <QDateTime>
51#endif
52
53using namespace KJS;
54using namespace WTF;
55
56static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
57
58class StopWatch
59{
60public:
61 void start();
62 void stop();
63 long getElapsedMS(); // call stop() first
64
65private:
66#if PLATFORM(QT)
67 uint m_startTime;
68 uint m_stopTime;
69#elif PLATFORM(WIN_OS)
70 DWORD m_startTime;
71 DWORD m_stopTime;
72#else
73 // Windows does not have timeval, disabling this class for now (bug 7399)
74 timeval m_startTime;
75 timeval m_stopTime;
76#endif
77};
78
79void StopWatch::start()
80{
81#if PLATFORM(QT)
82 QDateTime t = QDateTime::currentDateTime();
83 m_startTime = t.toTime_t() * 1000 + t.time().msec();
84#elif PLATFORM(WIN_OS)
85 m_startTime = timeGetTime();
86#else
87 gettimeofday(&m_startTime, 0);
88#endif
89}
90
91void StopWatch::stop()
92{
93#if PLATFORM(QT)
94 QDateTime t = QDateTime::currentDateTime();
95 m_stopTime = t.toTime_t() * 1000 + t.time().msec();
96#elif PLATFORM(WIN_OS)
97 m_stopTime = timeGetTime();
98#else
99 gettimeofday(&m_stopTime, 0);
100#endif
101}
102
103long StopWatch::getElapsedMS()
104{
105#if PLATFORM(WIN_OS) || PLATFORM(QT)
106 return m_stopTime - m_startTime;
107#else
108 timeval elapsedTime;
109 timersub(&m_stopTime, &m_startTime, &elapsedTime);
110
111 return elapsedTime.tv_sec * 1000 + lroundf(elapsedTime.tv_usec / 1000.0f);
112#endif
113}
114
115class GlobalImp : public JSGlobalObject {
116public:
117 virtual UString className() const { return "global"; }
118};
119COMPILE_ASSERT(!IsInteger<GlobalImp>::value, WTF_IsInteger_GlobalImp_false);
120
121class TestFunctionImp : public JSObject {
122public:
123 enum TestFunctionType { Print, Debug, Quit, GC, Version, Run, Load };
124
125 TestFunctionImp(TestFunctionType i, int length);
126 virtual bool implementsCall() const { return true; }
127 virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List &args);
128
129private:
130 TestFunctionType m_type;
131};
132
133TestFunctionImp::TestFunctionImp(TestFunctionType i, int length)
134 : JSObject()
135 , m_type(i)
136{
137 putDirect(Identifier("length"), length, DontDelete | ReadOnly | DontEnum);
138}
139
140JSValue* TestFunctionImp::callAsFunction(ExecState* exec, JSObject*, const List &args)
141{
142 switch (m_type) {
143 case Print:
144 printf("%s\n", args[0]->toString(exec).UTF8String().c_str());
145 return jsUndefined();
146 case Debug:
147 fprintf(stderr, "--> %s\n", args[0]->toString(exec).UTF8String().c_str());
148 return jsUndefined();
149 case GC:
150 {
151 JSLock lock;
152 Collector::collect();
153 return jsUndefined();
154 }
155 case Version:
156 // We need this function for compatibility with the Mozilla JS tests but for now
157 // we don't actually do any version-specific handling
158 return jsUndefined();
159 case Run:
160 {
161 StopWatch stopWatch;
162 UString fileName = args[0]->toString(exec);
163 Vector<char> script;
164 if (!fillBufferWithContentsOfFile(fileName, script))
165 return throwError(exec, GeneralError, "Could not open file.");
166
167 stopWatch.start();
168 Interpreter::evaluate(exec->dynamicGlobalObject()->globalExec(), fileName, 0, script.data());
169 stopWatch.stop();
170
171 return jsNumber(stopWatch.getElapsedMS());
172 }
173 case Load:
174 {
175 UString fileName = args[0]->toString(exec);
176 Vector<char> script;
177 if (!fillBufferWithContentsOfFile(fileName, script))
178 return throwError(exec, GeneralError, "Could not open file.");
179
180 Interpreter::evaluate(exec->dynamicGlobalObject()->globalExec(), fileName, 0, script.data());
181
182 return jsUndefined();
183 }
184 case Quit:
185 exit(0);
186 default:
187 abort();
188 }
189 return 0;
190}
191
192// Use SEH for Release builds only to get rid of the crash report dialog
193// (luckily the same tests fail in Release and Debug builds so far). Need to
194// be in a separate main function because the kjsmain function requires object
195// unwinding.
196
197#if PLATFORM(WIN_OS) && !defined(_DEBUG)
198#define TRY __try {
199#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
200#else
201#define TRY
202#define EXCEPT(x)
203#endif
204
205int kjsmain(int argc, char** argv);
206
207int main(int argc, char** argv)
208{
209#if defined(_DEBUG) && PLATFORM(WIN_OS)
210 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
211 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
212 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
213 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
214 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
215 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
216#endif
217
218 int res = 0;
219 TRY
220 res = kjsmain(argc, argv);
221 EXCEPT(res = 3)
222 return res;
223}
224
225static GlobalImp* createGlobalObject()
226{
227 GlobalImp* global = new GlobalImp;
228
229 // add debug() function
230 global->put(global->globalExec(), "debug", new TestFunctionImp(TestFunctionImp::Debug, 1));
231 // add "print" for compatibility with the mozilla js shell
232 global->put(global->globalExec(), "print", new TestFunctionImp(TestFunctionImp::Print, 1));
233 // add "quit" for compatibility with the mozilla js shell
234 global->put(global->globalExec(), "quit", new TestFunctionImp(TestFunctionImp::Quit, 0));
235 // add "gc" for compatibility with the mozilla js shell
236 global->put(global->globalExec(), "gc", new TestFunctionImp(TestFunctionImp::GC, 0));
237 // add "version" for compatibility with the mozilla js shell
238 global->put(global->globalExec(), "version", new TestFunctionImp(TestFunctionImp::Version, 1));
239 global->put(global->globalExec(), "run", new TestFunctionImp(TestFunctionImp::Run, 1));
240 global->put(global->globalExec(), "load", new TestFunctionImp(TestFunctionImp::Load, 1));
241
242 Interpreter::setShouldPrintExceptions(true);
243 return global;
244}
245
246static bool prettyPrintScript(const UString& fileName, const Vector<char>& script)
247{
248 int errLine = 0;
249 UString errMsg;
250 UString scriptUString(script.data());
251 RefPtr<ProgramNode> programNode = parser().parse<ProgramNode>(fileName, 0, scriptUString.data(), scriptUString.size(), 0, &errLine, &errMsg);
252 if (!programNode) {
253 fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str());
254 return false;
255 }
256
257 printf("%s\n", programNode->toString().UTF8String().c_str());
258 return true;
259}
260
261static bool runWithScripts(const Vector<UString>& fileNames, bool prettyPrint)
262{
263 GlobalImp* globalObject = createGlobalObject();
264 Vector<char> script;
265
266 bool success = true;
267
268 for (size_t i = 0; i < fileNames.size(); i++) {
269 UString fileName = fileNames[i];
270
271 if (!fillBufferWithContentsOfFile(fileName, script))
272 return false; // fail early so we can catch missing files
273
274 if (prettyPrint)
275 prettyPrintScript(fileName, script);
276 else {
277 Completion completion = Interpreter::evaluate(globalObject->globalExec(), fileName, 0, script.data());
278 success = success && completion.complType() != Throw;
279 }
280 }
281 return success;
282}
283
284static void parseArguments(int argc, char** argv, Vector<UString>& fileNames, bool& prettyPrint)
285{
286 if (argc < 2) {
287 fprintf(stderr, "Usage: testkjs file1 [file2...]\n");
288 exit(-1);
289 }
290
291 for (int i = 1; i < argc; i++) {
292 const char* fileName = argv[i];
293 if (strcmp(fileName, "-f") == 0) // mozilla test driver script uses "-f" prefix for files
294 continue;
295 if (strcmp(fileName, "-p") == 0) {
296 prettyPrint = true;
297 continue;
298 }
299 fileNames.append(fileName);
300 }
301}
302
303int kjsmain(int argc, char** argv)
304{
305 JSLock lock;
306
307 bool prettyPrint = false;
308 Vector<UString> fileNames;
309 parseArguments(argc, argv, fileNames, prettyPrint);
310
311 bool success = runWithScripts(fileNames, prettyPrint);
312
313#ifndef NDEBUG
314 Collector::collect();
315#endif
316
317 return success ? 0 : 3;
318}
319
320static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
321{
322 FILE* f = fopen(fileName.UTF8String().c_str(), "r");
323 if (!f) {
324 fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().c_str());
325 return false;
326 }
327
328 size_t buffer_size = 0;
329 size_t buffer_capacity = 1024;
330
331 buffer.resize(buffer_capacity);
332
333 while (!feof(f) && !ferror(f)) {
334 buffer_size += fread(buffer.data() + buffer_size, 1, buffer_capacity - buffer_size, f);
335 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
336 buffer_capacity *= 2;
337 buffer.resize(buffer_capacity);
338 }
339 }
340 fclose(f);
341 buffer[buffer_size] = '\0';
342
343 return true;
344}
Note: See TracBrowser for help on using the repository browser.