001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    http://www.geoapi.org
004 *
005 *    Copyright (C) 2011-2019 Open Geospatial Consortium, Inc.
006 *    All Rights Reserved. http://www.opengeospatial.org/ogc/legal
007 *
008 *    Permission to use, copy, and modify this software and its documentation, with
009 *    or without modification, for any purpose and without fee or royalty is hereby
010 *    granted, provided that you include the following on ALL copies of the software
011 *    and documentation or portions thereof, including modifications, that you make:
012 *
013 *    1. The full text of this NOTICE in a location viewable to users of the
014 *       redistributed or derivative work.
015 *    2. Notice of any changes or modifications to the OGC files, including the
016 *       date changes were made.
017 *
018 *    THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE
019 *    NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
020 *    TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
021 *    THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
022 *    PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
023 *
024 *    COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
025 *    CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
026 *
027 *    The name and trademarks of copyright holders may NOT be used in advertising or
028 *    publicity pertaining to the software without specific, written prior permission.
029 *    Title to copyright in this software and any associated documentation will at all
030 *    times remain with copyright holders.
031 */
032package org.opengis.test.referencing.gigs;
033
034import java.util.Map;
035import java.util.HashMap;
036
037import org.opengis.metadata.Identifier;
038import org.opengis.util.FactoryException;
039import org.opengis.referencing.ObjectFactory;
040import org.opengis.referencing.IdentifiedObject;
041import org.opengis.test.referencing.ReferencingTestCase;
042import org.opengis.test.Configuration;
043
044import static org.junit.Assert.*;
045
046
047/**
048 * Base class for tests of new CRS definitions (3000 series).
049 * The test procedures in this series are designed to evaluate the software’s capabilities
050 * for adding user-defined CRS and transformation definitions.
051 *
052 * @param <T> The type of objects to test.
053 *
054 * @see org.opengis.test.TestSuite
055 *
056 * @author  Martin Desruisseaux (Geomatys)
057 * @version 3.1
058 * @since   3.1
059 */
060public abstract strictfp class UserObjectFactoryTestCase<T> extends GIGSTestCase {
061    /**
062     * The properties to be given in argument to a {@code ObjectFactory.createXXX(String)} method.
063     * This map contains at least the given entries:
064     *
065     * <ul>
066     *   <li>A {@link String} value associated to the {@value org.opengis.referencing.IdentifiedObject#NAME_KEY} key.</li>
067     *   <li>An {@link Identifier} value associated to the {@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY} key.</li>
068     * </ul>
069     */
070    public final Map<String,Object> properties;
071
072    /**
073     * Whether the objects created by the tested {@link ObjectFactory} use the specified values <i>as-is</i>.
074     * This flag should be set to {@code false} if the factory performs any of the following operations:
075     *
076     * <ul>
077     *   <li>Convert numerical values from user-provided linear units to metres.</li>
078     *   <li>Convert numerical values from user-provided angular units to degrees.</li>
079     *   <li>Change ellipsoid second defining parameter
080     *       (e.g. from <i>semi-major axis length</i> to an equivalent <i>inverse flattening factor</i>).</li>
081     *   <li>Change map projection parameters
082     *       (e.g. from <i>standard parallel</i> to an equivalent <i>scale factor</i>).</li>
083     *   <li>Any other change that preserve numeric equivalence.</li>
084     * </ul>
085     *
086     * If the factory does not perform any of the above conversions, then this flag can be {@code true}.
087     */
088    protected boolean isFactoryPreservingUserValues;
089
090    /**
091     * If {@code true}, initialize the data but do not run the test.
092     */
093    boolean skipTests;
094
095    /**
096     * Creates a new test which will use the given factories to execute.
097     *
098     * @param factories  the factories to be used by the test. Those factories passed verbatim to the
099     *        {@linkplain ReferencingTestCase#ReferencingTestCase(Factory[]) super-class constructor}.
100     */
101    protected UserObjectFactoryTestCase(final ObjectFactory... factories) {
102        super(factories);
103        properties = new HashMap<>(4);
104        @SuppressWarnings("unchecked")
105        final boolean[] isEnabled = getEnabledFlags(
106                Configuration.Key.isFactoryPreservingUserValues);
107        isFactoryPreservingUserValues = isEnabled[0];
108    }
109
110    /**
111     * Returns information about the configuration of the test which has been run.
112     * This method returns a map containing:
113     *
114     * <ul>
115     *   <li>All the following values associated to the {@link org.opengis.test.Configuration.Key} of the same name:
116     *     <ul>
117     *       <li>{@link #isFactoryPreservingUserValues}</li>
118     *       <li>The factories used by the test (provided by subclasses)</li>
119     *     </ul>
120     *   </li>
121     * </ul>
122     *
123     * @return the configuration of the test being run.
124     */
125    @Override
126    public Configuration configuration() {
127        final Configuration op = super.configuration();
128        assertNull(op.put(Configuration.Key.isFactoryPreservingUserValues, isFactoryPreservingUserValues));
129        return op;
130    }
131
132    /**
133     * Copies the configuration to the given test cases. This method is invoked when a test depends on
134     * other tests, in which case the other tests need to be run with the same configuration in order
135     * to get data.
136     */
137    final void copyConfigurationTo(final UserObjectFactoryTestCase<?>... destinations) {
138        for (final UserObjectFactoryTestCase<?> destination : destinations) {
139            destination.isFactoryPreservingUserValues = isFactoryPreservingUserValues;
140        }
141    }
142
143    /**
144     * Creates a map containing the given name and code, to be given to object factories.
145     *
146     * @param  code  the GIGS (not EPSG) code of the object to create.
147     * @param  name  the name of the object to create.
148     * @return properties to be given to the {@code create(…)} method.
149     */
150    static Map<String,Object> properties(final int code, final String name) {
151        final Map<String,Object> properties = new HashMap<>(4);
152        assertNull(properties.put(IdentifiedObject.IDENTIFIERS_KEY, new GIGSIdentifier(code)));
153        assertNull(properties.put(IdentifiedObject.NAME_KEY, name));
154        return properties;
155    }
156
157    /**
158     * Sets the GIGS code name in the {@link #properties} map.
159     *
160     * @param  code  the GIGS (not EPSG) code of the object to create.
161     * @param  name  the name of the object to create.
162     */
163    final void setCodeAndName(final int code, final String name) {
164        assertNull(IdentifiedObject.NAME_KEY,        properties.put(IdentifiedObject.NAME_KEY, name));
165        assertNull(IdentifiedObject.IDENTIFIERS_KEY, properties.put(IdentifiedObject.IDENTIFIERS_KEY, new GIGSIdentifier(code)));
166    }
167
168    /**
169     * Returns the code stored in the {@link #properties} map, or {@code null} if none.
170     */
171    final String getCode() {
172        final Identifier identifier = (Identifier) properties.get(IdentifiedObject.IDENTIFIERS_KEY);
173        return (identifier != null) ? identifier.getCode() : null;
174    }
175
176    /**
177     * Returns the name stored in the {@link #properties} map, or {@code null} if none.
178     */
179    final String getName() {
180        return (String) properties.get(IdentifiedObject.NAME_KEY);
181    }
182
183    /**
184     * Returns the instance to be tested. When this method is invoked for the first time, it creates the instance
185     * to test by invoking a {@code createXXX(String)} method from the user-specified {@link ObjectFactory} with
186     * the current {@link #properties} in argument. The created object is then cached and returned in subsequent
187     * invocations of this method.
188     *
189     * @return the instance to test.
190     * @throws FactoryException if an error occurred while creating the identified object.
191     */
192    public abstract T getIdentifiedObject() throws FactoryException;
193}