1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package vogar.expect;
18 
19 import com.google.common.collect.Lists;
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.util.Arrays;
23 import java.util.Date;
24 import java.util.List;
25 import vogar.expect.util.Strings;
26 
27 /**
28  * An outcome of an action. Some actions may have multiple outcomes. For
29  * example, JUnit tests have one outcome for each test method.
30  */
31 public final class Outcome {
32 
33     private final String outcomeName;
34     private final Result result;
35     private final String output;
36     private final Date date;
37 
Outcome(String outcomeName, Result result, List<String> outputLines)38     public Outcome(String outcomeName, Result result, List<String> outputLines) {
39         this.outcomeName = outcomeName;
40         this.result = result;
41         this.output = sanitizeOutputLines(outputLines);
42         this.date = new Date();
43     }
44 
Outcome(String outcomeName, Result result, String outputLine, Date date)45     public Outcome(String outcomeName, Result result, String outputLine, Date date) {
46         this.outcomeName = outcomeName;
47         this.result = result;
48         this.output = sanitizeOutputLine(outputLine);
49         this.date = date;
50     }
51 
Outcome(String outcomeName, Result result, String outputLine)52     public Outcome(String outcomeName, Result result, String outputLine) {
53         this.outcomeName = outcomeName;
54         this.result = result;
55         this.output = sanitizeOutputLine(outputLine);
56         this.date = new Date();
57     }
58 
Outcome(String outcomeName, Result result, Throwable throwable)59     public Outcome(String outcomeName, Result result, Throwable throwable) {
60         this.outcomeName = outcomeName;
61         this.result = result;
62         this.output = sanitizeOutputLines(throwableToLines(throwable));
63         this.date = new Date();
64     }
65 
sanitizeOutputLines(List<String> outputLines)66     private String sanitizeOutputLines(List<String> outputLines) {
67         List<String> sanitizedStrings = Lists.newArrayList();
68         for (String line : outputLines) {
69             sanitizedStrings.add(sanitizeOutputLine(line));
70         }
71         return Strings.join(sanitizedStrings, "\n");
72     }
73 
sanitizeOutputLine(String outputLine)74     private String sanitizeOutputLine(String outputLine) {
75         return Strings.xmlSanitize(outputLine.replaceAll("\r\n?", "\n"));
76     }
77 
getDate()78     public Date getDate() {
79         return date;
80     }
81 
getName()82     public String getName() {
83         return outcomeName;
84     }
85 
getResult()86     public Result getResult() {
87         return result;
88     }
89 
getOutput()90     public String getOutput() {
91         return output;
92     }
93 
getOutputLines()94     public List<String> getOutputLines() {
95         return Arrays.asList(output.split("\n"));
96     }
97 
throwableToLines(Throwable t)98     private static List<String> throwableToLines(Throwable t) {
99         StringWriter writer = new StringWriter();
100         PrintWriter out = new PrintWriter(writer);
101         t.printStackTrace(out);
102         return Arrays.asList(writer.toString().split("\\n"));
103     }
104 
105     /**
106      * Returns the action's suite name, such as java.lang.Integer or
107      * java.lang.IntegerTest.
108      */
getSuiteName()109     public String getSuiteName() {
110         int split = split(outcomeName);
111         return split == -1 ? "defaultpackage" : outcomeName.substring(0, split);
112     }
113 
114     /**
115      * Returns the specific action name, such as BitTwiddle or testBitTwiddle.
116      */
getTestName()117     public String getTestName() {
118         int split = split(outcomeName);
119         return split == -1 ? outcomeName : outcomeName.substring(split + 1);
120     }
121 
split(String name)122     private static int split(String name) {
123         int lastHash = name.indexOf('#');
124         return lastHash == -1 ? name.lastIndexOf('.') : lastHash;
125     }
126 
127     /**
128      * Returns whether the result indicates that the contents of the Outcome are important.
129      *
130      * For example, for a test skipped because it is unsupported, we don't care about the result.
131      */
matters()132     private boolean matters() {
133         return result != Result.UNSUPPORTED;
134     }
135 
getResultValue(Expectation expectation)136     public ResultValue getResultValue(Expectation expectation) {
137         if (matters()) {
138             return expectation.matches(this) ? ResultValue.OK : ResultValue.FAIL;
139         }
140         return ResultValue.IGNORE;
141     }
142 
143     /**
144      * Returns a filesystem db path for this outcome. For example, a path for an outcome with name
145      * "foo.bar.baz#testName" would be "foo/bar/baz/testName".
146      */
getPath()147     public String getPath() {
148         return outcomeName.replaceAll("[\\.#]", "/");
149     }
150 
equals(Object o)151     @Override public boolean equals(Object o) {
152         if (o instanceof Outcome) {
153             Outcome outcome = (Outcome) o;
154             return outcomeName.equals(outcome.outcomeName)
155                     && result == outcome.result
156                     && output.equals(outcome.output);
157         }
158         return false;
159     }
160 
hashCode()161     @Override public int hashCode() {
162         int hashCode = 17;
163         hashCode = 37 * hashCode + outcomeName.hashCode();
164         hashCode  = 37 * hashCode + result.hashCode();
165         hashCode = 37 * hashCode + output.hashCode();
166         return hashCode;
167     }
168 
toString()169     @Override public String toString() {
170         return "Outcome[name=" + outcomeName + " output=" + output + "]";
171     }
172 
173 }
174