/*
* Copyright (C) 2013 lee
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.lee.echo360.test.builders;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import org.hamcrest.Matcher;
import org.hamcrest.core.IsAnything;
import org.hamcrest.core.IsEqual;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
/**
*
* @author lee
*/
public final class OrderedPcsBuilder {
private int max;
private int current = 0;
private final List<PceMatcher> validPCE = new ArrayList<PceMatcher>();
private final Listener listener = new Listener();
protected OrderedPcsBuilder() {
this(Integer.MAX_VALUE);
}
protected OrderedPcsBuilder(int max) {
this.max = max;
}
public OrderedPcsBuilder addEvent(Object source, String name, Object old, Object newO) {
return addMatchedEvent(new IsEqual<Object>(source),
new IsEqual<String>(name),
new IsEqual<Object>(old),
new IsEqual<Object>(newO));
}
public OrderedPcsBuilder addEvent(String name, Object old, Object newO) {
return addMatchedEvent(new IsEqual<String>(name),
new IsEqual<Object>(old),
new IsEqual<Object>(newO));
}
/**
* Adds an event using the same {@code source} and {@code name} that uses
* the previous matching event's {@code newValue}. If no previous events
* match the name, any {@code previous} is used.
* @param name Name to match events against.
* @param newO New value to check for.
* @return
*/
public OrderedPcsBuilder addFollowingEvent(Object source, String name, Object newO) {
return addFollowingMatchedEvent(new IsEqual<Object>(source),
new IsEqual<String>(name),
new IsEqual<Object>(newO));
}
/**
* Adds an event using the same name as {@code name} that uses the previous
* event's {@code newValue}. If no previous events match the name, any
* {@code source} and {@code previous} is used.
* @param name Name to match events against.
* @param newO New value to check for.
* @return
*/
public OrderedPcsBuilder addFollowingEvent(String name, Object newO) {
return addFollowingMatchedEvent(new IsEqual<String>(name), new IsEqual<Object>(newO));
}
public OrderedPcsBuilder addFollowingEvent(Object newO) {
return addFollowingMatchedEvent(new IsEqual<Object>(newO));
}
public OrderedPcsBuilder addMatchedEvent(Matcher<?> source, Matcher<String> name, Matcher<?> old, Matcher<?> newM) {
validPCE.add(new PceMatcher(source, name, old, newM));
return this;
}
private OrderedPcsBuilder addMatchedEvent(Matcher<String> name, Matcher<?> old, Matcher<?> newM) {
for (int i = validPCE.size() - 1; i >= 0; i--) {
PceMatcher l = validPCE.get(i);
return addMatchedEvent(l.getSource(), name, old, newM);
}
return addMatchedEvent(new IsAnything<Object>("Event Source"), name, old, newM);
}
private OrderedPcsBuilder addFollowingMatchedEvent(Matcher<Object> source, Matcher<String> name, Matcher<Object> newM) {
for (int i = validPCE.size() - 1; i >= 0; i--) {
PceMatcher l = validPCE.get(i);
if (l.getSource().equals(source) && l.getName().equals(name)) {
return addMatchedEvent(l.getSource(), name, l.getOld(), newM);
}
}
return addMatchedEvent(new IsAnything<Object>("Event Source"), name, new IsAnything<Object>("Old Value"), newM);
}
private OrderedPcsBuilder addFollowingMatchedEvent(IsEqual<String> name, IsEqual<Object> newM) {
for (int i = validPCE.size() - 1; i >= 0; i--) {
PceMatcher l = validPCE.get(i);
if (l.getName().equals(name)) {
return addMatchedEvent(l.getSource(), name, l.getOld(), newM);
}
}
return addMatchedEvent(new IsAnything<Object>(), name, new IsAnything<Object>(), newM);
}
private OrderedPcsBuilder addFollowingMatchedEvent(IsEqual<Object> newM) {
for (int i = validPCE.size() - 1; i >= 0; i--) {
PceMatcher l = validPCE.get(i);
return addMatchedEvent(l.getSource(), l.getName(), l.getNew(), newM);
}
return addMatchedEvent(new IsAnything<Object>(), new IsAnything<String>(), new IsAnything<Object>(), newM);
}
/**
* Takes last {@linkplain #addEvent(java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object) } or {@linkplain #addMatchedEvent(org.hamcrest.Matcher, org.hamcrest.Matcher, org.hamcrest.Matcher, org.hamcrest.Matcher) } and repeats it {@code times} times
* @param times The number of times to repeat the last event. If {@code times < 2} then does nothing.
* @return this {@link OrderedPcsBuilder}
*/
public OrderedPcsBuilder times(int times) {
PceMatcher get = validPCE.get(validPCE.size() - 1);
for (int i = 1; i < times; i++) {
validPCE.add(get);
}
return this;
}
public PropertyChangeListener build() {
if (max != Integer.MAX_VALUE) {
assertEquals("Too Many or Too Few event matchers", max, validPCE.size());
} else {
max = validPCE.size();
}
return listener;
}
public void assertAllInteractions() {
assertEquals("Too Many or Too Few event firings", max, current);
}
public int getEventCount() {
return current;
}
private class Listener implements PropertyChangeListener {
public Listener() {
}
public void propertyChange(PropertyChangeEvent evt) {
if (current >= max || current >= validPCE.size()) {
fail("Property Change fired too many times(max=" + max + ", This fire: " + evt);
}
if (!validPCE.get(current).checkEvent(evt)) {
// Woops
fail("The event \"" + evt + "\" is not valid. The matcher " + validPCE.get(current) + " (at " + current + ") has rejected it.\nMatchers:\n\t" + validPCE);
}
current++;
}
}
}