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 }