tom

Adding more unit tests.

Made some classes abstract which should have been.
......@@ -5,7 +5,7 @@ import static com.google.common.base.Preconditions.checkArgument;
/**
* Base abstraction of an annotated entity.
*/
public class AbstractAnnotated implements Annotated {
public abstract class AbstractAnnotated implements Annotated {
private static final Annotations EMPTY = DefaultAnnotations.builder().build();
......
......@@ -5,7 +5,7 @@ import static com.google.common.base.Preconditions.checkArgument;
/**
* Base implementation of an annotated model description.
*/
public class AbstractDescription implements Annotated {
public abstract class AbstractDescription implements Annotated {
private static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build();
......
......@@ -5,7 +5,7 @@ import org.onlab.onos.net.provider.ProviderId;
/**
* Base implementation of network elements, i.e. devices or hosts.
*/
public class AbstractElement extends AbstractModel implements Element {
public abstract class AbstractElement extends AbstractModel implements Element {
protected final ElementId id;
......@@ -27,9 +27,4 @@ public class AbstractElement extends AbstractModel implements Element {
this.id = id;
}
@Override
public ElementId id() {
return id;
}
}
......
......@@ -5,7 +5,7 @@ import org.onlab.onos.net.provider.ProviderId;
/**
* Base implementation of a network model entity.
*/
public class AbstractModel extends AbstractAnnotated implements Provided {
public abstract class AbstractModel extends AbstractAnnotated implements Provided {
private final ProviderId providerId;
......
......@@ -5,6 +5,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a set of simple annotations that can be used to add arbitrary
* attributes to various parts of the data model.
......@@ -19,9 +21,9 @@ public final class DefaultAnnotations implements SparseAnnotations {
}
/**
* Creates a new set of annotations using the specified immutable map.
* Creates a new set of annotations using clone of the specified hash map.
*
* @param map immutable map of key/value pairs
* @param map hash map of key/value pairs
*/
private DefaultAnnotations(Map<String, String> map) {
this.map = map;
......@@ -36,6 +38,38 @@ public final class DefaultAnnotations implements SparseAnnotations {
return new Builder();
}
/**
* Merges the specified base set of annotations and additional sparse
* annotations into new combined annotations. If the supplied sparse
* annotations are empty, the original base annotations are returned.
* Any keys tagged for removal in the sparse annotations will be omitted
* in the resulting merged annotations.
*
* @param annotations base annotations
* @param sparseAnnotations additional sparse annotations
* @return combined annotations or the original base annotations if there
* are not additional annotations
*/
public static DefaultAnnotations merge(DefaultAnnotations annotations,
SparseAnnotations sparseAnnotations) {
checkNotNull(annotations, "Annotations cannot be null");
if (sparseAnnotations == null || sparseAnnotations.keys().isEmpty()) {
return annotations;
}
// Merge the two maps. Yes, this is not very efficient, but the
// use-case implies small maps and infrequent merges, so we opt for
// simplicity.
Map<String, String> merged = copy(annotations.map);
for (String key : sparseAnnotations.keys()) {
if (sparseAnnotations.isRemoved(key)) {
merged.remove(key);
} else {
merged.put(key, sparseAnnotations.value(key));
}
}
return new DefaultAnnotations(merged);
}
@Override
public Set<String> keys() {
......@@ -53,15 +87,20 @@ public final class DefaultAnnotations implements SparseAnnotations {
return Objects.equals(Builder.REMOVED, map.get(key));
}
@SuppressWarnings("unchecked")
private static HashMap<String, String> copy(Map<String, String> original) {
if (original instanceof HashMap) {
return (HashMap) ((HashMap) original).clone();
}
throw new IllegalArgumentException("Expecting HashMap instance");
}
/**
* Facility for gradually building model annotations.
*/
public static final class Builder {
private static final String REMOVED = "~rEmOvEd~";
// FIXME: Figure out whether and how to make this immutable and serializable
// private final ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
private final Map<String, String> builder = new HashMap<>();
// Private construction is forbidden.
......@@ -99,8 +138,7 @@ public final class DefaultAnnotations implements SparseAnnotations {
* @return annotations
*/
public DefaultAnnotations build() {
// return new DefaultAnnotations(builder.build());
return new DefaultAnnotations(builder);
return new DefaultAnnotations(copy(builder));
}
}
}
......
......@@ -51,7 +51,7 @@ public class DefaultDevice extends AbstractElement implements Device {
@Override
public DeviceId id() {
return (DeviceId) super.id();
return (DeviceId) id;
}
@Override
......
......@@ -45,7 +45,7 @@ public class DefaultHost extends AbstractElement implements Host {
@Override
public HostId id() {
return (HostId) super.id();
return (HostId) id;
}
@Override
......
package org.onlab.onos.net;
import com.google.common.testing.EqualsTester;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.onlab.onos.net.Device.Type.SWITCH;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
/**
* Test of the connetion point entity.
*/
public class ConnectPointTest {
public static final DeviceId DID1 = deviceId("1");
public static final DeviceId DID2 = deviceId("2");
public static final PortNumber P1 = portNumber(1);
public static final PortNumber P2 = portNumber(2);
@Test
public void basics() {
ConnectPoint p = new ConnectPoint(DID1, P2);
assertEquals("incorrect element id", DID1, p.deviceId());
assertEquals("incorrect element id", P2, p.port());
}
@Test
public void testEquality() {
new EqualsTester()
.addEqualityGroup(new ConnectPoint(DID1, P1), new ConnectPoint(DID1, P1))
.addEqualityGroup(new ConnectPoint(DID1, P2), new ConnectPoint(DID1, P2))
.addEqualityGroup(new ConnectPoint(DID2, P1), new ConnectPoint(DID2, P1))
.testEquals();
}
}
\ No newline at end of file
package org.onlab.onos.net;
import org.junit.Test;
import static com.google.common.collect.ImmutableSet.of;
import static org.junit.Assert.*;
import static org.onlab.onos.net.DefaultAnnotations.builder;
/**
* Tests of the default annotations.
*/
public class DefaultAnnotationsTest {
private DefaultAnnotations annotations;
@Test
public void basics() {
annotations = builder().set("foo", "1").set("bar", "2").build();
assertEquals("incorrect keys", of("foo", "bar"), annotations.keys());
assertEquals("incorrect value", "1", annotations.value("foo"));
assertEquals("incorrect value", "2", annotations.value("bar"));
}
@Test
public void empty() {
annotations = builder().build();
assertTrue("incorrect keys", annotations.keys().isEmpty());
}
@Test
public void remove() {
annotations = builder().remove("foo").set("bar", "2").build();
assertEquals("incorrect keys", of("foo", "bar"), annotations.keys());
assertNull("incorrect value", annotations.value("foo"));
assertEquals("incorrect value", "2", annotations.value("bar"));
}
@Test
public void merge() {
annotations = builder().set("foo", "1").set("bar", "2").build();
assertEquals("incorrect keys", of("foo", "bar"), annotations.keys());
SparseAnnotations updates = builder().remove("foo").set("bar", "3").set("goo", "4").build();
annotations = DefaultAnnotations.merge(annotations, updates);
assertEquals("incorrect keys", of("goo", "bar"), annotations.keys());
assertNull("incorrect value", annotations.value("foo"));
assertEquals("incorrect value", "3", annotations.value("bar"));
}
@Test
public void noopMerge() {
annotations = builder().set("foo", "1").set("bar", "2").build();
assertEquals("incorrect keys", of("foo", "bar"), annotations.keys());
SparseAnnotations updates = builder().build();
assertSame("same annotations expected", annotations,
DefaultAnnotations.merge(annotations, updates));
assertSame("same annotations expected", annotations,
DefaultAnnotations.merge(annotations, null));
}
@Test(expected = NullPointerException.class)
public void badMerge() {
DefaultAnnotations.merge(null, null);
}
}
\ No newline at end of file
......@@ -40,6 +40,18 @@ public class DefaultDeviceTest {
@Test
public void basics() {
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1);
validate(device);
}
@Test
public void annotations() {
Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1,
DefaultAnnotations.builder().set("foo", "bar").build());
validate(device);
assertEquals("incorrect provider", "bar", device.annotations().value("foo"));
}
private void validate(Device device) {
assertEquals("incorrect provider", PID, device.providerId());
assertEquals("incorrect id", DID1, device.id());
assertEquals("incorrect type", SWITCH, device.type());
......@@ -50,4 +62,4 @@ public class DefaultDeviceTest {
assertEquals("incorrect serial", SN1, device.serialNumber());
}
}
}
\ No newline at end of file
......