1 /*
   2  * Copyright (c) 2013, 2015, 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.test.lib;
  25 
  26 import java.io.IOException;
  27 import java.util.Arrays;
  28 import java.util.List;
  29 import java.util.regex.Matcher;
  30 import java.util.regex.Pattern;
  31 
  32 public final class OutputAnalyzer {
  33 
  34   private final String stdout;
  35   private final String stderr;
  36   private final int exitValue;
  37 
  38   /**
  39    * Create an OutputAnalyzer, a utility class for verifying output and exit
  40    * value from a Process
  41    *
  42    * @param process Process to analyze
  43    * @throws IOException If an I/O error occurs.
  44    *
  45    * @deprecated This class is deprecated. Use the one from
  46    *             {@code <root>/test/lib/share/classes/jdk/test/lib/process}
  47    */
  48   @Deprecated
  49   public OutputAnalyzer(Process process) throws IOException {
  50     OutputBuffer output = ProcessTools.getOutput(process);
  51     exitValue = process.exitValue();
  52     this.stdout = output.getStdout();
  53     this.stderr = output.getStderr();
  54   }
  55 
  56   /**
  57    * Create an OutputAnalyzer, a utility class for verifying output
  58    *
  59    * @param buf String buffer to analyze
  60    */
  61   public OutputAnalyzer(String buf) {
  62     this(buf, buf);
  63   }
  64 
  65   /**
  66    * Create an OutputAnalyzer, a utility class for verifying output
  67    *
  68    * @param stdout stdout buffer to analyze
  69    * @param stderr stderr buffer to analyze
  70    */
  71   public OutputAnalyzer(String stdout, String stderr) {
  72     this.stdout = stdout;
  73     this.stderr = stderr;
  74     exitValue = -1;
  75   }
  76 
  77   /**
  78    * Verify that the stdout contents of output buffer is empty
  79    *
  80    * @throws RuntimeException
  81    *             If stdout was not empty
  82    */
  83   public void stdoutShouldBeEmpty() {
  84     if (!getStdout().isEmpty()) {
  85       reportDiagnosticSummary();
  86       throw new RuntimeException("stdout was not empty");
  87     }
  88   }
  89 
  90   /**
  91    * Verify that the stderr contents of output buffer is empty
  92    *
  93    * @throws RuntimeException
  94    *             If stderr was not empty
  95    */
  96   public void stderrShouldBeEmpty() {
  97     if (!getStderr().isEmpty()) {
  98       reportDiagnosticSummary();
  99       throw new RuntimeException("stderr was not empty");
 100     }
 101   }
 102 
 103   /**
 104    * Verify that the stdout contents of output buffer is not empty
 105    *
 106    * @throws RuntimeException
 107    *             If stdout was empty
 108    */
 109   public void stdoutShouldNotBeEmpty() {
 110     if (getStdout().isEmpty()) {
 111       reportDiagnosticSummary();
 112       throw new RuntimeException("stdout was empty");
 113     }
 114   }
 115 
 116   /**
 117    * Verify that the stderr contents of output buffer is not empty
 118    *
 119    * @throws RuntimeException
 120    *             If stderr was empty
 121    */
 122   public void stderrShouldNotBeEmpty() {
 123     if (getStderr().isEmpty()) {
 124       reportDiagnosticSummary();
 125       throw new RuntimeException("stderr was empty");
 126     }
 127   }
 128 
 129     /**
 130    * Verify that the stdout and stderr contents of output buffer contains the string
 131    *
 132    * @param expectedString String that buffer should contain
 133    * @throws RuntimeException If the string was not found
 134    */
 135   public OutputAnalyzer shouldContain(String expectedString) {
 136     if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) {
 137         reportDiagnosticSummary();
 138         throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n");
 139     }
 140     return this;
 141   }
 142 
 143   /**
 144    * Verify that the stdout contents of output buffer contains the string
 145    *
 146    * @param expectedString String that buffer should contain
 147    * @throws RuntimeException If the string was not found
 148    */
 149   public OutputAnalyzer stdoutShouldContain(String expectedString) {
 150     if (!stdout.contains(expectedString)) {
 151         reportDiagnosticSummary();
 152         throw new RuntimeException("'" + expectedString + "' missing from stdout \n");
 153     }
 154     return this;
 155   }
 156 
 157   /**
 158    * Verify that the stderr contents of output buffer contains the string
 159    *
 160    * @param expectedString String that buffer should contain
 161    * @throws RuntimeException If the string was not found
 162    */
 163   public OutputAnalyzer stderrShouldContain(String expectedString) {
 164     if (!stderr.contains(expectedString)) {
 165         reportDiagnosticSummary();
 166         throw new RuntimeException("'" + expectedString + "' missing from stderr \n");
 167     }
 168     return this;
 169   }
 170 
 171   /**
 172    * Verify that the stdout and stderr contents of output buffer does not contain the string
 173    *
 174    * @param expectedString String that the buffer should not contain
 175    * @throws RuntimeException If the string was found
 176    */
 177   public OutputAnalyzer shouldNotContain(String notExpectedString) {
 178     if (stdout.contains(notExpectedString)) {
 179         reportDiagnosticSummary();
 180         throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
 181     }
 182     if (stderr.contains(notExpectedString)) {
 183         reportDiagnosticSummary();
 184         throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
 185     }
 186     return this;
 187   }
 188 
 189   /**
 190    * Verify that the stdout contents of output buffer does not contain the string
 191    *
 192    * @param expectedString String that the buffer should not contain
 193    * @throws RuntimeException If the string was found
 194    */
 195   public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) {
 196     if (stdout.contains(notExpectedString)) {
 197         reportDiagnosticSummary();
 198         throw new RuntimeException("'" + notExpectedString + "' found in stdout \n");
 199     }
 200     return this;
 201   }
 202 
 203   /**
 204    * Verify that the stderr contents of output buffer does not contain the string
 205    *
 206    * @param expectedString String that the buffer should not contain
 207    * @throws RuntimeException If the string was found
 208    */
 209   public OutputAnalyzer stderrShouldNotContain(String notExpectedString) {
 210     if (stderr.contains(notExpectedString)) {
 211         reportDiagnosticSummary();
 212         throw new RuntimeException("'" + notExpectedString + "' found in stderr \n");
 213     }
 214     return this;
 215   }
 216 
 217   /**
 218    * Verify that the stdout and stderr contents of output buffer matches
 219    * the pattern
 220    *
 221    * @param pattern
 222    * @throws RuntimeException If the pattern was not found
 223    */
 224   public OutputAnalyzer shouldMatch(String pattern) {
 225       Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
 226       Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
 227       if (!stdoutMatcher.find() && !stderrMatcher.find()) {
 228           reportDiagnosticSummary();
 229           throw new RuntimeException("'" + pattern
 230                 + "' missing from stdout/stderr \n");
 231       }
 232       return this;
 233   }
 234 
 235   /**
 236    * Verify that the stdout contents of output buffer matches the
 237    * pattern
 238    *
 239    * @param pattern
 240    * @throws RuntimeException If the pattern was not found
 241    */
 242   public OutputAnalyzer stdoutShouldMatch(String pattern) {
 243       Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
 244       if (!matcher.find()) {
 245           reportDiagnosticSummary();
 246           throw new RuntimeException("'" + pattern
 247                 + "' missing from stdout \n");
 248       }
 249       return this;
 250   }
 251 
 252   /**
 253    * Verify that the stderr contents of output buffer matches the
 254    * pattern
 255    *
 256    * @param pattern
 257    * @throws RuntimeException If the pattern was not found
 258    */
 259   public OutputAnalyzer stderrShouldMatch(String pattern) {
 260       Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
 261       if (!matcher.find()) {
 262           reportDiagnosticSummary();
 263           throw new RuntimeException("'" + pattern
 264                 + "' missing from stderr \n");
 265       }
 266       return this;
 267   }
 268 
 269   /**
 270    * Verify that the stdout and stderr contents of output buffer does not
 271    * match the pattern
 272    *
 273    * @param pattern
 274    * @throws RuntimeException If the pattern was found
 275    */
 276   public OutputAnalyzer shouldNotMatch(String pattern) {
 277       Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
 278       if (matcher.find()) {
 279           reportDiagnosticSummary();
 280           throw new RuntimeException("'" + pattern
 281                   + "' found in stdout: '" + matcher.group() + "' \n");
 282       }
 283       matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
 284       if (matcher.find()) {
 285           reportDiagnosticSummary();
 286           throw new RuntimeException("'" + pattern
 287                   + "' found in stderr: '" + matcher.group() + "' \n");
 288       }
 289       return this;
 290   }
 291 
 292   /**
 293    * Verify that the stdout contents of output buffer does not match the
 294    * pattern
 295    *
 296    * @param pattern
 297    * @throws RuntimeException If the pattern was found
 298    */
 299   public OutputAnalyzer stdoutShouldNotMatch(String pattern) {
 300       Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
 301       if (matcher.find()) {
 302           reportDiagnosticSummary();
 303           throw new RuntimeException("'" + pattern
 304                   + "' found in stdout \n");
 305       }
 306       return this;
 307   }
 308 
 309   /**
 310    * Verify that the stderr contents of output buffer does not match the
 311    * pattern
 312    *
 313    * @param pattern
 314    * @throws RuntimeException If the pattern was found
 315    */
 316   public OutputAnalyzer stderrShouldNotMatch(String pattern) {
 317       Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
 318       if (matcher.find()) {
 319           reportDiagnosticSummary();
 320           throw new RuntimeException("'" + pattern
 321                   + "' found in stderr \n");
 322       }
 323       return this;
 324   }
 325 
 326   /**
 327    * Get the captured group of the first string matching the pattern.
 328    * stderr is searched before stdout.
 329    *
 330    * @param pattern The multi-line pattern to match
 331    * @param group The group to capture
 332    * @return The matched string or null if no match was found
 333    */
 334   public String firstMatch(String pattern, int group) {
 335     Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr);
 336     Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout);
 337     if (stderrMatcher.find()) {
 338       return stderrMatcher.group(group);
 339     }
 340     if (stdoutMatcher.find()) {
 341       return stdoutMatcher.group(group);
 342     }
 343     return null;
 344   }
 345 
 346   /**
 347    * Get the first string matching the pattern.
 348    * stderr is searched before stdout.
 349    *
 350    * @param pattern The multi-line pattern to match
 351    * @return The matched string or null if no match was found
 352    */
 353   public String firstMatch(String pattern) {
 354     return firstMatch(pattern, 0);
 355   }
 356 
 357   /**
 358    * Verify the exit value of the process
 359    *
 360    * @param expectedExitValue Expected exit value from process
 361    * @throws RuntimeException If the exit value from the process did not match the expected value
 362    */
 363   public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) {
 364       if (getExitValue() != expectedExitValue) {
 365           reportDiagnosticSummary();
 366           throw new RuntimeException("Expected to get exit value of ["
 367                   + expectedExitValue + "]\n");
 368       }
 369       return this;
 370   }
 371 
 372 
 373   /**
 374    * Report summary that will help to diagnose the problem
 375    * Currently includes:
 376    *  - standard input produced by the process under test
 377    *  - standard output
 378    *  - exit code
 379    *  Note: the command line is printed by the ProcessTools
 380    */
 381   public void reportDiagnosticSummary() {
 382       String msg =
 383           " stdout: [" + stdout + "];\n" +
 384           " stderr: [" + stderr + "]\n" +
 385           " exitValue = " + getExitValue() + "\n";
 386 
 387       System.err.println(msg);
 388   }
 389 
 390 
 391   /**
 392    * Get the contents of the output buffer (stdout and stderr)
 393    *
 394    * @return Content of the output buffer
 395    */
 396   public String getOutput() {
 397     return stdout + stderr;
 398   }
 399 
 400   /**
 401    * Get the contents of the stdout buffer
 402    *
 403    * @return Content of the stdout buffer
 404    */
 405   public String getStdout() {
 406     return stdout;
 407   }
 408 
 409   /**
 410    * Get the contents of the stderr buffer
 411    *
 412    * @return Content of the stderr buffer
 413    */
 414   public String getStderr() {
 415     return stderr;
 416   }
 417 
 418   /**
 419    * Get the process exit value
 420    *
 421    * @return Process exit value
 422    */
 423   public int getExitValue() {
 424     return exitValue;
 425   }
 426 
 427   /**
 428    * Get the contents of the output buffer (stdout and stderr) as list of strings.
 429    * Output will be split by newlines.
 430    *
 431    * @return Contents of the output buffer as list of strings
 432    */
 433   public List<String> asLines() {
 434     return asLines(getOutput());
 435   }
 436 
 437   private List<String> asLines(String buffer) {
 438     return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)"));
 439   }
 440 }