ScriptRunnable.java revision 475:fbd21b00197b
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.test.framework;
27
28import java.io.BufferedReader;
29import java.io.ByteArrayOutputStream;
30import java.io.File;
31import java.io.FileInputStream;
32import java.io.FileOutputStream;
33import java.io.IOException;
34import java.io.InputStreamReader;
35import java.io.OutputStream;
36import java.io.PrintStream;
37import java.io.PrintWriter;
38import java.io.StringReader;
39import java.nio.file.FileSystems;
40import java.nio.file.Files;
41import java.nio.file.StandardCopyOption;
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.List;
45import java.util.Map;
46
47import jdk.nashorn.tools.Shell;
48import org.testng.Assert;
49import org.testng.ITest;
50import org.testng.annotations.Test;
51
52/**
53 * Compiles a single JavaScript script source file and executes the resulting
54 * class. Optionally, output from running the script is compared against the
55 * corresponding .EXPECTED file.
56 */
57public final class ScriptRunnable extends AbstractScriptRunnable implements ITest {
58    public ScriptRunnable(final String framework, final File testFile, final List<String> engineOptions, final Map<String, String> testOptions,  final List<String> scriptArguments) {
59        super(framework, testFile, engineOptions, testOptions, scriptArguments);
60
61        if (this.shouldRun) {
62          // add --dump-on-error option always so that we can get detailed error msg.
63          engineOptions.add("-doe");
64        }
65    }
66
67    @Override
68    public String getTestName() {
69        return testFile.getAbsolutePath();
70    }
71
72    @Test
73    @Override
74    public void runTest() throws IOException {
75        super.runTest();
76    }
77
78    @Override
79    protected void execute() {
80        if (fork) {
81            executeInNewProcess();
82        } else {
83            executeInThisProcess();
84        }
85    }
86
87    // avoid direct System.out.println - use reporter to capture
88    @Override
89    protected void log(String msg) {
90        org.testng.Reporter.log(msg, true);
91    }
92
93    // throw Assert fail - but log as well so that user can see this at console
94    @Override
95    protected void fail(final String msg) {
96        log(msg);
97        Assert.fail(msg);
98    }
99
100    @Override
101    protected void compile() throws IOException {
102        final ByteArrayOutputStream out = new ByteArrayOutputStream();
103        final ByteArrayOutputStream err = new ByteArrayOutputStream();
104        final List<String> args = getCompilerArgs();
105        int errors;
106
107        try {
108            errors = evaluateScript(out, err, args.toArray(new String[args.size()]));
109        } catch (final AssertionError e) {
110            final PrintWriter writer = new PrintWriter(err);
111            e.printStackTrace(writer);
112            writer.flush();
113            errors = 1;
114        }
115
116        if (errors != 0 || checkCompilerMsg) {
117            if (expectCompileFailure || checkCompilerMsg) {
118                final PrintStream outputDest = new PrintStream(new FileOutputStream(errorFileName));
119                TestHelper.dumpFile(outputDest, new StringReader(new String(err.toByteArray())));
120                outputDest.println("--");
121            } else {
122                log(new String(err.toByteArray()));
123            }
124
125            if (errors != 0 && !expectCompileFailure) {
126                fail(String.format("%d errors compiling %s", errors, testFile));
127            }
128            if (checkCompilerMsg) {
129                compare(errorFileName, expectedFileName, true);
130            }
131        }
132
133        if (expectCompileFailure && errors == 0) {
134            fail(String.format("No errors encountered compiling negative test %s", testFile));
135        }
136    }
137
138    private void executeInThisProcess() {
139        final List<String> args = getRuntimeArgs();
140        final File outputFileHandle = new File(outputFileName);
141        final File errorFileHandle  = new File(errorFileName);
142
143        try (OutputStream outputFile = new FileOutputStream(outputFileName); OutputStream errorFile = new FileOutputStream(errorFileName)) {
144            final int errors = evaluateScript(outputFile, errorFile, args.toArray(new String[args.size()]));
145
146            if (errors != 0 || errorFileHandle.length() > 0) {
147                if (expectRunFailure) {
148                    return;
149                }
150
151                if (!ignoreStdError) {
152                    if (outputFileHandle.length() > 0) {
153                        TestHelper.dumpFile(outputFileHandle);
154                    }
155                    fail(TestHelper.fullContent(errorFileHandle));
156                }
157            }
158
159            if (compare) {
160                compare(outputFileName, expectedFileName, false);
161            }
162        } catch (final IOException e) {
163            if (!expectRunFailure) {
164                fail("Failure running test " + testFile + ": " + e.getMessage());
165                // else success
166            }
167        }
168    }
169
170    private void executeInNewProcess() {
171
172        final String separator = System.getProperty("file.separator");
173        final List<String> cmd = new ArrayList<>();
174
175        cmd.add(System.getProperty("java.home") + separator + "bin" + separator + "java");
176        cmd.add("-Djava.ext.dirs=dist");
177        for (String str : forkJVMOptions) {
178            cmd.add(str);
179        }
180        cmd.add(Shell.class.getName());
181        // now add the rest of the "in process" runtime arguments
182        cmd.addAll(getRuntimeArgs());
183
184        final File outputFileHandle = new File(outputFileName);
185        final File errorFileHandle = new File(errorFileName);
186
187        try {
188            final ProcessBuilder pb = new ProcessBuilder(cmd);
189            pb.redirectOutput(outputFileHandle);
190            pb.redirectError(errorFileHandle);
191            final Process process = pb.start();
192
193            process.waitFor();
194
195            if (errorFileHandle.length() > 0) {
196                if (expectRunFailure) {
197                    return;
198                }
199                if (!ignoreStdError) {
200                    if (outputFileHandle.length() > 0) {
201                        TestHelper.dumpFile(outputFileHandle);
202                    }
203                    fail(TestHelper.fullContent(errorFileHandle));
204                }
205            }
206
207            if (compare) {
208                compare(outputFileName, expectedFileName, false);
209            }
210        } catch (final IOException | InterruptedException e) {
211            if (!expectRunFailure) {
212                fail("Failure running test " + testFile + ": " + e.getMessage());
213                // else success
214            }
215        }
216    }
217
218    private void compare(final String outputFileName0, final String expectedFileName0, final boolean compareCompilerMsg) throws IOException {
219        final File expectedFile = new File(expectedFileName0);
220
221        BufferedReader expected;
222        if (expectedFile.exists()) {
223            expected = new BufferedReader(new InputStreamReader(new FileInputStream(expectedFileName0)));
224            // copy expected file overwriting existing file and preserving last
225            // modified time of source
226            try {
227                Files.copy(FileSystems.getDefault().getPath(expectedFileName0),
228                        FileSystems.getDefault().getPath(copyExpectedFileName),
229                        StandardCopyOption.REPLACE_EXISTING,
230                        StandardCopyOption.COPY_ATTRIBUTES);
231            } catch (final IOException ex) {
232                fail("failed to copy expected " + expectedFileName + " to " + copyExpectedFileName + ": " + ex.getMessage());
233            }
234        } else {
235            expected = new BufferedReader(new StringReader(""));
236        }
237
238        final BufferedReader actual = new BufferedReader(new InputStreamReader(new FileInputStream(outputFileName0)));
239        compare(actual, expected, compareCompilerMsg);
240    }
241}
242