|
|||||||||||||||||||
| Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
| EventSequence.java | 28.6% | 35% | 34.8% | 33.3% |
|
||||||||||||||
| 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 | } |
|
||||||||||