001 package org.junit.runner;
002
003 import java.io.IOException;
004 import java.io.ObjectInputStream;
005 import java.io.ObjectOutputStream;
006 import java.io.ObjectStreamClass;
007 import java.io.ObjectStreamField;
008 import java.io.Serializable;
009 import java.util.ArrayList;
010 import java.util.Collections;
011 import java.util.List;
012 import java.util.concurrent.CopyOnWriteArrayList;
013 import java.util.concurrent.atomic.AtomicInteger;
014 import java.util.concurrent.atomic.AtomicLong;
015
016 import org.junit.runner.notification.Failure;
017 import org.junit.runner.notification.RunListener;
018
019 /**
020 * A <code>Result</code> collects and summarizes information from running multiple tests.
021 * All tests are counted -- additional information is collected from tests that fail.
022 *
023 * @since 4.0
024 */
025 public class Result implements Serializable {
026 private static final long serialVersionUID = 1L;
027 private static final ObjectStreamField[] serialPersistentFields =
028 ObjectStreamClass.lookup(SerializedForm.class).getFields();
029 private final AtomicInteger count;
030 private final AtomicInteger ignoreCount;
031 private final CopyOnWriteArrayList<Failure> failures;
032 private final AtomicLong runTime;
033 private final AtomicLong startTime;
034
035 /** Only set during deserialization process. */
036 private SerializedForm serializedForm;
037
038 public Result() {
039 count = new AtomicInteger();
040 ignoreCount = new AtomicInteger();
041 failures = new CopyOnWriteArrayList<Failure>();
042 runTime = new AtomicLong();
043 startTime = new AtomicLong();
044 }
045
046 private Result(SerializedForm serializedForm) {
047 count = serializedForm.fCount;
048 ignoreCount = serializedForm.fIgnoreCount;
049 failures = new CopyOnWriteArrayList<Failure>(serializedForm.fFailures);
050 runTime = new AtomicLong(serializedForm.fRunTime);
051 startTime = new AtomicLong(serializedForm.fStartTime);
052 }
053
054 /**
055 * @return the number of tests run
056 */
057 public int getRunCount() {
058 return count.get();
059 }
060
061 /**
062 * @return the number of tests that failed during the run
063 */
064 public int getFailureCount() {
065 return failures.size();
066 }
067
068 /**
069 * @return the number of milliseconds it took to run the entire suite to run
070 */
071 public long getRunTime() {
072 return runTime.get();
073 }
074
075 /**
076 * @return the {@link Failure}s describing tests that failed and the problems they encountered
077 */
078 public List<Failure> getFailures() {
079 return failures;
080 }
081
082 /**
083 * @return the number of tests ignored during the run
084 */
085 public int getIgnoreCount() {
086 return ignoreCount.get();
087 }
088
089 /**
090 * @return <code>true</code> if all tests succeeded
091 */
092 public boolean wasSuccessful() {
093 return getFailureCount() == 0;
094 }
095
096 private void writeObject(ObjectOutputStream s) throws IOException {
097 SerializedForm serializedForm = new SerializedForm(this);
098 serializedForm.serialize(s);
099 }
100
101 private void readObject(ObjectInputStream s)
102 throws ClassNotFoundException, IOException {
103 serializedForm = SerializedForm.deserialize(s);
104 }
105
106 private Object readResolve() {
107 return new Result(serializedForm);
108 }
109
110 @RunListener.ThreadSafe
111 private class Listener extends RunListener {
112 @Override
113 public void testRunStarted(Description description) throws Exception {
114 startTime.set(System.currentTimeMillis());
115 }
116
117 @Override
118 public void testRunFinished(Result result) throws Exception {
119 long endTime = System.currentTimeMillis();
120 runTime.addAndGet(endTime - startTime.get());
121 }
122
123 @Override
124 public void testFinished(Description description) throws Exception {
125 count.getAndIncrement();
126 }
127
128 @Override
129 public void testFailure(Failure failure) throws Exception {
130 failures.add(failure);
131 }
132
133 @Override
134 public void testIgnored(Description description) throws Exception {
135 ignoreCount.getAndIncrement();
136 }
137
138 @Override
139 public void testAssumptionFailure(Failure failure) {
140 // do nothing: same as passing (for 4.5; may change in 4.6)
141 }
142 }
143
144 /**
145 * Internal use only.
146 */
147 public RunListener createListener() {
148 return new Listener();
149 }
150
151 /**
152 * Represents the serialized output of {@code Result}. The fields on this
153 * class match the files that {@code Result} had in JUnit 4.11.
154 */
155 private static class SerializedForm implements Serializable {
156 private static final long serialVersionUID = 1L;
157 private final AtomicInteger fCount;
158 private final AtomicInteger fIgnoreCount;
159 private final List<Failure> fFailures;
160 private final long fRunTime;
161 private final long fStartTime;
162
163 public SerializedForm(Result result) {
164 fCount = result.count;
165 fIgnoreCount = result.ignoreCount;
166 fFailures = Collections.synchronizedList(new ArrayList<Failure>(result.failures));
167 fRunTime = result.runTime.longValue();
168 fStartTime = result.startTime.longValue();
169 }
170
171 @SuppressWarnings("unchecked")
172 private SerializedForm(ObjectInputStream.GetField fields) throws IOException {
173 fCount = (AtomicInteger) fields.get("fCount", null);
174 fIgnoreCount = (AtomicInteger) fields.get("fIgnoreCount", null);
175 fFailures = (List<Failure>) fields.get("fFailures", null);
176 fRunTime = fields.get("fRunTime", 0L);
177 fStartTime = fields.get("fStartTime", 0L);
178 }
179
180 public void serialize(ObjectOutputStream s) throws IOException {
181 ObjectOutputStream.PutField fields = s.putFields();
182 fields.put("fCount", fCount);
183 fields.put("fIgnoreCount", fIgnoreCount);
184 fields.put("fFailures", fFailures);
185 fields.put("fRunTime", fRunTime);
186 fields.put("fStartTime", fStartTime);
187 s.writeFields();
188 }
189
190 public static SerializedForm deserialize(ObjectInputStream s)
191 throws ClassNotFoundException, IOException {
192 ObjectInputStream.GetField fields = s.readFields();
193 return new SerializedForm(fields);
194 }
195 }
196 }