    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    }