1 /*
   2  * Copyright (c) 2013, 2014, 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;
  25 
  26 import static jdk.testlibrary.Asserts.*;
  27 
  28 import java.io.IOException;
  29 import java.io.PrintStream;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import java.util.regex.Matcher;
  33 import java.util.regex.Pattern;
  34 
  35 /**
  36  * Utility class for verifying output and exit value from a {@code Process}.
  37  *
  38  * @deprecated  This class is deprecated. Use the one from
  39  *              {@code <root>/test/lib/jdk/test/lib/process}
  40  *
  41  */
  42 @Deprecated
  43 public final class OutputAnalyzer {
  44     private final OutputBuffer output;
  45     private final String stdout;
  46     private final String stderr;
  47     private final int exitValue;    // useless now. output contains exit value.
  48 
  49     /**
  50      * Create an OutputAnalyzer, a utility class for verifying output and exit
  51      * value from a Process.
  52      * <p>
  53      * OutputAnalyzer should never be instantiated directly -
  54      * use {@linkplain ProcessTools#executeProcess(ProcessBuilder)} instead
  55      *
  56      * @param process
  57      *            Process to analyze
  58      * @throws IOException
  59      *             If an I/O error occurs.
  60      */
  61     OutputAnalyzer(Process process) throws IOException {
  62         output = new OutputBuffer(process);
  63         exitValue = -1;
  64         this.stdout = null;
  65         this.stderr = null;
  66     }
  67 
  68     /**
  69      * Create an OutputAnalyzer, a utility class for verifying output.
  70      *
  71      * @param buf
  72      *            String buffer to analyze
  73      */
  74     OutputAnalyzer(String buf) {
  75         this(buf, buf);
  76     }
  77 
  78     /**
  79      * Create an OutputAnalyzer, a utility class for verifying output
  80      *
  81      * @param stdout
  82      *            stdout buffer to analyze
  83      * @param stderr
  84      *            stderr buffer to analyze
  85      */
  86     OutputAnalyzer(String stdout, String stderr) {
  87         this.output = null;
  88         this.stdout = stdout;
  89         this.stderr = stderr;
  90         exitValue = -1;
  91     }
  92 
  93     /**
  94      * Verify that the stdout and stderr contents of output buffer contains the
  95      * string
  96      *
  97      * @param expectedString
  98      *            String that buffer should contain
  99      * @throws RuntimeException
 100      *             If the string was not found
 101      */
 102     public OutputAnalyzer shouldContain(String expectedString) {
 103         if (!getStdout().contains(expectedString)
 104                 && !getStderr().contains(expectedString)) {
 105             reportDiagnosticSummary();
 106             throw new RuntimeException("'" + expectedString
 107                     + "' missing from stdout/stderr \n");
 108         }
 109         return this;
 110     }
 111 
 112     /**
 113      * Verify that the stdout contents of output buffer contains the string
 114      *
 115      * @param expectedString
 116      *            String that buffer should contain
 117      * @throws RuntimeException
 118      *             If the string was not found
 119      */
 120     public OutputAnalyzer stdoutShouldContain(String expectedString) {
 121         if (!getStdout().contains(expectedString)) {
 122             reportDiagnosticSummary();
 123             throw new RuntimeException("'" + expectedString
 124                     + "' missing from stdout \n");
 125         }
 126         return this;
 127     }
 128 
 129     /**
 130      * Verify that the stderr contents of output buffer contains the string
 131      *
 132      * @param expectedString
 133      *            String that buffer should contain
 134      * @throws RuntimeException
 135      *             If the string was not found
 136      */
 137     public OutputAnalyzer stderrShouldContain(String expectedString) {
 138         if (!getStderr().contains(expectedString)) {
 139             reportDiagnosticSummary();
 140             throw new RuntimeException("'" + expectedString
 141                     + "' missing from stderr \n");
 142         }
 143         return this;
 144     }
 145 
 146     /**
 147      * Verify that the stdout and stderr contents of output buffer does not
 148      * contain the string
 149      *
 150      * @param notExpectedString
 151      *            String that the buffer should not contain
 152      * @throws RuntimeException
 153      *             If the string was found
 154      */
 155     public OutputAnalyzer shouldNotContain(String notExpectedString) {
 156         if (getStdout().contains(notExpectedString)) {
 157             reportDiagnosticSummary();
 158             throw new RuntimeException("'" + notExpectedString
 159                     + "' found in stdout \n");
 160         }
 161         if (getStderr().contains(notExpectedString)) {
 162             reportDiagnosticSummary();
 163             throw new RuntimeException("'" + notExpectedString
 164                     + "' found in stderr \n");
 165         }
 166         return this;
 167     }
 168 
 169     /**
 170      * Verify that the stdout contents of output buffer does not contain the
 171      * string
 172      *
 173      * @param notExpectedString
 174      *            String that the buffer should not contain
 175      * @throws RuntimeException
 176      *             If the string was found
 177      */
 178     public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) {
 179         if (getStdout().contains(notExpectedString)) {
 180             reportDiagnosticSummary();
 181             throw new RuntimeException("'" + notExpectedString
 182                     + "' found in stdout \n");
 183         }
 184         return this;
 185     }
 186 
 187     /**
 188      * Verify that the stderr contents of output buffer does not contain the
 189      * string
 190      *
 191      * @param notExpectedString
 192      *            String that the buffer should not contain
 193      * @throws RuntimeException
 194      *             If the string was found
 195      */
 196     public OutputAnalyzer stderrShouldNotContain(String notExpectedString) {
 197         if (getStderr().contains(notExpectedString)) {
 198             reportDiagnosticSummary();
 199             throw new RuntimeException("'" + notExpectedString
 200                     + "' found in stderr \n");
 201         }
 202         return this;
 203     }
 204 
 205     /**
 206      * Verify that the stdout and stderr contents of output buffer matches the
 207      * pattern
 208      *
 209      * @param pattern
 210      * @throws RuntimeException
 211      *             If the pattern was not found
 212      */
 213     public OutputAnalyzer shouldMatch(String pattern) {
 214         Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
 215                 .matcher(getStdout());
 216         Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
 217                 .matcher(getStderr());
 218         if (!stdoutMatcher.find() && !stderrMatcher.find()) {
 219             reportDiagnosticSummary();
 220             throw new RuntimeException("'" + pattern
 221                     + "' missing from stdout/stderr \n");
 222         }
 223         return this;
 224     }
 225 
 226     /**
 227      * Verify that the stdout contents of output buffer matches the pattern
 228      *
 229      * @param pattern
 230      * @throws RuntimeException
 231      *             If the pattern was not found
 232      */
 233     public OutputAnalyzer stdoutShouldMatch(String pattern) {
 234         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
 235                 getStdout());
 236         if (!matcher.find()) {
 237             reportDiagnosticSummary();
 238             throw new RuntimeException("'" + pattern
 239                     + "' missing from stdout \n");
 240         }
 241         return this;
 242     }
 243 
 244     /**
 245      * Verify that the stderr contents of output buffer matches the pattern
 246      *
 247      * @param pattern
 248      * @throws RuntimeException
 249      *             If the pattern was not found
 250      */
 251     public OutputAnalyzer stderrShouldMatch(String pattern) {
 252         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
 253                 getStderr());
 254         if (!matcher.find()) {
 255             reportDiagnosticSummary();
 256             throw new RuntimeException("'" + pattern
 257                     + "' missing from stderr \n");
 258         }
 259         return this;
 260     }
 261 
 262     /**
 263      * Verify that the stdout and stderr contents of output buffer does not
 264      * match the pattern
 265      *
 266      * @param pattern
 267      * @throws RuntimeException
 268      *             If the pattern was found
 269      */
 270     public OutputAnalyzer shouldNotMatch(String pattern) {
 271         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
 272                 getStdout());
 273         if (matcher.find()) {
 274             reportDiagnosticSummary();
 275             throw new RuntimeException("'" + pattern + "' found in stdout: '"
 276                     + matcher.group() + "' \n");
 277         }
 278         matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(getStderr());
 279         if (matcher.find()) {
 280             reportDiagnosticSummary();
 281             throw new RuntimeException("'" + pattern + "' found in stderr: '"
 282                     + matcher.group() + "' \n");
 283         }
 284         return this;
 285     }
 286 
 287     /**
 288      * Verify that the stdout contents of output buffer does not match the
 289      * pattern
 290      *
 291      * @param pattern
 292      * @throws RuntimeException
 293      *             If the pattern was found
 294      */
 295     public OutputAnalyzer stdoutShouldNotMatch(String pattern) {
 296         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
 297                 getStdout());
 298         if (matcher.find()) {
 299             reportDiagnosticSummary();
 300             throw new RuntimeException("'" + pattern + "' found in stdout \n");
 301         }
 302         return this;
 303     }
 304 
 305     /**
 306      * Verify that the stderr contents of output buffer does not match the
 307      * pattern
 308      *
 309      * @param pattern
 310      * @throws RuntimeException
 311      *             If the pattern was found
 312      */
 313     public OutputAnalyzer stderrShouldNotMatch(String pattern) {
 314         Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(
 315                 getStderr());
 316         if (matcher.find()) {
 317             reportDiagnosticSummary();
 318             throw new RuntimeException("'" + pattern + "' found in stderr \n");
 319         }
 320         return this;
 321     }
 322 
 323     /**
 324      * Get the captured group of the first string matching the pattern. stderr
 325      * is searched before stdout.
 326      *
 327      * @param pattern
 328      *            The multi-line pattern to match
 329      * @param group
 330      *            The group to capture
 331      * @return The matched string or null if no match was found
 332      */
 333     public String firstMatch(String pattern, int group) {
 334         Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
 335                 .matcher(getStderr());
 336         Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE)
 337                 .matcher(getStdout());
 338         if (stderrMatcher.find()) {
 339             return stderrMatcher.group(group);
 340         }
 341         if (stdoutMatcher.find()) {
 342             return stdoutMatcher.group(group);
 343         }
 344         return null;
 345     }
 346 
 347     /**
 348      * Get the first string matching the pattern. stderr is searched before
 349      * stdout.
 350      *
 351      * @param pattern
 352      *            The multi-line pattern to match
 353      * @return The matched string or null if no match was found
 354      */
 355     public String firstMatch(String pattern) {
 356         return firstMatch(pattern, 0);
 357     }
 358 
 359     /**
 360      * Verify the exit value of the process
 361      *
 362      * @param expectedExitValue
 363      *            Expected exit value from process
 364      * @throws RuntimeException
 365      *             If the exit value from the process did not match the expected
 366      *             value
 367      */
 368     public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) {
 369         if (getExitValue() != expectedExitValue) {
 370             reportDiagnosticSummary();
 371             throw new RuntimeException("Expected to get exit value of ["
 372                     + expectedExitValue + "]\n");
 373         }
 374         return this;
 375     }
 376 
 377     /**
 378      * Report summary that will help to diagnose the problem Currently includes:
 379      * - standard input produced by the process under test - standard output -
 380      * exit code Note: the command line is printed by the ProcessTools
 381      */
 382     private OutputAnalyzer reportDiagnosticSummary() {
 383         String msg = " stdout: [" + getStdout() + "];\n" + " stderr: [" + getStderr()
 384                 + "]\n" + " exitValue = " + getExitValue() + "\n";
 385 
 386         System.err.println(msg);
 387         return this;
 388     }
 389 
 390     /**
 391      * Get the contents of the output buffer (stdout and stderr)
 392      *
 393      * @return Content of the output buffer
 394      */
 395     public String getOutput() {
 396         return getStdout() + getStderr();
 397     }
 398 
 399     /**
 400      * Get the contents of the stdout buffer
 401      *
 402      * @return Content of the stdout buffer
 403      */
 404     public String getStdout() {
 405         return output == null ? stdout : output.getStdout();
 406     }
 407 
 408     /**
 409      * Get the contents of the stderr buffer
 410      *
 411      * @return Content of the stderr buffer
 412      */
 413     public String getStderr() {
 414         return output == null ? stderr : output.getStderr();
 415     }
 416 
 417     /**
 418      * Get the process exit value
 419      *
 420      * @return Process exit value
 421      */
 422     public int getExitValue() {
 423         return output == null ? exitValue : output.getExitValue();
 424     }
 425 
 426 
 427     /**
 428      * Print the stdout buffer to the given {@code PrintStream}.
 429      *
 430      * @return this OutputAnalyzer
 431      */
 432     public OutputAnalyzer outputTo(PrintStream out) {
 433         out.println(getStdout());
 434         return this;
 435     }
 436 
 437     /**
 438      * Print the stderr buffer to the given {@code PrintStream}.
 439      *
 440      * @return this OutputAnalyzer
 441      */
 442     public OutputAnalyzer errorTo(PrintStream out) {
 443         out.println(getStderr());
 444         return this;
 445     }
 446 
 447 
 448     /**
 449      * Get the contents of the output buffer (stdout and stderr) as list of strings.
 450      * Output will be split by system property 'line.separator'.
 451      *
 452      * @return Contents of the output buffer as list of strings
 453      */
 454     public List<String> asLines() {
 455         return asLines(getOutput());
 456     }
 457 
 458     private List<String> asLines(String buffer) {
 459         List<String> l = new ArrayList<>();
 460         String[] a = buffer.split(Utils.NEW_LINE);
 461         for (String string : a) {
 462             l.add(string);
 463         }
 464         return l;
 465     }
 466 
 467     /**
 468      * Check if there is a line matching {@code pattern} and return its index
 469      *
 470      * @param pattern Matching pattern
 471      * @return Index of first matching line
 472      */
 473     private int indexOf(List<String> lines, String pattern) {
 474         for (int i = 0; i < lines.size(); i++) {
 475             if (lines.get(i).matches(pattern)) {
 476                 return i;
 477             }
 478         }
 479         return -1;
 480     }
 481 
 482     /**
 483      * @see #shouldMatchByLine(String, String, String)
 484      */
 485     public int shouldMatchByLine(String pattern) {
 486         return shouldMatchByLine(null, null, pattern);
 487     }
 488 
 489     /**
 490      * @see #stdoutShouldMatchByLine(String, String, String)
 491      */
 492     public int stdoutShouldMatchByLine(String pattern) {
 493         return stdoutShouldMatchByLine(null, null, pattern);
 494     }
 495 
 496     /**
 497      * @see #shouldMatchByLine(String, String, String)
 498      */
 499     public int shouldMatchByLineFrom(String from, String pattern) {
 500         return shouldMatchByLine(from, null, pattern);
 501     }
 502 
 503     /**
 504      * @see #shouldMatchByLine(String, String, String)
 505      */
 506     public int shouldMatchByLineTo(String to, String pattern) {
 507         return shouldMatchByLine(null, to, pattern);
 508     }
 509 
 510     /**
 511      * Verify that the stdout and stderr contents of output buffer match the
 512      * {@code pattern} line by line. The whole output could be matched or
 513      * just a subset of it.
 514      *
 515      * @param from
 516      *            The line from where output will be matched.
 517      *            Set {@code from} to null for matching from the first line.
 518      * @param to
 519      *            The line until where output will be matched.
 520      *            Set {@code to} to null for matching until the last line.
 521      * @param pattern
 522      *            Matching pattern
 523      * @return Count of lines which match the {@code pattern}
 524      */
 525     public int shouldMatchByLine(String from, String to, String pattern) {
 526         return shouldMatchByLine(getOutput(), from, to, pattern);
 527     }
 528 
 529     /**
 530      * Verify that the stdout contents of output buffer matches the
 531      * {@code pattern} line by line. The whole stdout could be matched or
 532      * just a subset of it.
 533      *
 534      * @param from
 535      *            The line from where stdout will be matched.
 536      *            Set {@code from} to null for matching from the first line.
 537      * @param to
 538      *            The line until where stdout will be matched.
 539      *            Set {@code to} to null for matching until the last line.
 540      * @param pattern
 541      *            Matching pattern
 542      * @return Count of lines which match the {@code pattern}
 543      */
 544     public int stdoutShouldMatchByLine(String from, String to, String pattern) {
 545         return shouldMatchByLine(getStdout(), from, to, pattern);
 546     }
 547 
 548     private int shouldMatchByLine(String buffer, String from, String to, String pattern) {
 549         List<String> lines = asLines(buffer);
 550 
 551         int fromIndex = 0;
 552         if (from != null) {
 553             fromIndex = indexOf(lines, from);
 554             assertGreaterThan(fromIndex, -1,
 555                     "The line/pattern '" + from + "' from where the output should match can not be found");
 556         }
 557 
 558         int toIndex = lines.size();
 559         if (to != null) {
 560             toIndex = indexOf(lines, to);
 561             assertGreaterThan(toIndex, -1,
 562                     "The line/pattern '" + to + "' until where the output should match can not be found");
 563         }
 564 
 565         List<String> subList = lines.subList(fromIndex, toIndex);
 566         int matchedCount = 0;
 567         for (String line : subList) {
 568             assertTrue(line.matches(pattern),
 569                     "The line '" + line + "' does not match pattern '" + pattern + "'");
 570             matchedCount++;
 571         }
 572 
 573         return matchedCount;
 574     }
 575 
 576 }