001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * http://www.geoapi.org 004 * 005 * Copyright (C) 2008-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.util; 033 034import java.util.Map; 035import java.util.List; 036import java.util.Locale; 037import java.util.HashMap; 038import java.util.regex.Pattern; 039 040import org.opengis.util.*; 041import org.opengis.test.TestCase; 042import org.opengis.test.Configuration; 043 044import org.junit.Test; 045import org.junit.runner.RunWith; 046import org.junit.runners.Parameterized; 047 048import static org.junit.Assume.*; 049import static org.opengis.test.Assert.*; 050 051 052/** 053 * Tests {@linkplain GenericName generic name} and related objects from the {@code org.opengis.util} 054 * package. Name instances are created using a {@link NameFactory} given at construction time. 055 * 056 * <div class="note"><b>Usage example:</b> 057 * in order to specify their factories and run the tests in a JUnit framework, implementors can 058 * define a subclass in their own test suite as in the example below: 059 * 060 * <blockquote><pre>import org.junit.runner.RunWith; 061 *import org.junit.runners.JUnit4; 062 *import org.opengis.test.util.NameTest; 063 * 064 *@RunWith(JUnit4.class) 065 *public class MyTest extends NameTest { 066 * public MyTest() { 067 * super(new MyNameFactory()); 068 * } 069 *}</pre></blockquote> 070 * </div> 071 * 072 * @see org.opengis.test.TestSuite 073 * 074 * @author Martin Desruisseaux (Geomatys) 075 * @version 3.1 076 * @since 2.2 077 */ 078@RunWith(Parameterized.class) 079public strictfp class NameTest extends TestCase { 080 /** 081 * The factory to be used for testing {@linkplain GenericName generic name} instances, 082 * or {@code null} if none. 083 */ 084 protected final NameFactory factory; 085 086 /** 087 * {@code true} if the {@link InternationalString} implementations created by the 088 * {@linkplain #factory} can support more than one {@linkplain Locale locale}. If 089 * {@code false}, then the factory method may retain only one locale among the set 090 * of user-provided localized strings. 091 */ 092 protected boolean isMultiLocaleSupported; 093 094 /** 095 * {@code true} if the {@link GenericName} implementations created by the {@linkplain #factory} 096 * can use different syntax rules in different part of their name. 097 * 098 * <ul> 099 * <li>If {@code true}, then URI using different separators in different parts of their name are supported. 100 * <div class="note"><b>Example:</b> {@code ":"}, {@code "."}, {@code "/"} and {@code "#"} in 101 * {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}.</div></li> 102 * <li>If {@code false}, then only a single rule can be applied to the name as a whole. 103 * <div class="note"><b>Example:</b> only the {@code ":"} separator is used in 104 * {@code "urn:ogc:def:crs:epsg:4326"}.</div></li> 105 * </ul> 106 */ 107 protected boolean isMixedNameSyntaxSupported; 108 109 /** 110 * Returns a default set of factories to use for running the tests. Those factories are given 111 * in arguments to the constructor when this test class is instantiated directly by JUnit (for 112 * example as a {@linkplain org.junit.runners.Suite.SuiteClasses suite} element), instead than 113 * subclassed by the implementor. The factories are fetched as documented in the 114 * {@link #factories(Class[])} javadoc. 115 * 116 * @return the default set of arguments to be given to the {@code NameTest} constructor. 117 * 118 * @since 3.1 119 */ 120 @Parameterized.Parameters 121 @SuppressWarnings("unchecked") 122 public static List<Factory[]> factories() { 123 return factories(NameFactory.class); 124 } 125 126 /** 127 * Creates a new test using the given factory. If the given factory is {@code null}, 128 * then the tests will be skipped. 129 * 130 * @param factory the factory to be used for creation of instances to be tested. 131 */ 132 public NameTest(final NameFactory factory) { 133 super(factory); 134 this.factory = factory; 135 @SuppressWarnings("unchecked") 136 final boolean[] isEnabled = getEnabledFlags( 137 Configuration.Key.isMultiLocaleSupported, 138 Configuration.Key.isMixedNameSyntaxSupported); 139 isMultiLocaleSupported = isEnabled[0]; 140 isMixedNameSyntaxSupported = isEnabled[1]; 141 } 142 143 /** 144 * Returns information about the configuration of the test which has been run. 145 * This method returns a map containing: 146 * 147 * <ul> 148 * <li>All the following values associated to the {@link org.opengis.test.Configuration.Key} of the same name: 149 * <ul> 150 * <li>{@link #isMultiLocaleSupported}</li> 151 * <li>{@link #isMixedNameSyntaxSupported}</li> 152 * </ul> 153 * </li> 154 * </ul> 155 * 156 * @return {@inheritDoc} 157 */ 158 @Override 159 public Configuration configuration() { 160 final Configuration op = super.configuration(); 161 assertNull(op.put(Configuration.Key.isMultiLocaleSupported, isMultiLocaleSupported)); 162 assertNull(op.put(Configuration.Key.isMixedNameSyntaxSupported, isMixedNameSyntaxSupported)); 163 return op; 164 } 165 166 /** 167 * Creates a namespace having the given name and separator. 168 * 169 * @param name 170 * the name of the namespace to be returned. This argument can be created using 171 * <code>{@linkplain #createGenericName createGenericName}(null, parsedNames)</code>. 172 * @param headSeparator 173 * the separator to insert between the namespace and the {@linkplain AbstractName#head head}. 174 * For HTTP namespace, it is {@code "://"}. For URN namespace, it is typically {@code ":"}. 175 * @param separator 176 * the separator to insert between {@linkplain AbstractName#getParsedNames parsed names} in that namespace. 177 * For HTTP namespace, it is {@code "."}. For URN namespace, it is typically {@code ":"}. 178 * @return a namespace having the given name and separator. 179 */ 180 private NameSpace createNameSpace(final GenericName name, 181 final String headSeparator, final String separator) 182 { 183 final Map<String,String> properties = new HashMap<>(4); 184 properties.put("separator", separator); 185 properties.put("separator.head", headSeparator); 186 return factory.createNameSpace(name, properties); 187 } 188 189 /** 190 * Tests the creation of "My documents" folder name. 191 * This test uses the following factory methods: 192 * 193 * <ul> 194 * <li>{@link NameFactory#createInternationalString(Map)}</li> 195 * </ul> 196 */ 197 @Test 198 public void testInternationalString() { 199 assumeNotNull(factory); 200 final Map<Locale,String> names = new HashMap<>(); 201 names.put(Locale.ENGLISH, "My documents"); 202 names.put(Locale.FRENCH, "Mes documents"); 203 InternationalString localized = factory.createInternationalString(names); 204 validators.validate(localized); 205 if (isMultiLocaleSupported) { 206 configurationTip = Configuration.Key.isMultiLocaleSupported; 207 for (final Map.Entry<Locale,String> entry : names.entrySet()) { 208 assertEquals("toString(Locale) should returns the value given to the factory method.", 209 entry.getValue(), localized.toString(entry.getKey())); 210 } 211 configurationTip = null; 212 } 213 assertContains("toString() should returns one of the values given to the factory method.", 214 names.values(), localized.toString()); 215 } 216 217 /** 218 * Tests the creation of {@code "EPSG:4326"} as local names. First the {@code "EPSG"} 219 * namespace is created. Then a {@code "4326"} local name is created in that namespace. 220 * This test uses the following factory methods: 221 * 222 * <ul> 223 * <li>{@link NameFactory#createLocalName(NameSpace, CharSequence)}</li> 224 * <li>{@link NameFactory#createNameSpace(GenericName, Map)}</li> 225 * </ul> 226 */ 227 @Test 228 public void testLocalName() { 229 assumeNotNull(factory); 230 final String EPSG = "EPSG"; 231 final LocalName authority = factory.createLocalName(null, EPSG); 232 validators.validate(authority); 233 assertTrue(authority.scope().isGlobal()); 234 assertEquals(EPSG, authority.toString()); 235 assertEquals(EPSG, authority.toInternationalString().toString()); 236 237 final NameSpace ns = createNameSpace(authority, ":", ":"); 238 validators.validate(ns); 239 assertEquals(authority, ns.name()); 240 241 final String WGS84 = "4326"; 242 final LocalName code = factory.createLocalName(ns, WGS84); 243 validators.validate(code); 244 assertEquals(ns, code.scope()); 245 assertEquals(WGS84, code.toString()); 246 assertEquals(EPSG + ':' + WGS84, code.toFullyQualifiedName().toString()); 247 } 248 249 /** 250 * Tests the creation of {@code "urn:ogc:def:crs:epsg:4326"} as a scoped name. 251 * This test uses the following factory methods: 252 * 253 * <ul> 254 * <li>{@link NameFactory#createGenericName(NameSpace, CharSequence[])}</li> 255 * </ul> 256 */ 257 @Test 258 public void testScopedName() { 259 assumeNotNull(factory); 260 final String[] parsed = new String[] { 261 "urn","ogc","def","crs","epsg","4326" 262 }; 263 GenericName name = factory.createGenericName(null, parsed); 264 validators.validate(name); 265 266 assertEquals("Name should be already fully qualified.", 267 name, name.toFullyQualifiedName()); 268 269 assertTrue("Fully qualified name should be \"urn:ogc:def:crs:epsg:4326\" (separator may vary).", 270 Pattern.matches("urn\\p{Punct}ogc\\p{Punct}def\\p{Punct}crs\\p{Punct}epsg\\p{Punct}4326", 271 name.toString())); 272 273 assertEquals("Depth shall be counted from the global namespace.", 6, name.depth()); 274 275 for (int i=parsed.length; --i>=0;) { 276 name = name.tip(); 277 validators.validate(name); 278 assertEquals(parsed[i], name.toString()); 279 name = name.scope().name(); 280 } 281 } 282 283 /** 284 * Tests the parsing of {@code "urn:ogc:def:crs:epsg:4326"} as a scoped name. 285 * This test uses the following factory methods: 286 * 287 * <ul> 288 * <li>{@link NameFactory#createLocalName(NameSpace, CharSequence)}</li> 289 * <li>{@link NameFactory#createNameSpace(GenericName, Map)}</li> 290 * <li>{@link NameFactory#parseGenericName(NameSpace, CharSequence)}</li> 291 * </ul> 292 */ 293 @Test 294 public void testParsedURN() { 295 assumeNotNull(factory); 296 final LocalName urn = factory.createLocalName(null, "urn"); 297 validators.validate(urn); 298 final NameSpace ns = createNameSpace(urn, ":", ":"); 299 validators.validate(ns); 300 final GenericName name = factory.parseGenericName(ns, "ogc:def:crs:epsg:4326"); 301 validators.validate(name); 302 303 assertEquals("Depth shall be counted from the \"urn\" namespace.", 5, name.depth()); 304 assertEquals("ogc:def:crs:epsg:4326", name.toString()); 305 assertEquals("urn:ogc:def:crs:epsg:4326", name.toFullyQualifiedName().toString()); 306 } 307 308 /** 309 * Tests the parsing of {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"} as a local name. 310 * This test uses the following factory methods: 311 * 312 * <ul> 313 * <li>{@link NameFactory#createLocalName(NameSpace, CharSequence)}</li> 314 * <li>{@link NameFactory#createNameSpace(GenericName, Map)}</li> 315 * <li>{@link NameFactory#parseGenericName(NameSpace, CharSequence)}</li> 316 * </ul> 317 * 318 * This tests is executed only if {@link #isMixedNameSyntaxSupported} is {@code true}. 319 */ 320 @Test 321 public void testParsedHTTP() { 322 assumeNotNull(factory); 323 assumeTrue(isMixedNameSyntaxSupported); 324 configurationTip = Configuration.Key.isMixedNameSyntaxSupported; 325 GenericName name = factory.createLocalName(null, "http"); 326 assertEquals(1, name.depth()); 327 assertEquals("http", name.head().toString()); 328 assertEquals("http", name.tip().toString()); 329 assertEquals("http", name.toString()); 330 NameSpace ns = createNameSpace(name, "://", "."); 331 validators.validate(ns); 332 333 name = factory.parseGenericName(ns, "www.opengis.net"); 334 assertEquals(3, name.depth()); 335 assertEquals("www", name.head().toString()); 336 assertEquals("net", name.tip().toString()); 337 assertEquals("www.opengis.net", name.toString()); 338 ns = createNameSpace(name, "/", "/"); 339 validators.validate(ns); 340 341 name = factory.parseGenericName(ns, "gml/srs/epsg.xml"); 342 assertEquals(3, name.depth()); 343 assertEquals("gml", name.head().toString()); 344 assertEquals("epsg.xml", name.tip().toString()); 345 assertEquals("gml/srs/epsg.xml", name.toString()); 346 ns = createNameSpace(name, "#", ":"); 347 validators.validate(ns); 348 349 name = factory.createLocalName(ns, "4326"); 350 assertEquals(1, name.depth()); 351 assertEquals("4326", name.head().toString()); 352 assertEquals("4326", name.tip().toString()); 353 assertEquals("4326", name.toString()); 354 validators.validate(name); 355 356 assertEquals("4326", name.toString()); 357 name = name.toFullyQualifiedName(); 358 assertEquals("http://www.opengis.net/gml/srs/epsg.xml#4326", name.toString()); 359 assertEquals(8, name.depth()); 360 assertEquals("http", name.head().toString()); 361 assertEquals("4326", name.tip().toString()); 362 } 363}