001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1/GPL 2.0
003: *
004: * The contents of this file are subject to the Mozilla Public License Version
005: * 1.1 (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS" basis,
010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: * for the specific language governing rights and limitations under the
012: * License.
013: *
014: * The Original Code is the Java port of jsDriver.pl.
015: *
016: * The Initial Developer of the Original Code is
017: * David P. Caldwell.
018: * Portions created by David P. Caldwell are Copyright (C)
019: * 2007 David P. Caldwell. All Rights Reserved.
020: *
021: *
022: * Contributor(s):
023: * David P. Caldwell <inonit@inonit.com>
024: *
025: * Alternatively, the contents of this file may be used under the terms of
026: * the GNU General Public License Version 2 or later (the "GPL"), in which
027: * case the provisions of the GPL are applicable instead of those above. If
028: * you wish to allow use of your version of this file only under the terms of
029: * the GPL and not to allow others to use your version of this file under the
030: * MPL, indicate your decision by deleting the provisions above and replacing
031: * them with the notice and other provisions required by the GPL. If you do
032: * not delete the provisions above, a recipient may use your version of this
033: * file under either the MPL or the GPL.
034: *
035: * ***** END LICENSE BLOCK ***** */
036:
037: package org.mozilla.javascript.drivers;
038:
039: import org.mozilla.javascript.*;
040: import java.io.*;
041: import java.util.*;
042:
043: import org.mozilla.javascript.tools.shell.*;
044:
045: /**
046: * @version $Id: ShellTest.java,v 1.5 2007/10/11 19:44:10 szegedia%freemail.hu Exp $
047: */
048: class ShellTest {
049: static final FileFilter DIRECTORY_FILTER = new FileFilter() {
050: public boolean accept(File pathname) {
051: return pathname.isDirectory()
052: && !pathname.getName().equals("CVS");
053: }
054: };
055:
056: static final FileFilter TEST_FILTER = new FileFilter() {
057: public boolean accept(File pathname) {
058: return pathname.getName().endsWith(".js")
059: && !pathname.getName().equals("shell.js")
060: && !pathname.getName().equals("browser.js")
061: && !pathname.getName().equals("template.js");
062: }
063: };
064:
065: static String getStackTrace(Throwable t) {
066: ByteArrayOutputStream bytes = new ByteArrayOutputStream();
067: t.printStackTrace(new PrintStream(bytes));
068: return new String(bytes.toByteArray());
069: }
070:
071: private static void runFileIfExists(Context cx, Scriptable global,
072: File f) {
073: if (f.isFile()) {
074: Main.processFile(cx, global, f.getPath());
075: }
076: }
077:
078: private static class TestState {
079: boolean finished;
080: ErrorReporterWrapper errors;
081: int exitCode = 0;
082: }
083:
084: static abstract class Status {
085: private boolean negative;
086:
087: final void setNegative() {
088: this .negative = true;
089: }
090:
091: final boolean isNegative() {
092: return this .negative;
093: }
094:
095: final void hadErrors(JsError[] errors) {
096: if (!negative && errors.length > 0) {
097: failed("JavaScript errors:\n"
098: + JsError.toString(errors));
099: } else if (negative && errors.length == 0) {
100: failed("Should have produced runtime error.");
101: }
102: }
103:
104: abstract void running(File jsFile);
105:
106: abstract void failed(String s);
107:
108: abstract void threw(Throwable t);
109:
110: abstract void timedOut();
111:
112: abstract void exitCodesWere(int expected, int actual);
113:
114: abstract void outputWas(String s);
115:
116: static Status compose(final Status[] array) {
117: return new Status() {
118: void running(File file) {
119: for (int i = 0; i < array.length; i++) {
120: array[i].running(file);
121: }
122: }
123:
124: void threw(Throwable t) {
125: for (int i = 0; i < array.length; i++) {
126: array[i].threw(t);
127: }
128: }
129:
130: void failed(String s) {
131: for (int i = 0; i < array.length; i++) {
132: array[i].failed(s);
133: }
134: }
135:
136: void exitCodesWere(int expected, int actual) {
137: for (int i = 0; i < array.length; i++) {
138: array[i].exitCodesWere(expected, actual);
139: }
140: }
141:
142: void outputWas(String s) {
143: for (int i = 0; i < array.length; i++) {
144: array[i].outputWas(s);
145: }
146: }
147:
148: void timedOut() {
149: for (int i = 0; i < array.length; i++) {
150: array[i].timedOut();
151: }
152: }
153: };
154: }
155:
156: static class JsError {
157: static String toString(JsError[] e) {
158: String rv = "";
159: for (int i = 0; i < e.length; i++) {
160: rv += e[i].toString();
161: if (i + 1 != e.length) {
162: rv += "\n";
163: }
164: }
165: return rv;
166: }
167:
168: private String message;
169: private String sourceName;
170: private int line;
171: private String lineSource;
172: private int lineOffset;
173:
174: JsError(String message, String sourceName, int line,
175: String lineSource, int lineOffset) {
176: this .message = message;
177: this .sourceName = sourceName;
178: this .line = line;
179: this .lineSource = lineSource;
180: this .lineOffset = lineOffset;
181: }
182:
183: public String toString() {
184: String locationLine = sourceName + ":" + line + ": "
185: + message;
186: String sourceLine = this .lineSource;
187: String errCaret = null;
188: if (lineSource != null) {
189: errCaret = "";
190: for (int i = 0; i < lineSource.length(); i++) {
191: char c = lineSource.charAt(i);
192: if (i < lineOffset - 1) {
193: if (c == '\t') {
194: errCaret += "\t";
195: } else {
196: errCaret += " ";
197: }
198: } else if (i == lineOffset - 1) {
199: errCaret += "^";
200: }
201: }
202: }
203: String rv = locationLine;
204: if (sourceLine != null) {
205: rv += "\n" + sourceLine;
206: }
207: if (errCaret != null) {
208: rv += "\n" + errCaret;
209: }
210: return rv;
211: }
212:
213: String getMessage() {
214: return message;
215: }
216:
217: String getSourceName() {
218: return sourceName;
219: }
220:
221: int getLine() {
222: return line;
223: }
224:
225: String getLineSource() {
226: return lineSource;
227: }
228:
229: int getLineOffset() {
230: return lineOffset;
231: }
232: }
233: }
234:
235: private static class ErrorReporterWrapper implements ErrorReporter {
236: private ErrorReporter original;
237: private ArrayList errors = new ArrayList();
238:
239: ErrorReporterWrapper(ErrorReporter original) {
240: this .original = original;
241: }
242:
243: private void addError(String string, String string0, int i,
244: String string1, int i0) {
245: errors.add(new Status.JsError(string, string0, i, string1,
246: i0));
247: }
248:
249: public void warning(String string, String string0, int i,
250: String string1, int i0) {
251: original.warning(string, string0, i, string1, i0);
252: }
253:
254: public EvaluatorException runtimeError(String string,
255: String string0, int i, String string1, int i0) {
256: return original.runtimeError(string, string0, i, string1,
257: i0);
258: }
259:
260: public void error(String string, String string0, int i,
261: String string1, int i0) {
262: addError(string, string0, i, string1, i0);
263: }
264: }
265:
266: static abstract class Parameters {
267: abstract int getTimeoutMilliseconds();
268: }
269:
270: static void run(final ShellContextFactory shellContextFactory,
271: final File jsFile, final Parameters parameters,
272: final Status status) throws Exception {
273: final Global global = new Global();
274: final ByteArrayOutputStream out = new ByteArrayOutputStream();
275: final PrintStream p = new PrintStream(out);
276: global.setOut(p);
277: global.setErr(p);
278: final TestState testState = new TestState();
279: if (jsFile.getName().endsWith("-n.js")) {
280: status.setNegative();
281: }
282: Thread t = new Thread(new Runnable() {
283: public void run() {
284: try {
285: shellContextFactory.call(new ContextAction() {
286: public Object run(Context cx) {
287: System.out.println("Running " + jsFile);
288: status.running(jsFile);
289: testState.errors = new ErrorReporterWrapper(
290: cx.getErrorReporter());
291: cx.setErrorReporter(testState.errors);
292: global.init(cx);
293: try {
294: runFileIfExists(cx, global, new File(
295: jsFile.getParentFile()
296: .getParentFile()
297: .getParentFile(),
298: "shell.js"));
299: runFileIfExists(cx, global, new File(
300: jsFile.getParentFile()
301: .getParentFile(),
302: "shell.js"));
303: runFileIfExists(cx, global, new File(
304: jsFile.getParentFile(),
305: "shell.js"));
306: runFileIfExists(cx, global, jsFile);
307: // Emulate SpiderMonkey enum value from mozilla/js/src/js.c
308: for (int i = 0; i < testState.errors.errors
309: .size(); i++) {
310: Status.JsError this One = (Status.JsError) testState.errors.errors
311: .get(i);
312: if (this One
313: .getMessage()
314: .indexOf(
315: "java.lang.OutOfMemoryError") != -1) {
316: testState.exitCode = 5;
317: testState.errors.errors
318: .remove(this One);
319: }
320: }
321: status
322: .hadErrors((Status.JsError[]) testState.errors.errors
323: .toArray(new Status.JsError[0]));
324: } catch (ThreadDeath e) {
325: } catch (Throwable t) {
326: status.threw(t);
327: }
328: return null;
329: }
330: });
331: } finally {
332: synchronized (testState) {
333: testState.finished = true;
334: }
335: }
336: }
337: }, jsFile.getPath());
338: t.setDaemon(true);
339: t.start();
340: t.join(parameters.getTimeoutMilliseconds());
341: synchronized (testState) {
342: if (!testState.finished) {
343: t.stop();
344: status.timedOut();
345: }
346: }
347: int expectedExitCode = 0;
348: p.flush();
349: status.outputWas(new String(out.toByteArray()));
350: BufferedReader r = new BufferedReader(new InputStreamReader(
351: new ByteArrayInputStream(out.toByteArray())));
352: String failures = "";
353: for (;;) {
354: String s = r.readLine();
355: if (s == null) {
356: break;
357: }
358: if (s.indexOf("FAILED!") != -1) {
359: failures += s + '\n';
360: }
361: int expex = s.indexOf("EXPECT EXIT CODE ");
362: if (expex != -1) {
363: expectedExitCode = s.charAt(expex
364: + "EXPECT EXIT CODE ".length()) - '0';
365: }
366: }
367: status.exitCodesWere(expectedExitCode, testState.exitCode);
368: if (failures != "") {
369: status.failed(failures);
370: }
371: }
372: }
|