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 AtomicInteger assumptionFailureCount;
032        private final CopyOnWriteArrayList<Failure> failures;
033        private final AtomicLong runTime;
034        private final AtomicLong startTime;
035    
036        /** Only set during deserialization process. */
037        private SerializedForm serializedForm;
038    
039        public Result() {
040            count = new AtomicInteger();
041            ignoreCount = new AtomicInteger();
042            assumptionFailureCount = new AtomicInteger();
043            failures = new CopyOnWriteArrayList<Failure>();
044            runTime = new AtomicLong();
045            startTime = new AtomicLong();
046        }
047    
048        private Result(SerializedForm serializedForm) {
049            count = serializedForm.fCount;
050            ignoreCount = serializedForm.fIgnoreCount;
051            assumptionFailureCount = serializedForm.assumptionFailureCount;
052            failures = new CopyOnWriteArrayList<Failure>(serializedForm.fFailures);
053            runTime = new AtomicLong(serializedForm.fRunTime);
054            startTime = new AtomicLong(serializedForm.fStartTime);
055        }
056    
057        /**
058         * Returns the number of tests run
059         */
060        public int getRunCount() {
061            return count.get();
062        }
063    
064        /**
065         * Returns the number of tests that failed during the run
066         */
067        public int getFailureCount() {
068            return failures.size();
069        }
070    
071        /**
072         * Returns the number of milliseconds it took to run the entire suite to run
073         */
074        public long getRunTime() {
075            return runTime.get();
076        }
077    
078        /**
079         * Returns the {@link Failure}s describing tests that failed and the problems they encountered
080         */
081        public List<Failure> getFailures() {
082            return failures;
083        }
084    
085        /**
086         * @return the number of tests ignored during the run
087         */
088        public int getIgnoreCount() {
089            return ignoreCount.get();
090        }
091    
092        /**
093         * Returns the number of tests skipped because of an assumption failure
094         *
095         * @throws UnsupportedOperationException if the result was serialized in a version before JUnit 4.13
096         * @since 4.13
097         */
098        public int getAssumptionFailureCount() {
099            if (assumptionFailureCount == null) {
100                throw new UnsupportedOperationException(
101                        "Result was serialized from a version of JUnit that doesn't support this method");
102            }
103            return assumptionFailureCount.get();
104        }
105    
106        /**
107         * @return <code>true</code> if all tests succeeded
108         */
109        public boolean wasSuccessful() {
110            return getFailureCount() == 0;
111        }
112    
113        private void writeObject(ObjectOutputStream s) throws IOException {
114            SerializedForm serializedForm = new SerializedForm(this);
115            serializedForm.serialize(s);
116        }
117    
118        private void readObject(ObjectInputStream s)
119                throws ClassNotFoundException, IOException {
120            serializedForm = SerializedForm.deserialize(s);
121        }
122    
123        private Object readResolve()  {
124            return new Result(serializedForm);
125        }
126    
127        @RunListener.ThreadSafe
128        private class Listener extends RunListener {
129            @Override
130            public void testRunStarted(Description description) throws Exception {
131                startTime.set(System.currentTimeMillis());
132            }
133    
134            @Override
135            public void testRunFinished(Result result) throws Exception {
136                long endTime = System.currentTimeMillis();
137                runTime.addAndGet(endTime - startTime.get());
138            }
139    
140            @Override
141            public void testFinished(Description description) throws Exception {
142                count.getAndIncrement();
143            }
144    
145            @Override
146            public void testFailure(Failure failure) throws Exception {
147                failures.add(failure);
148            }
149    
150            @Override
151            public void testIgnored(Description description) throws Exception {
152                ignoreCount.getAndIncrement();
153            }
154    
155            @Override
156            public void testAssumptionFailure(Failure failure) {
157                assumptionFailureCount.getAndIncrement();
158            }
159        }
160    
161        /**
162         * Internal use only.
163         */
164        public RunListener createListener() {
165            return new Listener();
166        }
167    
168        /**
169         * Represents the serialized output of {@code Result}. The fields on this
170         * class match the files that {@code Result} had in JUnit 4.11.
171         */
172        private static class SerializedForm implements Serializable {
173            private static final long serialVersionUID = 1L;
174            private final AtomicInteger fCount;
175            private final AtomicInteger fIgnoreCount;
176            private final AtomicInteger assumptionFailureCount;
177            private final List<Failure> fFailures;
178            private final long fRunTime;
179            private final long fStartTime;
180    
181            public SerializedForm(Result result) {
182                fCount = result.count;
183                fIgnoreCount = result.ignoreCount;
184                assumptionFailureCount = result.assumptionFailureCount;
185                fFailures = Collections.synchronizedList(new ArrayList<Failure>(result.failures));
186                fRunTime = result.runTime.longValue();
187                fStartTime = result.startTime.longValue();
188            }
189    
190            @SuppressWarnings("unchecked")
191            private SerializedForm(ObjectInputStream.GetField fields) throws IOException {
192                fCount = (AtomicInteger) fields.get("fCount", null);
193                fIgnoreCount = (AtomicInteger) fields.get("fIgnoreCount", null);
194                assumptionFailureCount = (AtomicInteger) fields.get("assumptionFailureCount", null);
195                fFailures = (List<Failure>) fields.get("fFailures", null);
196                fRunTime = fields.get("fRunTime", 0L);
197                fStartTime = fields.get("fStartTime", 0L);
198            }
199    
200            public void serialize(ObjectOutputStream s) throws IOException {
201                ObjectOutputStream.PutField fields = s.putFields();
202                fields.put("fCount", fCount);
203                fields.put("fIgnoreCount", fIgnoreCount);
204                fields.put("fFailures", fFailures);
205                fields.put("fRunTime", fRunTime);
206                fields.put("fStartTime", fStartTime);
207                fields.put("assumptionFailureCount", assumptionFailureCount);
208                s.writeFields();
209            }
210    
211            public static SerializedForm deserialize(ObjectInputStream s)
212                    throws ClassNotFoundException, IOException {
213                ObjectInputStream.GetField fields = s.readFields();
214                return new SerializedForm(fields);
215            }
216        }
217    }