Merge pull request #1 from msmock/master

Value Framework
This commit is contained in:
Robert von Burg 2012-12-11 00:32:57 -08:00
commit 39e2eee613
19 changed files with 1435 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,45 @@
package li.strolch.model.timedstate;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.ITimeVariable;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
/**
* A time based state characterized by a {@link IValue} object implementation.
*
* @author martin_smock
*
* @param <T>
* IValue implementation representing the state at a given time
*/
@SuppressWarnings("rawtypes")
public interface ITimedState<T extends IValue> {
/**
* @return the new {@link ITimeValue} matching the value in the future
*/
ITimeValue<T> getNextMatch(final Long time, T value);
/**
* @return the new {@link ITimeValue} matching the value in the future
*/
ITimeValue<T> getPreviousMatch(final Long time, T value);
/**
* @param change
* the state change to be applied
*/
void applyChange(final IValueChange<T> change);
/**
* @return the state at the given time
*/
ITimeValue<T> getStateAt(final Long time);
/**
* @return get the states evolution in time
*/
ITimeVariable<T> getTimeEvolution();
}

View File

@ -0,0 +1,64 @@
package li.strolch.model.timedstate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.ITimeVariable;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.TimeVariable;
/**
* @author martin_smock
*/
@SuppressWarnings("rawtypes")
public class TimedState<T extends IValue> implements ITimedState<T> {
private ITimeVariable<T> timeVariable = new TimeVariable<T>();
@Override
@SuppressWarnings("unchecked")
public ITimeValue<T> getNextMatch(final Long time, final T value) {
Collection<ITimeValue<T>> futureValues = timeVariable.getFutureValues(time);
for (ITimeValue<T> iTimeValue : futureValues) {
if (iTimeValue.getValue().matches(value)) {
return iTimeValue;
}
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public ITimeValue<T> getPreviousMatch(final Long time, final T value) {
Collection<ITimeValue<T>> pastValues = timeVariable.getPastValues(time);
List<ITimeValue<T>> asList = new ArrayList<ITimeValue<T>>(pastValues);
Collections.reverse(asList);
for (ITimeValue<T> iTimeValue : asList) {
if (iTimeValue.getValue().matches(value)) {
return iTimeValue;
}
}
return null;
}
@Override
public void applyChange(final IValueChange<T> change) {
timeVariable.applyChange(change);
}
@Override
public ITimeValue<T> getStateAt(final Long time) {
return timeVariable.getValueAt(time);
}
@Override
public ITimeVariable<T> getTimeEvolution() {
return timeVariable;
}
}

View File

@ -0,0 +1,24 @@
package li.strolch.model.timevalue;
import li.strolch.model.timevalue.impl.TimeVariable;
/**
* Interface for timed value objects to be used with the {@link TimeVariable}
*
* @author martin_smock
*
* @param <T>
* the backing value of the timed value object
*/
@SuppressWarnings("rawtypes")
public interface ITimeValue<T extends IValue> extends Comparable<ITimeValue<T>> {
ITimeValue<T> setValue(final T value);
T getValue();
Long getTime();
ITimeValue<T> add(final T change);
}

View File

@ -0,0 +1,70 @@
package li.strolch.model.timevalue;
import java.util.Collection;
/**
* A timed variable storing a ordered sequence of {@link ITimeValue} objects
* modeling a time evolution of a quantity.
*
* @author martin_smock
*
* @param <T>
* the backing value of the timed value object
*/
@SuppressWarnings("rawtypes")
public interface ITimeVariable<T extends IValue> {
/**
* set the value at a point in time to a given time value object
*
* @param time
* the time to set the {@link IValue}
* @param value
* the {@link IValue} to set
*/
void setValueAt(final Long time, final T value);
/**
* get the latest {@link ITimeValue} whose time field is less or equal to
* the time given
*/
ITimeValue<T> getValueAt(final Long time);
/**
* Applies a {@link IValueChange} propagating the change to all future
* values starting from the time of the change.
*
* @param change
* the {@link IValueChange} to be applied
*/
void applyChange(final IValueChange<T> change);
/**
* Get all {@link ITimeValue} objects whose time field is greater or equal
* to the given time
*
* @param time
* the time the sequence starts with
* @return the sequence of {@link ITimeValue} objects in the future
*/
Collection<ITimeValue<T>> getFutureValues(final Long time);
/**
* Get all {@link ITimeValue} objects whose time field is strictly smaller
* than the given time
*
* @param time
* the time the sequence starts with
* @return the sequence of {@link ITimeValue} objects in the future
*/
Collection<ITimeValue<T>> getPastValues(final Long time);
/**
* removes {@link ITimeValue} objects from the sequence, where the successor
* matches value. I.e considering a pair of adjacent {@link ITimeValue}
* objects in the sequence which have the same {@link IValue}, the later one
* is removed, since it contains no additional information.
*/
void compact();
}

View File

@ -0,0 +1,41 @@
package li.strolch.model.timevalue;
/**
* A value object defining some basic algebraic operations. Mathematically
* speaking {@link IValue} objects define a group with a addition operation.
*
* @author martin_smock
*
* @param <T>
* any object for which a (generalized) add operation can be defined.
*
*/
public interface IValue<T> {
/**
* @return the backing value
*/
T getValue();
/**
* @return a value with the backing value added to the argument value
*/
IValue<T> add(T o);
/**
* @return true, if the backing values match.
*/
boolean matches(IValue<T> other);
/**
* @return the inverse value, such that add(value.getInverse()) returns the
* neutral element of the group
*/
IValue<T> getInverse();
/**
* @return a copy of this
*/
IValue<T> getCopy();
}

View File

@ -0,0 +1,28 @@
package li.strolch.model.timevalue;
/**
* Interface for operators to be used to change the values of {@link ITimeValue}
* in a {@link ITimeVariable}.
*
* @author martin_smock
*/
@SuppressWarnings("rawtypes")
public interface IValueChange<T extends IValue> {
/**
* @return the time this change has to be applied
*/
Long getTime();
/**
* @return the value of the change
*/
T getValue();
/**
* @return the inverse neutralizing a change. Very useful to undo changes
* applied.
*/
IValueChange<T> getInverse();
}

View File

@ -0,0 +1,69 @@
package li.strolch.model.timevalue.impl;
/**
* Wrapper for java.util.String object defining a inverse to support algebraic
* operations.
*
* @author martin_smock
*/
public class AString {
private final String string;
private final boolean inverse;
public AString(final String string) {
this.string = string;
this.inverse = false;
}
public AString(final String string, final boolean inverse) {
this.string = string;
this.inverse = inverse;
}
public String getString() {
return string;
}
public boolean isInverse() {
return inverse;
}
public AString getInverse() {
return new AString(string, !inverse);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (inverse ? 1231 : 1237);
result = prime * result + ((string == null) ? 0 : string.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AString other = (AString) obj;
if (inverse != other.inverse)
return false;
if (string == null) {
if (other.string != null)
return false;
} else if (!string.equals(other.string))
return false;
return true;
}
@Override
public String toString() {
return "AString [string=" + string + ", inverse=" + inverse + "]";
}
}

View File

@ -0,0 +1,94 @@
package li.strolch.model.timevalue.impl;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
/**
* {@link IValue} implementation to work with Double valued {@link ITimeValue} objects
*
* @author martin_smock
*/
public class DoubleValue implements IValue<Double> {
public static final DoubleValue NEUTRAL = new DoubleValue(0.0d);
private Double value;
public DoubleValue(Double value) {
this.value = value;
}
public DoubleValue(double value) {
this.value = Double.valueOf(value);
}
public DoubleValue(Integer value) {
this.value = this.value.doubleValue();
}
public DoubleValue(int value) {
this.value = Integer.valueOf(value).doubleValue();
}
public DoubleValue(String valueAsString) throws NumberFormatException {
this.value = Double.parseDouble(valueAsString);
}
@Override
public DoubleValue add(Double o) {
value += o;
return this;
}
@Override
public Double getValue() {
return value;
}
@Override
public String toString() {
return "DoubleValue [value=" + value + "]";
}
@Override
public boolean matches(IValue<Double> other) {
return this.value.equals(other.getValue());
}
@Override
public DoubleValue getInverse() {
return new DoubleValue(-getValue());
}
@Override
public DoubleValue getCopy(){
return new DoubleValue(value);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DoubleValue other = (DoubleValue) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}

View File

@ -0,0 +1,86 @@
package li.strolch.model.timevalue.impl;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
/**
* {@link IValue} implementation to work with Integer valued {@link ITimeValue}
* objects
*
* @author martin_smock
*/
public class IntegerValue implements IValue<Integer> {
public static final IntegerValue NEUTRAL = new IntegerValue(0);
private Integer value;
public IntegerValue(Integer value) {
this.value = value;
}
public IntegerValue(int value) {
this.value = Integer.valueOf(value);
}
public IntegerValue(String valueAsString) throws NumberFormatException {
this.value = Integer.parseInt(valueAsString);
}
@Override
public IntegerValue add(Integer o) {
value += o;
return this;
}
@Override
public boolean matches(IValue<Integer> other) {
return this.value.equals(other.getValue());
}
@Override
public Integer getValue() {
return value;
}
@Override
public IntegerValue getInverse() {
return new IntegerValue(-getValue());
}
@Override
public String toString() {
return "IntegerValue [value=" + value + "]";
}
@Override
public IntegerValue getCopy() {
return new IntegerValue(value);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IntegerValue other = (IntegerValue) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}

View File

@ -0,0 +1,86 @@
package li.strolch.model.timevalue.impl;
import java.util.HashSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
/**
* {@link IValue} implementation to work with String valued {@link ITimeValue}
* objects. Since a java.util.String object does not define a inverse, a
* algebraic {@link AString} wrapper is used.
*
* @author martin_smock
*/
public class StringSetValue implements IValue<Set<AString>> {
private static Set<AString> neu = Collections.emptySet();
public static final IValue<Set<AString>> NEUTRAL = new StringSetValue(neu);
private Set<AString> aStrings = new HashSet<AString>();
public StringSetValue() {
}
public StringSetValue(final Set<AString> aStrings) {
this.aStrings = aStrings;
}
@Override
public Set<AString> getValue() {
return aStrings;
}
@Override
public IValue<Set<AString>> add(Set<AString> o) {
Set<AString> toBeAdded = new HashSet<AString>(o);
for (Iterator<AString> iter1 = toBeAdded.iterator(); iter1.hasNext();) {
AString toAdd = iter1.next();
for (Iterator<AString> iter = aStrings.iterator(); iter.hasNext();) {
AString aString = iter.next();
boolean valueMatch = aString.getString().equals(toAdd.getString());
boolean compensate = (toAdd.isInverse() && !aString.isInverse())
|| (!toAdd.isInverse() && aString.isInverse());
if (valueMatch && compensate) {
iter.remove();
iter1.remove();
}
}
}
aStrings.addAll(toBeAdded);
return this;
}
@Override
public boolean matches(IValue<Set<AString>> other) {
return this.getValue().equals(other.getValue());
}
@Override
public IValue<Set<AString>> getInverse() {
Set<AString> inverseSet = new HashSet<AString>();
for (AString as : aStrings) {
inverseSet.add(as.getInverse());
}
StringSetValue inverse = new StringSetValue();
inverse.aStrings = inverseSet;
return inverse;
}
@Override
public StringSetValue getCopy() {
return new StringSetValue(aStrings);
}
@Override
public String toString() {
return "StringSetValue [aStrings=" + aStrings + "]";
}
}

View File

@ -0,0 +1,90 @@
package li.strolch.model.timevalue.impl;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
/**
* @author martin_smock
*/
@SuppressWarnings("rawtypes")
public class TimeValue<T extends IValue> implements ITimeValue <T> {
protected final Long time;
protected T value;
/**
* @param time
* @param value
*/
public TimeValue(final Long time, final T value){
this.time = time;
this.value = value;
}
@Override
@SuppressWarnings("unchecked")
public T getValue() {
return (T) value.getCopy();
}
@Override
public Long getTime() {
return time;
}
@Override
public ITimeValue<T> setValue(final T value) {
this.value = value;
return this;
}
@SuppressWarnings("unchecked")
@Override
public ITimeValue<T> add(final T change) {
this.value.add(change.getValue());
return this;
}
@Override
public int compareTo(final ITimeValue<T> arg0) {
return this.getTime().compareTo(arg0.getTime());
}
@Override
public String toString() {
return "TimeValue [time=" + time + ", value=" + value + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((time == null) ? 0 : time.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
@SuppressWarnings("unchecked")
TimeValue<T> other = (TimeValue<T>) obj;
if (time == null) {
if (other.time != null)
return false;
} else if (!time.equals(other.time))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}

View File

@ -0,0 +1,98 @@
package li.strolch.model.timevalue.impl;
import java.util.Collection;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.ITimeVariable;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
/**
* @author martin_smock
*/
@SuppressWarnings("rawtypes")
public class TimeVariable<T extends IValue> implements ITimeVariable<T> {
public SortedSet<ITimeValue<T>> container = new TreeSet<ITimeValue<T>>();
@Override
public ITimeValue<T> getValueAt(final Long time) {
ITimeValue<T> tmp = null;
for (ITimeValue<T> value : container) {
if (value.getTime() <= time) {
tmp = value;
} else {
break;
}
}
return tmp;
}
@Override
public void setValueAt(final Long time, final T targetValue) {
ITimeValue<T> current = getValueAt(time);
if (current != null && current.getTime().equals(time)) {
current.setValue(targetValue);
} else {
container.add(new TimeValue<T>(time, targetValue));
}
}
@Override
public SortedSet<ITimeValue<T>> getFutureValues(final Long time) {
TimeValue<T> picker = new TimeValue<T>(time, null);
return new TreeSet<ITimeValue<T>>(container.tailSet(picker));
}
@Override
public Collection<ITimeValue<T>> getPastValues(final Long time) {
TimeValue<T> picker = new TimeValue<T>(time, null);
return new TreeSet<ITimeValue<T>>(container.headSet(picker));
}
@Override
public void applyChange(final IValueChange<T> change) {
SortedSet<ITimeValue<T>> futureValues = getFutureValues(change.getTime());
for (ITimeValue<T> value : futureValues) {
value.add(change.getValue());
}
ITimeValue<T> initialValue = getValueAt(change.getTime());
if (initialValue == null) {
ITimeValue<T> newValue = new TimeValue<T>(change.getTime(), change.getValue());
container.add(newValue);
} else if (initialValue.getTime().longValue() < change.getTime().longValue()) {
ITimeValue<T> newValue = new TimeValue<T>(change.getTime(), initialValue.getValue());
newValue.add(change.getValue());
container.add(newValue);
}
compact();
}
@SuppressWarnings("unchecked")
@Override
public void compact() {
if (container.size() < 2)
return;
Iterator<ITimeValue<T>> iterator = container.iterator();
ITimeValue<T> predecessor = iterator.next();
while (iterator.hasNext()) {
ITimeValue<T> successor = iterator.next();
if (successor.getValue().matches(predecessor.getValue())) {
iterator.remove();
} else {
predecessor = successor;
}
}
}
}

View File

@ -0,0 +1,77 @@
package li.strolch.model.timevalue.impl;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
/**
* @author martin_smock
*/
@SuppressWarnings("rawtypes")
public class ValueChange<T extends IValue> implements IValueChange<T> {
protected final Long time;
protected final T value;
/**
* @param time
* @param value
*/
public ValueChange(final Long time, final T value) {
this.time = time;
this.value = value;
}
@Override
public Long getTime() {
return time;
}
@Override
@SuppressWarnings("unchecked")
public T getValue() {
return (T) value.getCopy();
}
@Override
@SuppressWarnings("unchecked")
public IValueChange<T> getInverse() {
return new ValueChange(time, value.getInverse());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ValueChange<?> other = (ValueChange<?>) obj;
if (time == null) {
if (other.time != null)
return false;
} else if (!time.equals(other.time))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((time == null) ? 0 : time.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public String toString() {
return "ValueChange [time=" + time + ", value=" + value + "]";
}
}

View File

@ -0,0 +1,96 @@
package li.strolch.model.timedstate;
import junit.framework.Assert;
import li.strolch.model.timedstate.ITimedState;
import li.strolch.model.timedstate.TimedState;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.DoubleValue;
import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
public class TimeStateTest {
private ITimedState<DoubleValue> state = new TimedState<DoubleValue>();
final DoubleValue expectedValue1 = new DoubleValue(Double.valueOf(100D));
final DoubleValue expectedValue2 = new DoubleValue(Double.valueOf(200D));
final Long t0 = Long.valueOf(0);
final Long t10 = Long.valueOf(10);
final Long t20 = Long.valueOf(20);
final Long t30 = Long.valueOf(30);
final Long t100 = Long.valueOf(100);
@Before
public void before() {
final IValueChange<DoubleValue> change1 = new ValueChange<DoubleValue>(t10, expectedValue1);
state.applyChange(change1);
final ITimeValue<DoubleValue> stateAt9 = state.getStateAt(9L);
Assert.assertNull(stateAt9);
final ITimeValue<DoubleValue> stateAt11 = state.getStateAt(11L);
Assert.assertNotNull(stateAt11);
Assert.assertEquals(true, stateAt11.getValue().matches(expectedValue1));
final IValueChange<DoubleValue> change2 = new ValueChange<DoubleValue>(t30, expectedValue1);
state.applyChange(change2);
final ITimeValue<DoubleValue> stateAt31 = state.getStateAt(31L);
Assert.assertNotNull(stateAt31);
Assert.assertEquals(true, stateAt31.getValue().matches(expectedValue2));
}
@Test
public void testGetNextMatch() {
ITimeValue<DoubleValue> nextMatch = state.getNextMatch(t0, expectedValue1);
Assert.assertNotNull(nextMatch);
Assert.assertEquals(t10, nextMatch.getTime());
nextMatch = state.getNextMatch(t20, expectedValue1);
Assert.assertNull(nextMatch);
nextMatch = state.getNextMatch(t20, expectedValue2);
Assert.assertNotNull(nextMatch);
Assert.assertEquals(t30, nextMatch.getTime());
nextMatch = state.getNextMatch(t30, expectedValue2);
Assert.assertNotNull(nextMatch);
Assert.assertEquals(t30, nextMatch.getTime());
nextMatch = state.getNextMatch(t100, expectedValue1);
Assert.assertNull(nextMatch);
nextMatch = state.getNextMatch(t100, expectedValue2);
Assert.assertNull(nextMatch);
}
@Test
public void testGetPreviousMatch() {
ITimeValue<DoubleValue> previousMatch = state.getPreviousMatch(t100, expectedValue2);
Assert.assertNotNull(previousMatch);
Assert.assertEquals(t30, previousMatch.getTime());
previousMatch = state.getPreviousMatch(t30, expectedValue2);
Assert.assertNull(previousMatch);
previousMatch = state.getPreviousMatch(t20, expectedValue2);
Assert.assertNull(previousMatch);
previousMatch = state.getPreviousMatch(t20, expectedValue1);
Assert.assertNotNull(previousMatch);
Assert.assertEquals(t10, previousMatch.getTime());
previousMatch = state.getPreviousMatch(t10, expectedValue1);
Assert.assertNull(previousMatch);
}
}

View File

@ -0,0 +1,137 @@
package li.strolch.model.timevalue;
import java.util.Collection;
import java.util.SortedSet;
import junit.framework.Assert;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.DoubleValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
public class FloatTimeVariableTest {
private static final Long MAX = 100L;
private static final Long STEP = 10L;
private static final Long PICK = 50L;
private TimeVariable<DoubleValue> timeVariable;
/**
* set the values ascending with a difference of STEP
*/
@Before
public void init() {
timeVariable = new TimeVariable<DoubleValue>();
for (long i = 0; i < MAX; i += STEP) {
timeVariable.setValueAt(Long.valueOf(i), new DoubleValue(i));
}
}
@Test
public void testGetValueAt() {
ITimeValue<DoubleValue> valueAt = timeVariable.getValueAt(PICK);
Assert.assertEquals(PICK.doubleValue(), valueAt.getValue().getValue());
}
/**
* test, that the future values start with the PICK time and are ascending
*/
@Test
public void testGetFutureValues() {
Collection<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(PICK);
Long expectedTime = PICK;
Double expectedValue = PICK.doubleValue();
for (ITimeValue<DoubleValue> value : futureValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(value.getValue().matches(new DoubleValue(expectedValue)));
expectedTime += STEP;
expectedValue += STEP.doubleValue();
}
}
/**
* test, that the past values time fields start with 0 and are strictly
* smaller than PICK
*/
@Test
public void testGetPastValues() {
Collection<ITimeValue<DoubleValue>> pastValues = timeVariable.getPastValues(MAX);
Long expectedTime = 0L;
Double expectedValue = expectedTime.doubleValue();
for (ITimeValue<DoubleValue> value : pastValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(value.getValue().matches(new DoubleValue(expectedValue)));
expectedTime += STEP;
expectedValue += STEP.doubleValue();
}
}
/**
* apply a change and check that the future values are all changed
*/
@Test
public void testApplyChange() {
DoubleValue doubleValue = new DoubleValue(STEP.doubleValue());
IValueChange<DoubleValue> change = new ValueChange<DoubleValue>(PICK, doubleValue);
timeVariable.applyChange(change);
Collection<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(PICK);
Long expectedTime = PICK;
IValue<Double> expectedValue = new DoubleValue(PICK.doubleValue() + change.getValue().getValue());
for (ITimeValue<DoubleValue> value : futureValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(expectedValue.matches(value.getValue()));
expectedTime += STEP;
expectedValue = expectedValue.add(STEP.doubleValue());
}
}
/**
* apply a change to an empty time variable
*/
@Test
public void testApply2Change() {
timeVariable = new TimeVariable<DoubleValue>();
DoubleValue doubleValue = new DoubleValue(STEP.doubleValue());
IValueChange<DoubleValue> change = new ValueChange<DoubleValue>(PICK, doubleValue);
timeVariable.applyChange(change);
ITimeValue<DoubleValue> actual = timeVariable.getValueAt(PICK);
Assert.assertNotNull(actual);
IValue<Double> expectedValue = new DoubleValue(STEP.doubleValue());
Assert.assertEquals(true, actual.getValue().matches(expectedValue));
}
/**
* test that successors matching the values of their predecessors are
* removed
*/
@Test
public void testCompact() {
timeVariable = new TimeVariable<DoubleValue>();
for (Long i = 0L; i < MAX; i += STEP) {
timeVariable.setValueAt(i, new DoubleValue(STEP.doubleValue()));
}
// call
timeVariable.compact();
// check
SortedSet<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(0L);
Assert.assertEquals(1, futureValues.size());
}
}

View File

@ -0,0 +1,131 @@
package li.strolch.model.timevalue;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import junit.framework.Assert;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.IntegerValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
/**
* Basic tests for a {@link TimeVariable} with integer values.
*
* @author martin_smock
*/
public class IntegerTimeVariableTest {
private static final Long MAX = 100L;
private static final Integer STEP = 10;
private static final Long PICK = 50L;
private TimeVariable<IntegerValue> timeVariable;
private Map<Long, IntegerValue> expectedValues = new HashMap<Long, IntegerValue>();
/**
* set the values ascending with a difference of STEP
*/
@Before
public void init() {
timeVariable = new TimeVariable<IntegerValue>();
for (int i = 0; i < MAX; i += STEP) {
IntegerValue expectedValue = new IntegerValue(i);
Long time = Long.valueOf(i);
expectedValues.put(time, expectedValue);
timeVariable.setValueAt(time, expectedValue);
}
}
@Test
public void testGetValueAt() {
ITimeValue<IntegerValue> valueAt = timeVariable.getValueAt(PICK);
Assert.assertEquals(expectedValues.get(PICK), valueAt.getValue());
}
/**
* test, that the future values start with the PICK time and are ascending
*/
@Test
public void testGetFutureValues() {
Collection<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(PICK);
Long expectedTime = PICK;
Integer expectedValue = PICK.intValue();
for (ITimeValue<IntegerValue> value : futureValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(value.getValue().matches(new IntegerValue(expectedValue)));
expectedTime += STEP;
expectedValue += STEP.intValue();
}
}
/**
* test, that the past values time fields start with 0 and are strictly
* smaller than PICK
*/
@Test
public void testGetPastValues() {
Collection<ITimeValue<IntegerValue>> pastValues = timeVariable.getPastValues(MAX);
Long expectedTime = 0L;
Integer expectedValue = expectedTime.intValue();
for (ITimeValue<IntegerValue> value : pastValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(value.getValue().matches(new IntegerValue(expectedValue)));
expectedTime += STEP;
expectedValue += STEP.intValue();
}
}
/**
* apply a change and check that the future values are all changed
*/
@Test
public void testApplyChange() {
IntegerValue integerValue = new IntegerValue(STEP.intValue());
IValueChange<IntegerValue> change = new ValueChange<IntegerValue>(PICK, integerValue);
timeVariable.applyChange(change);
Collection<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(PICK);
Long expectedTime = PICK;
IValue<Integer> expectedValue = new IntegerValue(PICK.intValue() + change.getValue().getValue());
for (ITimeValue<IntegerValue> value : futureValues) {
Assert.assertEquals(expectedTime, value.getTime());
Assert.assertTrue(expectedValue.matches(value.getValue()));
expectedTime += STEP;
expectedValue = expectedValue.add(STEP.intValue());
}
}
/**
* test that successors matching the values of their predecessors are
* removed
*/
@Test
public void testCompact() {
timeVariable = new TimeVariable<IntegerValue>();
for (Long i = 0L; i < MAX; i += STEP) {
timeVariable.setValueAt(i, new IntegerValue(STEP.intValue()));
}
// call
timeVariable.compact();
// check
SortedSet<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(0L);
Assert.assertEquals(1, futureValues.size());
ITimeValue<IntegerValue> next = futureValues.iterator().next();
Assert.assertEquals(Long.valueOf(0), next.getTime());
}
}

View File

@ -0,0 +1,118 @@
package li.strolch.model.timevalue;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import junit.framework.Assert;
import li.strolch.model.timevalue.ITimeValue;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.IValueChange;
import li.strolch.model.timevalue.impl.AString;
import li.strolch.model.timevalue.impl.StringSetValue;
import li.strolch.model.timevalue.impl.TimeVariable;
import li.strolch.model.timevalue.impl.ValueChange;
import org.junit.Before;
import org.junit.Test;
public class StringTimeVariableTest {
private static final Long MAX = 100L;
private static final Long STEP = 10L;
private static final Long PICK = 50L;
private TimeVariable<IValue<Set<AString>>> timeVariable;
private Map<Long, StringSetValue> testSets = new HashMap<Long, StringSetValue>();
@Before
public void init() {
timeVariable = new TimeVariable<IValue<Set<AString>>>();
for (Long i = 0L; i < MAX; i += STEP) {
Set<AString> testSet = new HashSet<AString>();
StringSetValue testValue = new StringSetValue(testSet);
testSets.put(i, testValue);
testSet.add(new AString("string " + i));
timeVariable.setValueAt(i, new StringSetValue(testSet));
}
}
@Test
public void testGetValueAt() {
ITimeValue<IValue<Set<AString>>> valueAt = timeVariable.getValueAt(PICK);
Assert.assertEquals(true, valueAt.getValue().matches(testSets.get(PICK)));
}
@Test
public void testGetFutureValues() {
Collection<ITimeValue<IValue<Set<AString>>>> futureValues = timeVariable.getFutureValues(PICK);
for (ITimeValue<IValue<Set<AString>>> iTimeValue : futureValues) {
Long time = iTimeValue.getTime();
Assert.assertEquals(true, time >= PICK);
Assert.assertNotNull(iTimeValue.getValue());
Assert.assertEquals(true, iTimeValue.getValue().matches(testSets.get(time)));
}
}
@Test
public void testGetPastValues() {
Collection<ITimeValue<IValue<Set<AString>>>> pastValues = timeVariable.getPastValues(PICK);
for (ITimeValue<IValue<Set<AString>>> iTimeValue : pastValues) {
Long time = iTimeValue.getTime();
Assert.assertEquals(true, time < PICK);
Assert.assertNotNull(iTimeValue.getValue());
Assert.assertEquals(true, iTimeValue.getValue().matches(testSets.get(time)));
}
}
@Test
public void testApplyChange() {
Set<AString> testSet = new HashSet<AString>();
testSet.add(new AString("Martin"));
StringSetValue testValue = new StringSetValue(testSet);
timeVariable = new TimeVariable<IValue<Set<AString>>>();
timeVariable.setValueAt(PICK, testValue);
IValue<Set<AString>> inverseTestValue = testValue.getInverse();
IValueChange<IValue<Set<AString>>> change = new ValueChange<IValue<Set<AString>>>(PICK, inverseTestValue);
timeVariable.applyChange(change);
// check the future values
Collection<ITimeValue<IValue<Set<AString>>>> futureValues = timeVariable.getFutureValues(0L);
for (ITimeValue<IValue<Set<AString>>> iTimeValue : futureValues) {
System.out.println("++ " + iTimeValue);
}
Assert.assertEquals(1, futureValues.size()); // a empty one is left
}
@Test
public void testCompact() {
timeVariable = new TimeVariable<IValue<Set<AString>>>();
for (Long i = 0L; i < MAX; i += STEP) {
Set<AString> testSet = new HashSet<AString>();
StringSetValue testValue = new StringSetValue(testSet);
testSets.put(i, testValue);
testSet.add(new AString("same string"));
timeVariable.setValueAt(i, new StringSetValue(testSet));
}
SortedSet<ITimeValue<IValue<Set<AString>>>> valuesInitial = timeVariable.getFutureValues(0L);
Assert.assertEquals(true, valuesInitial.size() > 1);
timeVariable.compact();
SortedSet<ITimeValue<IValue<Set<AString>>>> valuesCompacted = timeVariable.getFutureValues(0L);
Assert.assertEquals(1, valuesCompacted.size());
}
}

View File

@ -0,0 +1,81 @@
package li.strolch.model.timevalue;
import static org.junit.Assert.assertEquals;
import java.util.HashSet;
import java.util.Set;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.timevalue.impl.AString;
import li.strolch.model.timevalue.impl.DoubleValue;
import li.strolch.model.timevalue.impl.IntegerValue;
import li.strolch.model.timevalue.impl.StringSetValue;
import org.junit.Test;
public class ValueTests {
/**
* check, that adding the inverse results in the neutral element (=0)
*/
@Test
public void testDoubleInverse() {
DoubleValue value = new DoubleValue(10.0d);
DoubleValue inverse = value.getInverse();
assertEquals(Double.valueOf(-10.0d), inverse.getValue());
assertEquals(Double.valueOf(0), value.add(inverse.getValue())
.getValue());
}
/**
* check, that adding the inverse results in the neutral element (=0)
*/
@Test
public void testIntegerInverse() {
IntegerValue value = new IntegerValue(10);
IntegerValue inverse = value.getInverse();
assertEquals(Integer.valueOf(-10), inverse.getValue());
assertEquals(Integer.valueOf(0), value.add(inverse.getValue())
.getValue());
}
/**
* check, that adding the inverse results in the neutral element (empty Set)
*/
@Test
public void testStringSetInverse() {
Set<AString> aStrings = new HashSet<AString>();
for (int i = 0; i < 10; i++) {
aStrings.add(new AString("string " + i));
}
IValue<Set<AString>> value = new StringSetValue(aStrings);
IValue<Set<AString>> inverse = value.getInverse();
assertEquals(true, value.matches(inverse.getInverse()));
assertEquals(0, value.add(inverse.getValue()).getValue().size());
}
/**
* check, that the difference left is as expected
*/
@Test
public void testStringSetNearInverse() {
Set<AString> aStrings1 = new HashSet<AString>();
for (int i = 0; i < 10; i++) {
aStrings1.add(new AString("string " + i));
}
IValue<Set<AString>> value1 = new StringSetValue(aStrings1);
Set<AString> aStrings2 = new HashSet<AString>();
for (int i = 0; i < 9; i++) {
aStrings2.add(new AString("string " + i, true));
}
IValue<Set<AString>> value2 = new StringSetValue(aStrings2);
assertEquals(false, value1.matches(value2));
assertEquals(1, value1.add(value2.getValue()).getValue().size());
assertEquals(10, value1.add(value2.getInverse().getValue()).getValue()
.size());
}
}