blob: 2e19fc55fbfd33e3add68ca06385dbc81b5db208 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.referencing;
import java.util.Map;
import java.util.HashMap;
import org.opengis.util.NameSpace;
import org.opengis.util.LocalName;
import org.opengis.util.GenericName;
import org.opengis.util.NameFactory;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.metadata.simple.SimpleCitation;
import org.apache.sis.metadata.simple.SimpleIdentifier;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.util.iso.DefaultNameFactory;
// Test dependencies
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.apache.sis.test.Assertions.assertMessageContains;
import org.apache.sis.test.TestCase;
// Specific to the main branch:
import org.opengis.referencing.ReferenceIdentifier;
/**
* Tests {@link Builder}.
*
* @author Martin Desruisseaux (Geomatys)
*/
public final class BuilderTest extends TestCase {
/**
* Creates a new test case.
*/
public BuilderTest() {
}
/**
* Tests {@link Builder#verifyParameterizedType(Class)}.
*/
@Test
@SuppressWarnings("ResultOfObjectAllocationIgnored")
public void testVerifyParameterizedType() {
final class Invalid extends Builder<BuilderMock> {
}
var exception = assertThrows(AssertionError.class, () -> new Invalid());
assertMessageContains(exception, BuilderMock.class.getName());
}
/**
* Tests {@link Builder#setCodeSpace(Citation, String)}.
*/
@Test
public void testSetCodeSpace() {
final var builder = new BuilderMock();
builder.setCodeSpace(Citations.EPSG, "EPSG");
builder.addName("Mercator (variant A)");
/*
* Setting the same codespace should have no effect, while attempt to
* set a new codespace after we added a name shall not be allowed.
*/
final SimpleCitation IOGP = new SimpleCitation("IOGP");
builder.setCodeSpace(Citations.EPSG, "EPSG");
var exception = assertThrows(IllegalStateException.class, () -> builder.setCodeSpace(IOGP, "EPSG"));
assertMessageContains(exception, Identifier.AUTHORITY_KEY);
/*
* The failed attempt to set a new codespace shall not have modified builder state.
*/
assertEquals("EPSG", builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
assertSame (Citations.EPSG, builder.properties.get(Identifier.AUTHORITY_KEY));
/*
* After a cleanup (normally after a createXXX(…) method call), user shall be allowed to
* set a new codespace again. Note that the cleanup operation shall not clear the codespace.
*/
builder.onCreate(true);
assertEquals("EPSG", builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
assertSame (Citations.EPSG, builder.properties.get(Identifier.AUTHORITY_KEY));
builder.setCodeSpace(IOGP, "EPSG");
assertEquals("EPSG", builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
assertSame ( IOGP, builder.properties.get(Identifier.AUTHORITY_KEY));
}
/**
* Tests {@link Builder#addName(CharSequence)} without codespace.
*/
@Test
public void testAddName() {
final NameFactory factory = DefaultNameFactory.provider();
// Expected values to be used later in the test.
final String name = "Mercator (variant A)";
final LocalName alias1 = factory.createLocalName(null, "Mercator (1SP)");
final LocalName alias2 = factory.createLocalName(null, "Mercator_1SP");
final LocalName alias3 = factory.createLocalName(null, "CT_Mercator");
assertTrue(alias1.scope().isGlobal());
assertTrue(alias2.scope().isGlobal());
assertTrue(alias3.scope().isGlobal());
assertEquals("Mercator (1SP)", alias1.toString());
assertEquals("Mercator_1SP", alias2.toString());
assertEquals("CT_Mercator", alias3.toString());
// The test.
final BuilderMock builder = new BuilderMock();
assertSame(builder, builder.addName("Mercator (variant A)")); // EPSG version 7.6 and later.
assertSame(builder, builder.addName("Mercator (1SP)")); // EPSG before version 7.6.
assertSame(builder, builder.addName("Mercator_1SP")); // OGC
assertSame(builder, builder.addName("CT_Mercator")); // GeoTIFF
builder.onCreate(false);
assertEquals(name, builder.getName());
assertArrayEquals(new GenericName[] {alias1, alias2, alias3}, builder.getAliases());
}
/**
* Creates a {@link Builder} with <q>Mercator (variant A)</q> projection (EPSG:9804) names and identifiers.
* This method uses scopes for differentiating the EPSG names from the OGC and GeoTIFF ones.
*
* @param withNames {@code true} for adding the names in the builder.
* @param withIdentifiers {@code true} for adding the identifiers in the builder.
* @return the builder with Mercator names and/or identifiers.
*/
private static BuilderMock createMercator(final boolean withNames, final boolean withIdentifiers) {
final var builder = new BuilderMock();
assertSame(builder, builder.setCodeSpace(Citations.EPSG, "EPSG"));
if (withNames) {
assertSame(builder, builder.addName( "Mercator (variant A)")); // EPSG version 7.6 and later.
assertSame(builder, builder.addName( "Mercator (1SP)")); // EPSG before version 7.6.
assertSame(builder, builder.addName(Citations.OGC, "Mercator_1SP"));
assertSame(builder, builder.addName(Citations.GEOTIFF, "CT_Mercator"));
}
if (withIdentifiers) {
assertSame(builder, builder.addIdentifier( "9804"));
assertSame(builder, builder.addIdentifier(Citations.GEOTIFF, "7"));
}
builder.onCreate(false);
return builder;
}
/**
* Tests {@link Builder#addName(Citation, CharSequence)} and {@link Builder#addName(CharSequence)} with codespace.
*/
@Test
public void testAddNameWithScope() {
final NameFactory factory = DefaultNameFactory.provider();
// Expected values to be used later in the test.
final String name = "Mercator (variant A)";
final GenericName alias1 = factory.createLocalName(scope(factory, "EPSG"), "Mercator (1SP)");
final GenericName alias2 = new NamedIdentifier(Citations.OGC, "Mercator_1SP");
final GenericName alias3 = new NamedIdentifier(Citations.GEOTIFF, "CT_Mercator");
assertTrue (alias3.scope().isGlobal());
assertTrue (alias2.scope().isGlobal());
assertFalse(alias1.scope().isGlobal());
assertEquals("EPSG", alias1.scope().name().toString());
assertEquals("Mercator (1SP)", alias1.toString());
assertEquals("OGC:Mercator_1SP", alias2.toString());
assertEquals("GeoTIFF:CT_Mercator", alias3.toString());
// The test.
final BuilderMock builder = createMercator(true, false);
assertEquals(name, builder.getName());
assertArrayEquals(new GenericName[] {alias1, alias2, alias3}, builder.getAliases());
}
/**
* Convenience method creating a namespace for {@link #testAddNameWithScope()} purpose.
*/
private static NameSpace scope(final NameFactory factory, final String codespace) {
return factory.createNameSpace(factory.createLocalName(null, codespace), null);
}
/**
* Tests {@link Builder#addIdentifier(Citation, String)} and {@link Builder#addIdentifier(String)} with code space.
*/
@Test
public void testAddIdentifiers() {
// Expected values to be used later in the test.
final var id1 = new ImmutableIdentifier(Citations.EPSG, "EPSG", "9804");
final var id2 = new ImmutableIdentifier(Citations.GEOTIFF, "GeoTIFF", "7");
assertEquals("EPSG:9804", IdentifiedObjects.toString(id1));
assertEquals("GeoTIFF:7", IdentifiedObjects.toString(id2));
// The test.
final BuilderMock builder = createMercator(false, true);
assertArrayEquals(new Identifier[] {id1, id2}, builder.getIdentifiers());
}
/**
* Tests {@link Builder#addNamesAndIdentifiers(IdentifiedObject)}.
*/
@Test
public void testAddNamesAndIdentifiers() {
final BuilderMock builder = createMercator(true, true);
final var object = new AbstractIdentifiedObject(builder.properties);
builder.onCreate(true);
for (final Map.Entry<String,?> entry : builder.properties.entrySet()) {
final Object value = entry.getValue();
switch (entry.getKey()) {
case Identifier.AUTHORITY_KEY: {
assertSame(Citations.EPSG, value); // Authority and codespace shall be unchanged.
break;
}
case ReferenceIdentifier.CODESPACE_KEY: {
assertEquals("EPSG", value); // Authority and codespace shall be unchanged.
break;
}
default: {
assertNull(value); // Should not contain any non-null value except the authority.
break;
}
}
}
assertSame(builder, builder.addNamesAndIdentifiers(object));
builder.onCreate(false);
assertSame (object.getName(), builder.getName());
assertArrayEquals(object.getAlias().toArray(), builder.getAliases());
assertArrayEquals(object.getIdentifiers().toArray(), builder.getIdentifiers());
}
/**
* Tests {@link Builder#rename(Citation, CharSequence[])}.
*/
@Test
public void testRename() {
final BuilderMock builder = createMercator(true, false);
// Replace "OGC:Mercator_1SP" and insert a new OGC code before the GeoTIFF one.
assertSame(builder, builder.rename(Citations.OGC, "Replacement 1", "Replacement 2"));
builder.onCreate(false);
assertArrayEquals(new String[] {
"Mercator (variant A)",
"Mercator (1SP)",
"OGC:Replacement 1",
"OGC:Replacement 2",
"GeoTIFF:CT_Mercator"
}, builder.getAsStrings(1));
// Replace "EPSG:Mercator (variant A)" and "(1SP)", and insert a new EPSG code as an alias.
assertSame(builder, builder.rename(Citations.EPSG, "Replacement 3", "Replacement 4", "Replacement 5"));
builder.onCreate(false);
assertArrayEquals(new String[] {
"Replacement 3",
"Replacement 4",
"Replacement 5",
"OGC:Replacement 1",
"OGC:Replacement 2",
"GeoTIFF:CT_Mercator"
}, builder.getAsStrings(1));
// Remove all EPSG codes.
assertSame(builder, builder.rename(Citations.EPSG, (String[]) null));
builder.onCreate(false);
assertArrayEquals(new String[] {
"OGC:Replacement 1",
"OGC:Replacement 2",
"GeoTIFF:CT_Mercator"
}, builder.getAsStrings(1));
}
/**
* Tests the {@link Builder#Builder(IdentifiedObject)} constructor.
*/
@Test
public void testCreationFromObject() {
final Map<String,Object> properties = new HashMap<>();
final Identifier id = new SimpleIdentifier(null, "An identifier", false);
assertNull(properties.put(AbstractIdentifiedObject.IDENTIFIERS_KEY, id));
assertNull(properties.put(AbstractIdentifiedObject.ALIAS_KEY, "An alias"));
assertNull(properties.put(AbstractIdentifiedObject.NAME_KEY, "Dummy object"));
assertNull(properties.put(AbstractIdentifiedObject.REMARKS_KEY, "Some remarks"));
final var builder = new BuilderMock(new AbstractIdentifiedObject(properties));
assertEquals(3, builder.properties.size()); // Expect only name, remarks and deprecated status.
builder.onCreate(false);
assertEquals(5, builder.properties.size()); // Expect name, aliases, identifiers and remarks.
assertEquals("Dummy object", builder.properties.get(AbstractIdentifiedObject.NAME_KEY).toString());
assertEquals("Some remarks", builder.properties.get(AbstractIdentifiedObject.REMARKS_KEY).toString());
assertEquals("An alias", ((Object[]) builder.properties.get(AbstractIdentifiedObject.ALIAS_KEY))[0].toString());
assertSame(id, ((Object[]) builder.properties.get(AbstractIdentifiedObject.IDENTIFIERS_KEY))[0]);
}
}