1 /* 2 * Copyright (c) 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary.tasks; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * The supertype for tasks. 34 * Complex operations are modeled by building and running a "Task" object. 35 * Tasks are typically configured in a fluent series of calls. 36 */ 37 public interface Task { 38 /** 39 * {@code ALL-UNNAMED} 40 */ 41 public static final String ALL_UNNAMED = "ALL-UNNAMED"; 42 43 /** The platform line separator. */ 44 static final String lineSeparator = System.getProperty("line.separator"); 45 /** 46 * Returns the name of the task. 47 * @return the name of the task 48 */ 49 String name(); 50 51 /** 52 * Executes the task as currently configured. 53 * @return a Result object containing the results of running the task 54 * @throws TaskError if the outcome of the task was not as expected 55 */ 56 Result run() throws TaskError; 57 58 /** 59 * Exception thrown by {@code Task.run} when the outcome is not as 60 * expected. 61 */ 62 public static class TaskError extends Error { 63 /** 64 * Creates a TaskError object with the given message. 65 * @param message the message 66 */ 67 public TaskError(String message) { 68 super(message); 69 } 70 } 71 72 /** 73 * An enum to indicate the mode a task should use it is when executed. 74 */ 75 public enum Mode { 76 /** 77 * The task should use the interface used by the command 78 * line launcher for the task. 79 * For example, for javac: com.sun.tools.javac.Main.compile 80 */ 81 //next mode is commented out until there is a use for it 82 //CMDLINE, 83 /** 84 * The task should use a publicly defined API for the task. 85 * For example, for javac: javax.tools.JavaCompiler 86 */ 87 //next mode is commented out until there is a use for it 88 //API, 89 /** 90 * The task should use the standard launcher for the task. 91 * For example, $JAVA_HOME/bin/javac 92 */ 93 EXEC 94 } 95 96 /** 97 * An enum to indicate the expected success or failure of executing a task. 98 */ 99 public enum Expect { 100 /** It is expected that the task will complete successfully. */ 101 SUCCESS, 102 /** It is expected that the task will not complete successfully. */ 103 FAIL 104 } 105 106 /** 107 * An enum to identify the streams that may be written by a {@code Task}. 108 */ 109 public enum OutputKind { 110 /** Identifies output written to {@code System.out} or {@code stdout}. */ 111 STDOUT, 112 /** Identifies output written to {@code System.err} or {@code stderr}. */ 113 STDERR 114 /** Identifies output written to a stream provided directly to the task. */ 115 //next output kind is commented out until there is a use for it 116 //,DIRECT 117 }; 118 119 /** 120 * The results from running a {@link Task}. 121 * The results contain the exit code returned when the tool was invoked, 122 * and a map containing the output written to any streams during the 123 * execution of the tool. 124 * All tools support "stdout" and "stderr". 125 * Tools that take an explicit PrintWriter save output written to that 126 * stream as "main". 127 */ 128 public static class Result { 129 final Task task; 130 final int exitCode; 131 final Map<OutputKind, String> outputMap; 132 final List<String> command; 133 134 Result(Task task, int exitCode, Map<OutputKind, String> outputMap, 135 List<String> command) { 136 this.task = task; 137 this.exitCode = exitCode; 138 this.outputMap = outputMap; 139 this.command = command; 140 } 141 142 Result(Task task, int exitCode, Map<OutputKind, String> outputMap) { 143 this(task, exitCode, outputMap, Collections.EMPTY_LIST); 144 } 145 146 /** 147 * Returns the exit code. 148 * @return the exit code. 149 */ 150 public int getExitCode() { 151 return exitCode; 152 } 153 154 /** 155 * Returns the exit code. 156 * @return the exit code. 157 */ 158 public List<String> getCommand() { 159 return command; 160 } 161 162 /** 163 * Returns the content of a specified stream. 164 * @param outputKind the kind of the selected stream 165 * @return the content that was written to that stream when the tool 166 * was executed. 167 */ 168 public String getOutput(OutputKind outputKind) { 169 return outputMap.get(outputKind); 170 } 171 172 /** 173 * Returns the content of named streams as a list of lines. 174 * @param outputKinds the kinds of the selected streams 175 * @return the content that was written to the given streams when the tool 176 * was executed. 177 */ 178 public List<String> getOutputLines(OutputKind... outputKinds) { 179 List<String> result = new ArrayList<>(); 180 for (OutputKind outputKind : outputKinds) { 181 result.addAll(Arrays.asList(outputMap.get(outputKind).split(lineSeparator))); 182 } 183 return result; 184 } 185 186 /** 187 * Writes the content of the specified stream to the log. 188 * @param kind the kind of the selected stream 189 * @return this Result object 190 */ 191 public Result write(OutputKind kind) { 192 String text = getOutput(kind); 193 if (text == null || text.isEmpty()) 194 System.out.println("[" + task.name() + ":" + kind + "]: empty"); 195 else { 196 System.out.println("[" + task.name() + ":" + kind + "]:"); 197 System.out.print(text); 198 } 199 return this; 200 } 201 202 /** 203 * Writes the content of all streams with any content to the log. 204 * @return this Result object 205 */ 206 public Result writeAll() { 207 outputMap.forEach((name, text) -> { 208 if (!text.isEmpty()) { 209 System.out.println("[" + name + "]:"); 210 System.out.print(text); 211 } 212 }); 213 return this; 214 } 215 216 /** 217 * Verify that the specified output contains the string 218 * 219 * @param kind the output kind 220 * @param expectedString String that buffer should contain 221 * @throws RuntimeException If the string was not found 222 */ 223 public void shouldContain(OutputKind kind, String expectedString) { 224 if (!getOutput(kind).contains(expectedString)) 225 throw new RuntimeException("'" + expectedString 226 + "' missing from " + kind.name()); 227 } 228 229 /** 230 * Verify that either stdout or stderr contains the string 231 * 232 * @param expectedString String that buffer should contain 233 * @throws RuntimeException If the string was not found 234 */ 235 public void shouldContain(String expectedString) { 236 for (OutputKind kind : OutputKind.values()) { 237 if (getOutput(kind).contains(expectedString)) 238 return; 239 } 240 throw new RuntimeException("'" + expectedString 241 + "' missing from output"); 242 } 243 } 244 } 245