001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2008-2024 Open Geospatial Consortium, Inc.
004 *    http://www.geoapi.org
005 *
006 *    Licensed under the Apache License, Version 2.0 (the "License");
007 *    you may not use this file except in compliance with the License.
008 *    You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *    Unless required by applicable law or agreed to in writing, software
013 *    distributed under the License is distributed on an "AS IS" BASIS,
014 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *    See the License for the specific language governing permissions and
016 *    limitations under the License.
017 */
018package org.opengis.test;
019
020import java.util.Arrays;
021import java.util.Objects;
022import org.junit.jupiter.api.TestInstance;
023
024import org.opengis.util.Factory;
025
026
027/**
028 * Base class of all GeoAPI tests.
029 * All concrete subclasses need at least one {@link Factory} for instantiating the objects to test.
030 * The factories must be specified at subclasses construction time either directly by the implementer,
031 * or indirectly through dependency injection.
032 *
033 * <h2>Test case life cycle</h2>
034 * GeoAPI test cases contain states as non-final protected fields.
035 * Therefor, a new {@code TestCase} instance should be created for each test method to run
036 * ({@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_METHOD Lifecycle.PER_METHOD}).
037 * If {@link org.junit.jupiter.api.TestInstance.Lifecycle#PER_CLASS PER_CLASS} is desired,
038 * then subclasses are responsible for resetting these fields after each test.
039 *
040 * @author  Martin Desruisseaux (Geomatys)
041 * @version 3.1
042 * @since   2.2
043 */
044@TestInstance(TestInstance.Lifecycle.PER_METHOD)
045@SuppressWarnings("strictfp")   // Because we still target Java 11.
046public strictfp abstract class TestCase {
047    /**
048     * Provider of units of measurement (degree, metre, second, <i>etc</i>), never {@code null}.
049     * The {@link Units#degree()}, {@link Units#metre() metre()} and other methods shall return
050     * {@link javax.measure.Unit} instances compatible with the units created by the {@link Factory}
051     * instances to be tested. Those {@code Unit<?>} instances depend on the Unit of Measurement (JSR-373)
052     * implementation used by the factories.
053     * If no units were {@linkplain org.opengis.test.Configuration.Key#units explicitly specified},
054     * then the {@linkplain Units#getDefault() default units} are used.
055     *
056     * @since 3.1
057     */
058    protected final Units units;
059
060    /**
061     * The set of {@link Validator} instances to use for verifying objects conformance (never {@code null}).
062     * If no validators were {@linkplain org.opengis.test.Configuration.Key#validators explicitly specified},
063     * then the {@linkplain Validators#DEFAULT default validators} are used.
064     *
065     * @since 3.1
066     */
067    protected final ValidatorContainer validators;
068
069    /**
070     * A tip set by subclasses during the execution of some optional tests.
071     * In case of optional test failure, if this field is non-null, then a message will be logged at the
072     * {@link java.util.logging.Level#INFO} for giving some tips to the developer about how he can disable the test.
073     *
074     * <h4>Example</h4>
075     * {@snippet lang="java" :
076     * @Test
077     * public void myTest() {
078     *     if (isDerivativeSupported) {
079     *         configurationTip = Configuration.Key.isDerivativeSupported;
080     *         // Do some tests the require support of math transform derivatives.
081     *     }
082     *     configurationTip = null;
083     * }}
084     *
085     * @since 3.1
086     */
087    protected transient Configuration.Key<Boolean> configurationTip;
088
089    /**
090     * Creates a new test case.
091     */
092    protected TestCase() {
093        this.validators = Objects.requireNonNull(Validators.DEFAULT, "Validators.DEFAULT shall not be null.");
094        this.units      = Units.getDefault();
095    }
096
097    /**
098     * Returns booleans indicating whether the given operations are enabled.
099     * By default, every operations are enabled.
100     *
101     * @param  properties  the key for which the flags are wanted.
102     * @return an array of the same length as {@code properties} in which each element at index
103     *         <var>i</var> indicates whether the {@code properties[i]} test should be enabled.
104     *
105     * @since 3.1
106     */
107    @SafeVarargs
108    protected final boolean[] getEnabledFlags(final Configuration.Key<Boolean>... properties) {
109        final boolean[] isEnabled = new boolean[properties.length];
110        Arrays.fill(isEnabled, true);
111        return isEnabled;
112    }
113
114    /**
115     * Returns information about the configuration of the test which has been run.
116     * The content of this map depends on the {@code TestCase} subclass.
117     * For a description of the map content, see any of the following subclasses:
118     *
119     * <ul>
120     *   <li>{@link org.opengis.test.referencing.AffineTransformTest#configuration()}</li>
121     *   <li>{@link org.opengis.test.referencing.ParameterizedTransformTest#configuration()}</li>
122     *   <li>{@link org.opengis.test.referencing.AuthorityFactoryTest#configuration()}</li>
123     * </ul>
124     *
125     * @return the configuration of the test being run, or an empty map if none.
126     *         This method returns a modifiable map in order to allow subclasses to modify it.
127     *
128     * @since 3.1
129     */
130    public Configuration configuration() {
131        final Configuration configuration = new Configuration();
132        configuration.put(Configuration.Key.units,      units);
133        configuration.put(Configuration.Key.validators, validators);
134        return configuration;
135    }
136}