blob: 8b3e026c469cd7ee7a718d0a9d015aa355c19198 [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.metadata;
import java.util.Locale;
import java.util.Iterator;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.opengis.annotation.Obligation;
import org.opengis.util.InternationalString;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.util.collection.TreeTable;
import org.apache.sis.util.collection.TableColumn;
import org.apache.sis.metadata.iso.citation.DefaultCitation;
import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.apache.sis.xml.NilReason;
// Test dependencies
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import org.apache.sis.test.TestCase;
import static org.apache.sis.test.Assertions.assertMultilinesEquals;
import static org.apache.sis.test.TestUtilities.toTreeStructure;
import static org.apache.sis.test.TestUtilities.formatMetadata;
/**
* Tests the {@link TreeTableView} class.
* Unless otherwise specified, all tests use the {@link MetadataStandard#ISO_19115} constant.
*
* @author Martin Desruisseaux (Geomatys)
*/
public final class TreeTableViewTest extends TestCase {
/**
* Creates a new test case.
*/
public TreeTableViewTest() {
}
/**
* Creates a table to be tested for the given value policy.
*/
private static TreeTableView create(final ValueExistencePolicy valuePolicy) {
return new TreeTableView(MetadataStandard.ISO_19115, TreeNodeTest.metadataWithHierarchy(), Citation.class, valuePolicy);
}
/**
* The expected string representation of the tree created by {@link #create(ValueExistencePolicy)}
* with {@link ValueExistencePolicy#NON_EMPTY}.
*/
private static final String EXPECTED =
"Citation………………………………………………………………………………………………… Some title\n" +
"  ├─Alternate title (1 of 2)…………………………………………… First alternate title\n" +
"  ├─Alternate title (2 of 2)…………………………………………… Second alternate title\n" +
"  ├─Edition………………………………………………………………………………………… Some edition\n" +
"  ├─Cited responsible party (1 of 2)\n" +
"  │   ├─Organisation………………………………………………………………… Some organisation\n" +
"  │   └─Role……………………………………………………………………………………… Distributor\n" +
"  ├─Cited responsible party (2 of 2)\n" +
"  │   ├─Individual……………………………………………………………………… Some person of contact\n" +
"  │   │   └─Contact info\n" +
"  │   │       └─Address\n" +
"  │   │           └─Electronic mail address…… Some email\n" +
"  │   └─Role……………………………………………………………………………………… Point of contact\n" +
"  ├─Presentation form (1 of 2)……………………………………… Map digital\n" +
"  ├─Presentation form (2 of 2)……………………………………… Map hardcopy\n" +
"  └─Other citation details………………………………………………… Some other details\n";
/**
* Tests {@link TreeTableView#toString()}.
* Since the result is locale-dependent, we cannot compare against an exact string.
* We will only compare the beginning of each line.
*/
@Test
public void testToString() {
final TreeTableView metadata = create(ValueExistencePolicy.COMPACT);
assertFalse(metadata.getColumns().contains(MetadataColumn.NIL_REASON));
assertMultilinesEquals(EXPECTED, formatMetadata(metadata)); // Locale-independent
assertArrayEquals(toTreeStructure(EXPECTED), toTreeStructure(metadata.toString())); // Locale-dependent.
}
/**
* Verifies most columns in the tree table. All nil reasons are null.
*/
@Test
public void testGetValues() {
final TreeTableView metadata = create(ValueExistencePolicy.NON_NULL);
assertTrue(metadata.getColumns().contains(MetadataColumn.NIL_REASON));
verify(metadata.getRoot(), "Some title", null);
}
/**
* Verifies columns in the tree table with some non-null nil reasons.
*/
@Test
public void testNilReasons() {
final TreeTableView metadata = create(ValueExistencePolicy.NON_NULL);
assertTrue(metadata.getColumns().contains(MetadataColumn.NIL_REASON));
final var citation = (DefaultCitation) metadata.getRoot().getUserObject();
citation.setTitle(NilReason.TEMPLATE.createNilObject(InternationalString.class));
verify(metadata.getRoot(), null, NilReason.TEMPLATE);
}
/**
* Verifies the values of the given root node and some of its children.
* This method modifies the metadata for also testing some nil values.
*
* @param node root node to verify.
* @param title expected citation title, or {@code null} if it is expected to be missing.
* @param titleNR if the title is missing, the expected reason why.
*/
private void verify(TreeTableView.Node node, final String title, final NilReason titleNR) {
assertEquals("CI_Citation", node.getValue(TableColumn.IDENTIFIER));
assertNull ( node.getValue(TableColumn.INDEX));
assertEquals("Citation", node.getValue(TableColumn.NAME));
assertEquals(Citation.class, node.getValue(TableColumn.TYPE));
assertNull ( node.getValue(TableColumn.OBLIGATION));
assertNull ( node.getValue(TableColumn.VALUE));
assertNull ( node.getValue(MetadataColumn.NIL_REASON));
/*
* The first child of a Citation object should be the title.
* Verify the title value, type, obligation, etc.
*/
Iterator<TreeTable.Node> it = node.getChildren().iterator();
node = it.next();
assertEquals("title", node.getValue(TableColumn.IDENTIFIER));
assertNull ( node.getValue(TableColumn.INDEX));
assertEquals("Title", node.getValue(TableColumn.NAME));
assertEquals(InternationalString.class, node.getValue(TableColumn.TYPE));
assertEquals(Obligation.MANDATORY, node.getValue(TableColumn.OBLIGATION));
assertI18nEq(title, node.getValue(TableColumn.VALUE));
assertEquals(titleNR, node.getValue(MetadataColumn.NIL_REASON));
/*
* Declare the title as missing and verify that the change has been applied.
*/
node.setValue(MetadataColumn.NIL_REASON, NilReason.MISSING);
assertEquals(NilReason.MISSING, node.getValue(MetadataColumn.NIL_REASON));
assertNull(node.getValue(TableColumn.VALUE));
/*
* The second child of the Citation use in this test should be an alternate title.
* This property is a collection with two elements. Check the first one.
*/
node = it.next();
assertEquals("alternateTitle", node.getValue(TableColumn.IDENTIFIER));
assertEquals(0, node.getValue(TableColumn.INDEX));
assertI18nEq("Alternate title (1 of 2)", node.getValue(TableColumn.NAME));
assertEquals(InternationalString.class, node.getValue(TableColumn.TYPE));
assertEquals(Obligation.OPTIONAL, node.getValue(TableColumn.OBLIGATION));
assertI18nEq("First alternate title", node.getValue(TableColumn.VALUE));
assertNull ( node.getValue(MetadataColumn.NIL_REASON));
/*
* Set the first element to nil, then check that the second element has not been impacted.
* Contrarily to the previous test, this test modifies a collection elements instead of the
* property as a whole.
*/
node.setValue(MetadataColumn.NIL_REASON, NilReason.INAPPLICABLE);
assertEquals(NilReason.INAPPLICABLE, node.getValue(MetadataColumn.NIL_REASON));
assertNull(node.getValue(TableColumn.VALUE));
node = it.next();
assertI18nEq("Second alternate title", node.getValue(TableColumn.VALUE));
assertNull(node.getValue(MetadataColumn.NIL_REASON));
}
/**
* Verifies the value of the given international string in English.
*/
private static void assertI18nEq(final String expected, Object text) {
if (text instanceof InternationalString i18n) {
text = i18n.toString(Locale.ENGLISH);
}
assertEquals(expected, text);
}
/**
* Tests serialization.
*
* @throws Exception if an error occurred during the serialization process.
*/
@Test
public void testSerialization() throws Exception {
final Object original = create(ValueExistencePolicy.COMPACT);
final Object deserialized;
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {
out.writeObject(original);
}
// Now reads the object we just serialized.
final byte[] data = buffer.toByteArray();
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data))) {
deserialized = in.readObject();
}
assertMultilinesEquals(EXPECTED, formatMetadata((TreeTableView) deserialized));
}
/**
* Tests formatting a tree containing a remark. We use a geographic bounding box crossing the anti-meridian.
* In this test the longitude value and the remarks and separated by "……" characters, but this is because we
* use the default {@link org.apache.sis.util.collection.TreeTableFormat}. When using {@link MetadataFormat}
* specialization, the formatting is a little bit different
*/
@Test
public void testRemarks() {
final DefaultGeographicBoundingBox bbox = new DefaultGeographicBoundingBox(170, -160, -30, 40);
final String text = formatMetadata(bbox.asTreeTable());
assertMultilinesEquals(
"Geographic bounding box\n" +
"  ├─West bound longitude…… 170°E\n" +
"  ├─East bound longitude…… 160°W…… Bounding box crosses the antimeridian.\n" + // See method javadoc.
"  ├─South bound latitude…… 30°S\n" +
"  ├─North bound latitude…… 40°N\n" +
"  └─Extent type code……………… True\n", text);
}
}