Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 240   Methods: 23
NCLOC: 113   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
EventSequence.java 28.6% 35% 34.8% 33.3%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK*
 2   
 3    PLT Utilities BSD License
 4   
 5    Copyright (c) 2007-2010 JavaPLT group at Rice University
 6    All rights reserved.
 7   
 8    Developed by: Java Programming Languages Team
 9    Rice University
 10    http://www.cs.rice.edu/~javaplt/
 11   
 12    Redistribution and use in source and binary forms, with or without modification, are permitted
 13    provided that the following conditions are met:
 14   
 15    - Redistributions of source code must retain the above copyright notice, this list of conditions
 16    and the following disclaimer.
 17    - Redistributions in binary form must reproduce the above copyright notice, this list of
 18    conditions and the following disclaimer in the documentation and/or other materials provided
 19    with the distribution.
 20    - Neither the name of the JavaPLT group, Rice University, nor the names of the library's
 21    contributors may be used to endorse or promote products derived from this software without
 22    specific prior written permission.
 23   
 24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 25    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 26    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND
 27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 30    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 31    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32   
 33    *END_COPYRIGHT_BLOCK*/
 34   
 35    package edu.rice.cs.plt.debug;
 36   
 37    import java.util.List;
 38    import java.util.LinkedList;
 39    import java.util.Arrays;
 40    import java.util.Iterator;
 41    import edu.rice.cs.plt.collect.CollectUtil;
 42    import edu.rice.cs.plt.iter.AbstractIterable;
 43    import edu.rice.cs.plt.iter.SizedIterable;
 44    import edu.rice.cs.plt.iter.IterUtil;
 45    import edu.rice.cs.plt.iter.ImmutableIterator;
 46    import edu.rice.cs.plt.tuple.Option;
 47    import edu.rice.cs.plt.tuple.Pair;
 48   
 49    /**
 50    * <p>A sequence of "events" used to record and verify program behavior, especially when this
 51    * behavior is effect-based. In typical usage, an instance is created as part of a stub
 52    * which records events rather than performing normal actions. An "event" may be represented
 53    * simply by a string, or by a more complex object. Given a stub, the driving code is then
 54    * run, and afterwards the contents of the EventSequence is verified.</p>
 55    *
 56    * <p>Concurrent access is supported.</p>
 57    */
 58    public class EventSequence<T> extends AbstractIterable<T> implements SizedIterable<T> {
 59   
 60    private final List<T> _events; // should always be accessed after synchronizing
 61   
 62  3 public EventSequence() {
 63    // we don't use Collections.synchronizedList() because we prefer to have direct control
 64    // over synchronization (the behavior of the Collections implementation is hazy, for
 65    // example, on the atomicity of addAll
 66  3 _events = new LinkedList<T>();
 67    }
 68   
 69  0 public boolean isEmpty() { return false; }
 70  0 public int size() { return _events.size(); }
 71  0 public int size(int bound) { return IterUtil.sizeOf(_events, bound); }
 72  0 public boolean isInfinite() { return false; }
 73  0 public boolean hasFixedSize() { return false; }
 74  0 public boolean isStatic() { return false; }
 75   
 76  0 public Iterator<T> iterator() { return new ImmutableIterator<T>(_events.iterator()); }
 77   
 78    /** Record a sequence of events. The entire sequence is recorded atomically. */
 79  29 public void record(T... events) { record(Arrays.asList(events)); }
 80   
 81    /** Record a sequence of events. The entire sequence is recorded atomically. */
 82  29 public void record(Iterable<? extends T> events) {
 83  29 synchronized (_events) {
 84  29 _events.addAll(CollectUtil.asCollection(events));
 85    }
 86    }
 87   
 88    /**
 89    * Assert that the event sequence is empty. If not, throw an AssertionError describing the first
 90    * unexpected event.
 91    */
 92  9 public void assertEmpty() {
 93  9 synchronized (_events) {
 94  0 if (!_events.isEmpty()) { throw new AssertionError("Unexpected event: " + _events.get(0)); }
 95    }
 96    }
 97   
 98    /**
 99    * Assert that the event sequence is empty. If not, throw an AssertionError with the given
 100    * message.
 101    */
 102  0 public void assertEmpty(String message) {
 103  0 synchronized (_events) {
 104  0 if (!_events.isEmpty()) { throw new AssertionError(message); }
 105    }
 106    }
 107   
 108    /**
 109    * Assert that each of the given events have been recorded. Remove all events that do appear. If
 110    * any do not, throw an AssertionError describing the first missing event. All events are removed
 111    * atomically.
 112    */
 113  0 public void assertOccurance(T... expectedEvents) { assertOccurance(Arrays.asList(expectedEvents)); }
 114   
 115    /**
 116    * Assert that each of the given events have been recorded. Remove all events that do appear. If
 117    * any do not, throw an AssertionError describing the first missing event. All events are removed
 118    * atomically.
 119    */
 120  0 public void assertOccurance(Iterable<? extends T> expectedEvents) {
 121  0 Option<T> missing = checkOccurance(expectedEvents);
 122  0 if (missing.isSome()) {
 123  0 throw new AssertionError("Event " + missing.unwrap() + " did not occur");
 124    }
 125    }
 126   
 127    /**
 128    * Assert that each of the given events have been recorded. Remove all events that do appear. If
 129    * any do not, throw an AssertionError with the given message. All events are removed atomically.
 130    */
 131  0 public void assertOccurance(String message, Iterable<? extends T> expectedEvents) {
 132  0 Option<T> missing = checkOccurance(expectedEvents);
 133  0 if (missing.isSome()) {
 134  0 throw new AssertionError(message);
 135    }
 136    }
 137   
 138    /** Implementation for assertOccurance. Returns the first missing element (if any). */
 139  0 private Option<T> checkOccurance(Iterable<? extends T> expectedEvents) {
 140  0 Option<T> missing = Option.none();
 141  0 synchronized (_events) {
 142  0 for (T expected : expectedEvents) {
 143  0 boolean removed = _events.remove(expected);
 144  0 if (!removed && missing.isNone()) { missing = Option.some(expected); }
 145    }
 146    }
 147  0 return missing;
 148    }
 149   
 150    /**
 151    * Assert that the given sequence of events was recorded (starting at the beginning). Remove
 152    * the matching subsequence. If there is a mismatch, throw an AssertionError describing it.
 153    * All events are removed atomically.
 154    */
 155  0 public void assertSequence(T... expectedEvents) { assertSequence(Arrays.asList(expectedEvents)); }
 156   
 157    /**
 158    * Assert that the given sequence of events was recorded (starting at the beginning). Remove
 159    * the matching subsequence. If there is a mismatch, throw an AssertionError describing it.
 160    * All events are removed atomically.
 161    */
 162  10 public void assertSequence(Iterable<? extends T> expectedEvents) {
 163  10 Option<Pair<T, Option<T>>> mismatched = checkSequence(expectedEvents);
 164  10 if (mismatched.isSome()) {
 165  0 Pair<T, Option<T>> pair = mismatched.unwrap();
 166  0 if (pair.second().isSome()) {
 167  0 throw new AssertionError("Unexpected event. Expected: " + pair.first() +
 168    "; Actual: " + pair.second().unwrap());
 169    }
 170    else {
 171  0 throw new AssertionError("Event " + pair.first() + " did not occur");
 172    }
 173    }
 174    }
 175   
 176    /**
 177    * Assert that the given sequence of events was recorded (starting at the beginning). Remove
 178    * the matching subsequence. If there is a mismatch, throw an AssertionError with the given
 179    * message. All events are removed atomically.
 180    */
 181  0 public void assertSequence(String message, Iterable<? extends T> expectedEvents) {
 182  0 Option<?> mismatched = checkSequence(expectedEvents);
 183  0 if (mismatched.isSome()) {
 184  0 throw new AssertionError(message);
 185    }
 186    }
 187   
 188    /**
 189    * Implementation of assertSequence. Returns the first mismatched expected/actual pair, if any.
 190    * If the actual sequence is too short, the second pair element is empty.
 191    */
 192  10 private Option<Pair<T, Option<T>>> checkSequence(Iterable<? extends T> expectedEvents) {
 193  10 Iterator<? extends T> expected = expectedEvents.iterator();
 194  10 synchronized (_events) {
 195  10 Iterator<? extends T> actual = _events.iterator();
 196  10 while (expected.hasNext() && actual.hasNext()) {
 197  29 T exp = expected.next();
 198  29 T act = actual.next();
 199  29 if (exp == null ? act == null : exp.equals(act)) {
 200  29 actual.remove();
 201    }
 202  0 else { return Option.some(Pair.make(exp, Option.some(act))); }
 203    }
 204    }
 205  10 if (expected.hasNext()) {
 206  0 return Option.some(Pair.<T, Option<T>>make(expected.next(), Option.<T>none()));
 207    }
 208  10 return Option.none();
 209    }
 210   
 211    /**
 212    * Assert that the given sequence of events, and only that sequence, was recorded (starting
 213    * at the beginning). Remove the matching subsequence. If there is a mismatch, throw an
 214    * AssertionError describing it. All events are removed atomically.
 215    */
 216  10 public void assertContents(T... expectedEvents) { assertContents(Arrays.asList(expectedEvents)); }
 217   
 218    /**
 219    * Assert that the given sequence of events, and only that sequence, was recorded (starting
 220    * at the beginning). Remove the matching subsequence. If there is a mismatch, throw an
 221    * AssertionError describing it. All events are removed atomically.
 222    */
 223  10 public void assertContents(Iterable<? extends T> expectedEvents) {
 224  10 assertSequence(expectedEvents);
 225  10 if (!_events.isEmpty()) {
 226  0 throw new AssertionError("Unexpected additional event: " + _events.get(0));
 227    }
 228    }
 229   
 230    /**
 231    * Assert that the given sequence of events, and only that sequence, was recorded (starting
 232    * at the beginning). Remove the matching subsequence. If there is a mismatch, throw an
 233    * AssertionError with the given message. All events are removed atomically.
 234    */
 235  0 public void assertContents(String message, Iterable<? extends T> expectedEvents) {
 236  0 assertSequence(message, expectedEvents);
 237  0 if (!_events.isEmpty()) { throw new AssertionError(message); }
 238    }
 239   
 240    }