package org.geotools.map;
import java.util.concurrent.CountDownLatch;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.event.MapLayerListEvent;
import org.geotools.map.event.MapLayerListListener;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Tests to ensure the consistency of MapContent and MapViewport functionality.
* @author Jody Garnett
*/
public class MapContentTest {
// timeout period for waiting listener (see end of class)
private static final long LISTENER_TIMEOUT = 500;
private static final ReferencedEnvelope WORLD_ENV =
new ReferencedEnvelope(149, 153, -32, -36, DefaultGeographicCRS.WGS84);
private static final ReferencedEnvelope SUB_ENV =
new ReferencedEnvelope(150, 152, -33, -35, DefaultGeographicCRS.WGS84);
private static final double TOL = 1.0e-6;
static class MockLayer extends Layer {
ReferencedEnvelope bounds;
MockLayer(ReferencedEnvelope bounds) {
if (bounds != null) {
this.bounds = new ReferencedEnvelope(bounds);
}
}
@Override
public ReferencedEnvelope getBounds() {
return bounds;
}
}
@Test
public void testDispose() {
MapContent map = new MapContent();
map.dispose();
map = new MapContent(DefaultGeographicCRS.WGS84);
map.dispose();
}
/**
* Test DefaultMapContext handles layers that return null bounds.
*/
@Test
public void testNPELayerBounds() throws IOException {
Layer mapLayerBoundsNull = new MockLayer(null);
MapContent map = new MapContent(DefaultGeographicCRS.WGS84);
map.addLayer(mapLayerBoundsNull);
ReferencedEnvelope maxBounds = map.getMaxBounds();
assertNotNull(maxBounds);
assertEquals( "wgs84", DefaultGeographicCRS.WGS84, maxBounds.getCoordinateReferenceSystem() );
assertTrue( maxBounds.isEmpty() );
map.dispose();
map = new MapContent();
map.addLayer(mapLayerBoundsNull);
maxBounds = map.getMaxBounds();
assertNull(maxBounds);
}
/**
* Calling {@link MapContent#getViewport()} initially creates a
* new viewport instance with default settings.
*/
@Test
public void getDefaultViewport() throws Exception {
MapContent map = new MapContent();
map.addLayer(new MockLayer(WORLD_ENV));
MapViewport viewport = map.getViewport();
assertNotNull(viewport);
map.dispose();
}
@Test
public void setNewViewportAndCheckBounds() {
MapContent map = new MapContent();
map.addLayer(new MockLayer(WORLD_ENV));
MapViewport newViewport = new MapViewport();
newViewport.setBounds(SUB_ENV);
map.setViewport(newViewport);
ReferencedEnvelope bounds = map.getBounds();
assertTrue(SUB_ENV.boundsEquals2D(bounds, TOL));
}
@Test
public void addLayerAndGetEvent() {
MapContent map = new MapContent();
WaitingListener listener = new WaitingListener();
map.addMapLayerListListener(listener);
listener.setExpected(WaitingListener.Type.ADDED);
map.addLayer(new MockLayer(WORLD_ENV));
assertTrue(listener.await(WaitingListener.Type.ADDED, LISTENER_TIMEOUT));
}
@Test
public void removeLayerAndGetEvent() {
MapContent map = new MapContent();
Layer layer = new MockLayer(WORLD_ENV);
map.addLayer(layer);
WaitingListener listener = new WaitingListener();
map.addMapLayerListListener(listener);
listener.setExpected(WaitingListener.Type.REMOVED);
map.removeLayer(layer);
assertTrue(listener.await(WaitingListener.Type.REMOVED, LISTENER_TIMEOUT));
}
@Test
public void moveLayerAndGetEvent() {
MapContent map = new MapContent();
Layer layer0 = new MockLayer(WORLD_ENV);
Layer layer1 = new MockLayer(WORLD_ENV);
map.addLayer(layer0);
map.addLayer(layer1);
WaitingListener listener = new WaitingListener();
map.addMapLayerListListener(listener);
listener.setExpected(WaitingListener.Type.MOVED, 2);
map.moveLayer(0, 1);
assertTrue(listener.await(WaitingListener.Type.MOVED, LISTENER_TIMEOUT));
}
private static class WaitingListener implements MapLayerListListener {
static enum Type {
ADDED,
REMOVED,
CHANGED,
MOVED;
}
private final static int N = Type.values().length;
CountDownLatch[] latches = new CountDownLatch[N];
void setExpected(Type type) {
setExpected(type, 1);
}
void setExpected(Type type, int count) {
latches[type.ordinal()] = new CountDownLatch(count);
}
boolean await(Type type, long timeoutMillis) {
int index = type.ordinal();
if (latches[index] == null) {
throw new IllegalStateException("Event type not expected: " + type);
}
boolean result = false;
try {
result = latches[index].await(timeoutMillis, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
return result;
}
public void layerAdded(MapLayerListEvent event) {
catchEvent(Type.ADDED);
}
public void layerRemoved(MapLayerListEvent event) {
catchEvent(Type.REMOVED);
}
public void layerChanged(MapLayerListEvent event) {
catchEvent(Type.CHANGED);
}
public void layerMoved(MapLayerListEvent event) {
catchEvent(Type.MOVED);
}
private void catchEvent(Type type) {
int index = type.ordinal();
if (latches[index] == null) {
throw new IllegalStateException("Event type not expected: " + type);
}
latches[index].countDown();
}
}
}