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; 033 034import java.util.Arrays; 035import java.util.Objects; 036import java.util.Iterator; 037import java.util.Collection; 038import java.util.ServiceLoader; 039import java.lang.reflect.Array; 040import org.junit.runner.RunWith; 041import org.junit.runners.Suite; 042import org.opengis.util.Factory; 043import org.opengis.referencing.operation.MathTransform; 044 045 046/** 047 * The suite of every tests defined in the GeoAPI conformance module. 048 * The test cases included in this test suite are: 049 * 050 * <ul> 051 * <li>{@link org.opengis.test.util.NameTest}</li> 052 * <li>{@link org.opengis.test.referencing.ObjectFactoryTest}</li> 053 * <li>{@link org.opengis.test.referencing.AffineTransformTest}</li> 054 * <li>{@link org.opengis.test.referencing.ParameterizedTransformTest}</li> 055 * <li>{@link org.opengis.test.referencing.AuthorityFactoryTest}</li> 056 * <li>{@link org.opengis.test.referencing.gigs.GIGS2001}</li> 057 * <li>{@link org.opengis.test.referencing.gigs.GIGS2002}</li> 058 * <li>{@link org.opengis.test.referencing.gigs.GIGS2003}</li> 059 * <li>{@link org.opengis.test.referencing.gigs.GIGS2004}</li> 060 * <li>{@link org.opengis.test.referencing.gigs.GIGS2005}</li> 061 * <li>{@link org.opengis.test.referencing.gigs.GIGS2006}</li> 062 * <li>{@link org.opengis.test.referencing.gigs.GIGS2007}</li> 063 * <li>{@link org.opengis.test.referencing.gigs.GIGS2008}</li> 064 * <li>{@link org.opengis.test.referencing.gigs.GIGS2009}</li> 065 * <li>{@link org.opengis.test.referencing.gigs.GIGS3002}</li> 066 * <li>{@link org.opengis.test.referencing.gigs.GIGS3003}</li> 067 * <li>{@link org.opengis.test.referencing.gigs.GIGS3004}</li> 068 * <li>{@link org.opengis.test.referencing.gigs.GIGS3005}</li> 069 * <li>{@link org.opengis.test.wkt.CRSParserTest}</li> 070 * </ul> 071 * 072 * This {@code TestSuite} class provides also some static methods for {@linkplain #setFactories specifying 073 * explicitely which factories to use} or {@linkplain #addTestListener being notified of test results}. 074 * Those methods take effect even if the {@link TestCase} are run outside of a {@code TestSuite} context. 075 * 076 * <section class="note"> 077 * <h1>How implementations are discovered</h1> 078 * All tests use {@link Factory} instances that are specific to the implementation being tested. 079 * By default {@code TestSuite} fetches the factory implementations with {@link ServiceLoader}, 080 * which will scan every <code>META-INF/services/org.opengis.<var>TheFactory</var></code> files 081 * on the classpath. However implementors can override this default mechanism with explicit calls 082 * to the {@link #setFactories(Class, Factory[])} method. 083 * 084 * <p>Implementors can have some control on the tests (factories to use, features to test, tolerance 085 * thresholds) by registering their {@link FactoryFilter} or {@link ImplementationDetails} in the 086 * {@code META-INF/services/} directory. As an alternative, implementors can also extend directly 087 * the various {@link TestCase} subclasses.</p> 088 * 089 * <div class="note"><b>Example:</b> 090 * The test suite below declares that the tolerance threshold for {@code MyProjection} 091 * needs to be relaxed by a factor 10 during inverse projections. 092 * 093 * <blockquote><pre>package org.myproject; 094 * 095 *import org.opengis.test.TestSuite; 096 *import org.opengis.test.CalculationType; 097 *import org.opengis.test.ToleranceModifier; 098 *import org.opengis.test.ToleranceModifiers; 099 *import org.opengis.test.ImplementationDetails; 100 *import org.opengis.referencing.operation.MathTransform; 101 *import org.opengis.util.Factory; 102 *import java.util.Properties; 103 * 104 *public class AllTests extends TestSuite implements {@linkplain ImplementationDetails} { 105 * @Override 106 * public Properties {@linkplain ImplementationDetails#configuration configuration}({@linkplain Factory}... factories) { 107 * return null; 108 * } 109 * 110 * @Override 111 * public {@linkplain ToleranceModifier} {@linkplain ImplementationDetails#tolerance tolerance}({@linkplain MathTransform} transform) { 112 * if (transform instanceof <var>MyProjection</var>) { 113 * return {@linkplain ToleranceModifiers#scale ToleranceModifiers.scale}(EnumSet.of({@linkplain CalculationType#INVERSE_TRANSFORM}), 1, 10); 114 * } 115 * return null; 116 * } 117 *}</pre></blockquote> 118 * 119 * The above {@code AllTests} class needs to be registered in the {@code META-INF/services/} 120 * directory if the implementation details shall be honored (otherwise the tests will be run, 121 * but the implementation details will be ignored). 122 * </div> 123 * </section> 124 * 125 * @see ImplementationDetails 126 * @see TestCase 127 * @see Factory 128 * 129 * @author Martin Desruisseaux (Geomatys) 130 * @version 3.1 131 * @since 3.1 132 */ 133@RunWith(Suite.class) 134@Suite.SuiteClasses({ 135 org.opengis.test.util.NameTest.class, 136 org.opengis.test.referencing.ObjectFactoryTest.class, 137 org.opengis.test.referencing.AffineTransformTest.class, 138 org.opengis.test.referencing.ParameterizedTransformTest.class, 139 org.opengis.test.referencing.AuthorityFactoryTest.class, 140 org.opengis.test.referencing.gigs.GIGS2001.class, 141 org.opengis.test.referencing.gigs.GIGS2002.class, 142 org.opengis.test.referencing.gigs.GIGS2003.class, 143 org.opengis.test.referencing.gigs.GIGS2004.class, 144 org.opengis.test.referencing.gigs.GIGS2005.class, 145 org.opengis.test.referencing.gigs.GIGS2006.class, 146 org.opengis.test.referencing.gigs.GIGS2007.class, 147 org.opengis.test.referencing.gigs.GIGS2008.class, 148 org.opengis.test.referencing.gigs.GIGS2009.class, 149 org.opengis.test.referencing.gigs.GIGS3002.class, 150 org.opengis.test.referencing.gigs.GIGS3003.class, 151 org.opengis.test.referencing.gigs.GIGS3004.class, 152 org.opengis.test.referencing.gigs.GIGS3005.class, 153 org.opengis.test.wkt.CRSParserTest.class 154}) 155public strictfp class TestSuite { 156 /** 157 * Constructor provided for allowing subclassing. 158 * Instances of this class usually don't need to be created. 159 */ 160 protected TestSuite() { 161 } 162 163 /** 164 * Sets the class loader to use for loading implementations. A {@code null} value restores 165 * the default {@linkplain Thread#getContextClassLoader() context class loader}. 166 * 167 * @param loader the class loader to use, or {@code null} for the default. 168 */ 169 public static void setClassLoader(final ClassLoader loader) { 170 TestCase.setClassLoader(loader); 171 } 172 173 /** 174 * Specifies the factory implementations to use for the given factory interface. 175 * 176 * @param <T> the compile-time type of the {@code type} class argument. 177 * @param type the factory interface for which an implementation is specified. 178 * @param factory the implementations to use for the given interface. 179 */ 180 @SafeVarargs 181 public static <T extends Factory> void setFactories(final Class<T> type, final T... factory) { 182 Objects.requireNonNull(type, "Given 'type' can not be null"); 183 final Iterable<? extends Factory> list = Arrays.asList(factory.clone()); 184 synchronized (TestCase.FACTORIES) { 185 TestCase.FACTORIES.put(type, list); 186 } 187 } 188 189 /** 190 * Returns the factory implementations explicitely given by the last call to 191 * {@link #setFactories(Class, Factory[])} for the given interface. 192 * This method does not scan the {@code META-INF/services/<T>} entries. 193 * 194 * @param <T> the compile-time type of the {@code type} class argument. 195 * @param type the factory interface for which an implementations is desired. 196 * @return the implementations for the given interface, or {@code null} if none. 197 */ 198 @SuppressWarnings("unchecked") 199 public static <T extends Factory> T[] getFactories(final Class<T> type) { 200 Objects.requireNonNull(type, "Given 'type' can not be null"); 201 final Iterable<? extends Factory> factories; 202 synchronized (TestCase.FACTORIES) { 203 factories = TestCase.FACTORIES.get(type); 204 } 205 if (factories instanceof Collection<?>) { 206 final Collection<? extends Factory> collection = (Collection<? extends Factory>) factories; 207 return collection.toArray((T[]) Array.newInstance(type, collection.size())); 208 } 209 return null; 210 } 211 212 /** 213 * Adds a listener to be informed every time a test begin or finish, either on success 214 * or failure. This method does not check if the given listener was already registered 215 * (i.e. the same listener may be added more than once). 216 * 217 * @param listener The listener to add. {@code null} values are silently ignored. 218 * 219 * @deprecated To be replaced by JUnit 5 listener mechanism. 220 */ 221 @Deprecated 222 public static void addTestListener(final TestListener listener) { 223 TestCase.addTestListener(listener); 224 } 225 226 /** 227 * Removes a previously {@linkplain #addTestListener(TestListener) added} listener. If the 228 * given listener has been added more than once, then only the last occurrence is removed. 229 * If the given listener is not found, then this method does nothing. 230 * 231 * @param listener the listener to remove. {@code null} values are silently ignored. 232 * 233 * @deprecated To be replaced by JUnit 5 listener mechanism. 234 */ 235 @Deprecated 236 public static void removeTestListener(final TestListener listener) { 237 TestCase.removeTestListener(listener); 238 } 239 240 /** 241 * Clears all factories specified to the {@link #setFactories(Class, Factory[])} method, and clears 242 * all {@linkplain ServiceLoader service loader} caches. After this method call, all factories 243 * will be reloaded when first needed. This method is intended for use in situations in which 244 * new factories can be installed or removed into a running Java virtual machine. 245 * 246 * @see ServiceLoader#reload() 247 */ 248 public static void clear() { 249 synchronized (TestCase.FACTORIES) { 250 ServiceLoader<?> services = TestCase.getFactoryFilter(); 251 synchronized (services) { 252 services.reload(); 253 } 254 services = TestCase.getImplementationDetails(); 255 synchronized (services) { 256 services.reload(); 257 } 258 final Iterator<Iterable<? extends Factory>> it = TestCase.FACTORIES.values().iterator(); 259 while (it.hasNext()) { 260 final Iterable<? extends Factory> factories = it.next(); 261 if (factories instanceof ServiceLoader<?>) { 262 ((ServiceLoader<? extends Factory>) factories).reload(); 263 } else { 264 it.remove(); 265 } 266 } 267 } 268 } 269}