This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 172d3c1866dd638f8ae9fd550385dfe134d80924
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Dec 9 14:44:34 2023 +0100

    Allow to specify a metadata auxiliary file using wildcard.
    For example if the main file is "city-center.tiff" and metadata path
    is "*.xml", then the actual metadata file will be "city-center.xml".
---
 .../main/org/apache/sis/io/stream/IOUtilities.java |  61 +++++++----
 .../main/org/apache/sis/storage/DataOptionKey.java |   5 +
 .../org/apache/sis/storage/base/PRJDataStore.java  |   6 +-
 .../org/apache/sis/storage/base/URIDataStore.java  | 115 ++++++++++++++++++---
 .../sis/storage/esri/RawRasterStoreProvider.java   |   5 +-
 .../apache/sis/storage/folder/WritableStore.java   |   3 +-
 .../apache/sis/storage/image/WorldFileStore.java   |   5 +-
 .../org/apache/sis/io/stream/IOUtilitiesTest.java  |  15 +--
 8 files changed, 168 insertions(+), 47 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
index a4232f2849..9c3d270eb4 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
@@ -72,6 +72,18 @@ public final class IOUtilities extends Static {
      */
     public static final String CURRENT_DIRECTORY_SYMBOL = ".";
 
+    /**
+     * The separator between a filename components in an URI.
+     * Declared for making easier to identify the code doing such separation.
+     */
+    public static final char URI_PATH_SEPARATOR = '/';
+
+    /**
+     * The separator between a filename and its suffix.
+     * Declared for making easier to identify the code doing such separation.
+     */
+    public static final char EXTENSION_SEPARATOR = '.';
+
     /**
      * Do not allow instantiation of this class.
      */
@@ -113,7 +125,7 @@ public final class IOUtilities extends Static {
      * {@link URI} or {@link CharSequence} instance. If no extension is found, 
returns an empty string.
      * If the given object is of unknown type, return {@code null}.
      *
-     * @param  path  the filename extension (may be an empty string), or 
{@code null} if unknown.
+     * @param  path  the path as an instance of one of the above-cited types, 
or {@code null}.
      * @return the extension in the given path, or an empty string if none, or 
{@code null}
      *         if the given object is null or of unknown type.
      */
@@ -123,6 +135,11 @@ public final class IOUtilities extends Static {
 
     /**
      * Implementation of {@link #filename(Object)} and {@link 
#extension(Object)} methods.
+     *
+     * @param  path      the path as an instance of the types listed in public 
methods, or {@code null}.
+     * @param  exension  {@code true} for requesting the extension instead of 
the file name.
+     * @return the filename or extension in the given path, or an empty string 
if none, or {@code null}
+     *         if the given object is null or of unknown type.
      */
     private static String part(final Object path, final boolean extension) {
         int fromIndex = 0;
@@ -132,10 +149,12 @@ public final class IOUtilities extends Static {
             name = ((File) path).getName();
             end  = name.length();
         } else if (path instanceof Path) {
-            name = ((Path) path).getFileName().toString();
+            final Path tip = ((Path) path).getFileName();
+            if (tip == null) return null;
+            name = tip.toString();
             end  = name.length();
         } else {
-            char separator = '/';
+            char separator = URI_PATH_SEPARATOR;
             if (path instanceof URL) {
                 name = ((URL) path).getPath();
             } else if (path instanceof URI) {
@@ -155,8 +174,8 @@ public final class IOUtilities extends Static {
             end = name.length();
             do {
                 if (--end < 0) return "";               // `end` is 
temporarily inclusive in this loop.
-                fromIndex = name.lastIndexOf('/', end);
-                if (separator != '/') {
+                fromIndex = name.lastIndexOf(URI_PATH_SEPARATOR, end);
+                if (separator != URI_PATH_SEPARATOR) {
                     // Search for platform-specific character only if the 
object is neither a URL or a URI.
                     fromIndex = Math.max(fromIndex, 
name.lastIndexOf(separator, end));
                 }
@@ -165,7 +184,7 @@ public final class IOUtilities extends Static {
             end++;                                      // Make exclusive.
         }
         if (extension) {
-            fromIndex = CharSequences.lastIndexOf(name, '.', fromIndex, end) + 
1;
+            fromIndex = CharSequences.lastIndexOf(name, EXTENSION_SEPARATOR, 
fromIndex, end) + 1;
             if (fromIndex <= 1) {
                 // If the dot is the first character, do not consider as a 
filename extension.
                 return "";
@@ -221,16 +240,19 @@ public final class IOUtilities extends Static {
     }
 
     /**
-     * Converts the given URI to a new URI with the same path except for the 
file extension,
-     * which is replaced by the given extension. This method is used for 
opening auxiliary files
-     * such as {@code "*.prj"} and {@code "*.tfw"} files that come with e.g. 
TIFF files.
+     * Converts the given URI to a new URI with the same path except for the 
filename or extension.
+     * This method is used for opening auxiliary files such as {@code "*.prj"} 
and {@code "*.tfw"}
+     * files that come with e.g. TIFF files.
      *
-     * @param  location   the URI to convert to a URL with a different 
extension, or {@code null}.
-     * @param  extension  the file extension (without {@code '.'}) of the 
auxiliary file.
+     * @param  location     the URI to convert to a URL with a different 
extension, or {@code null}.
+     * @param  replacement  the filename (including extension) or file 
extension (without {@code '.'}) of the auxiliary file.
+     * @param  extension    whether the replacement is the filename or only 
the file extension.
      * @return URI for the auxiliary file with the given extension, or {@code 
null} if none.
      * @throws URISyntaxException if the URI cannot be reconstructed.
      */
-    public static URI toAuxiliaryURI(final URI location, final String 
extension) throws URISyntaxException {
+    public static URI toAuxiliaryURI(final URI location, final String 
replacement, final boolean extension)
+            throws URISyntaxException
+    {
         if (location == null || !location.isAbsolute() || location.isOpaque()) 
{
             return null;
         }
@@ -242,11 +264,12 @@ public final class IOUtilities extends Static {
                 s = path.length();
             }
         }
-        s = path.lastIndexOf('.', s);
-        if (s >= 0) {
-            path = path.substring(0, s+1) + extension;
+        final int base = path.lastIndexOf(URI_PATH_SEPARATOR, s);
+        s = extension ? path.lastIndexOf(EXTENSION_SEPARATOR, s) : base;
+        if (!extension || s > base) {
+            path = path.substring(0, s+1) + replacement;
         } else {
-            path = path + '.' + extension;
+            path = path + EXTENSION_SEPARATOR + replacement;
         }
         return new URI(location.getScheme(),            // http, https, file 
or jar.
                        location.getRawAuthority(),      // Host name or 
literal IP address.
@@ -264,10 +287,10 @@ public final class IOUtilities extends Static {
     public static String filenameWithoutExtension(String path) {
         if (path != null) {
             int s = path.lastIndexOf(File.separatorChar);
-            if (s < 0 && File.separatorChar != '/') {
-                s = path.lastIndexOf('/');
+            if (s < 0 && File.separatorChar != URI_PATH_SEPARATOR) {
+                s = path.lastIndexOf(URI_PATH_SEPARATOR);
             }
-            int e = path.lastIndexOf('.');
+            int e = path.lastIndexOf(EXTENSION_SEPARATOR);
             if (e <= ++s) {
                 e = path.length();
             }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataOptionKey.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataOptionKey.java
index 44d069e4e1..116ff542cf 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataOptionKey.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataOptionKey.java
@@ -50,6 +50,11 @@ public final class DataOptionKey<T> extends OptionKey<T> {
      * If the file exists, it is parsed and its content is merged or appended 
after the
      * metadata read by the storage. If the file does not exist, then it is 
ignored.
      *
+     * <h4>Wildcard</h4>
+     * It the {@code '*'} character is present in the path, then it is 
replaced by the name of the
+     * main file without its extension. For example if the main file is {@code 
"city-center.tiff"},
+     * then {@code "*.xml"} will become {@code "city-center.xml"}.
+     *
      * @since 1.5
      */
     public static final OptionKey<Path> METADATA_PATH =
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
index 5bd4edcebd..3249a57314 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
@@ -204,7 +204,7 @@ public abstract class PRJDataStore extends URIDataStore {
             stream = Files.newInputStream(path);
             source = path;
         } else try {
-            final URI uri = IOUtilities.toAuxiliaryURI(location, extension);
+            final URI uri = IOUtilities.toAuxiliaryURI(location, extension, 
true);
             if (uri == null) {
                 return null;
             }
@@ -437,8 +437,8 @@ public abstract class PRJDataStore extends URIDataStore {
      */
     private static String getBaseFilename(final Path path) {
         final String base = path.getFileName().toString();
-        final int s = base.lastIndexOf('.');
-        return (s >= 0) ? base.substring(0, s+1) : base + '.';
+        final int s = base.lastIndexOf(IOUtilities.EXTENSION_SEPARATOR);
+        return (s >= 0) ? base.substring(0, s+1) : base + 
IOUtilities.EXTENSION_SEPARATOR;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
index df7f1141ae..856b34f6f8 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.base;
 
+import java.util.Arrays;
 import java.util.Optional;
 import java.io.DataInput;
 import java.io.DataOutput;
@@ -28,6 +29,7 @@ import java.nio.file.Files;
 import java.nio.file.OpenOption;
 import java.nio.file.StandardOpenOption;
 import java.nio.charset.Charset;
+import java.net.URISyntaxException;
 import jakarta.xml.bind.JAXBException;
 import org.opengis.util.GenericName;
 import org.opengis.parameter.ParameterValueGroup;
@@ -75,6 +77,8 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
     /**
      * Path to an auxiliary file providing metadata as path, or {@code null} 
if none or not applicable.
      * Unless absolute, this path is relative to the {@link #location} or to 
the {@link #locationAsPath}.
+     * The path may contain the {@code '*'} character, which need to be 
replaced by the main file name
+     * without suffix at reading time.
      */
     private final Path metadataPath;
 
@@ -134,31 +138,100 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
     }
 
     /**
-     * Returns the path to the auxiliary metadata file, or {@code null} if 
none.
-     * This is a path build from the "metadata path" option if present.
+     * {@return the path to the auxiliary metadata file, or {@code null} if 
none}.
+     * This is a path built from the {@link DataOptionKey#METADATA_PATH} value 
if present.
+     * Note that the metadata may be unavailable as a {@link Path} but 
available as an {@link URI}.
      */
-    private Path getMetadataPath() {
-        if (metadataPath != null && locationAsPath != null) {
-            Path path = locationAsPath.getParent();
+    private Path getMetadataPath() throws IOException {
+        Path path = replaceWildcard(metadataPath);
+        if (path != null) {
+            Path parent = locationAsPath;
+            if (parent != null) {
+                parent = parent.getParent();
+                if (parent != null) {
+                    path = parent.resolve(path);
+                }
+            }
+            if (Files.isSameFile(path, locationAsPath)) {
+                return null;
+            }
+        }
+        return path;
+    }
+
+    /**
+     * {@return the URI to the auxiliary metadata file, or {@code null} if 
none}.
+     * This is a path built from the {@link DataOptionKey#METADATA_PATH} value 
if present.
+     * Note that the metadata may be unavailable as an {@link URI} but 
available as a {@link Path}.
+     */
+    private URI getMetadataURI() throws URISyntaxException {
+        URI uri = location;
+        if (uri != null) {
+            final Path path = replaceWildcard(metadataPath);
             if (path != null) {
-                return path.resolve(metadataPath);
+                uri = IOUtilities.toAuxiliaryURI(uri, path.toString(), false);
+                if (!uri.equals(location)) {
+                    return uri;
+                }
             }
         }
         return null;
     }
 
+    /**
+     * Returns the given path with the wildcard character replaced by the name 
of the main file.
+     *
+     * @param  path  path in which to replace wildcard character, or {@code 
null}.
+     * @return path with wildcard character replaced, or {@code path} if no 
replacement was done,
+     *         or {@code null} if a replacement was required but couldn't be 
done.
+     */
+    private Path replaceWildcard(Path path) {
+        if (path != null) {
+            boolean changed = false;
+            String filename = null;     // Determined when first needed.
+            final var names = new String[path.getNameCount()];
+            int count = 0;
+            for (final Path p : path) {
+                String name = p.toString();
+                if (name.indexOf('*') >= 0) {
+                    if (filename == null) {
+                        filename = IOUtilities.filename(locationAsPath != null 
? locationAsPath : location);
+                        if (filename == null) {
+                            return null;
+                        }
+                        final int s = 
filename.lastIndexOf(IOUtilities.EXTENSION_SEPARATOR);
+                        if (s >= 0) {
+                            filename = filename.substring(0, s);
+                        }
+                    }
+                    name = name.replace("*", filename);
+                    changed = true;
+                }
+                names[count++] = name;
+            }
+            if (changed) {
+                path = path.getFileSystem().getPath(names[0], 
Arrays.copyOfRange(names, 1, count));
+            }
+        }
+        return path;
+    }
+
     /**
      * Returns the main and metadata locations as {@code Path} components, or 
an empty array if none.
      * The default implementation returns the storage specified at 
construction time converted to a {@link Path}
      * if such conversion was possible, or {@code null} otherwise.
      *
      * @return the URI as a path, or an empty array if unknown.
-     * @throws DataStoreException if the URI cannot be converted to a {@link 
Path}.
+     * @throws DataStoreException if an error occurred while getting the paths.
      */
     @Override
     public Path[] getComponentFiles() throws DataStoreException {
-        final var paths = new Path[] {locationAsPath, getMetadataPath()};
-        return ArraysExt.resize(paths, ArraysExt.removeDuplicated(paths, 
ArraysExt.removeNulls(paths)));
+        try {
+            final var paths = new Path[] {locationAsPath, getMetadataPath()};
+            return ArraysExt.resize(paths, ArraysExt.removeDuplicated(paths, 
ArraysExt.removeNulls(paths)));
+        } catch (IOException e) {
+            throw new DataStoreException(e);
+        }
     }
 
     /**
@@ -404,12 +477,28 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
      * @param  builder  where to merge the metadata.
      */
     protected final void mergeAuxiliaryMetadata(final MetadataBuilder builder) 
{
-        final Path path = getMetadataPath();
-        if (path != null) try {
-            builder.mergeMetadata(XML.unmarshal(path), getLocale());
+        Object metadata = null;
+        Exception error = null;
+        try {
+            final Path path = getMetadataPath();
+            if (path != null) {
+                metadata = XML.unmarshal(path);
+            } else {
+                final URI uri = getMetadataURI();
+                if (uri != null) {
+                    metadata = XML.unmarshal(uri.toURL());
+                }
+            }
+        } catch (URISyntaxException | IOException e) {
+            error = e;
         } catch (JAXBException e) {
             final Throwable cause = e.getCause();
-            listeners.warning(cannotReadAuxiliaryFile("xml"), (cause 
instanceof IOException) ? (Exception) cause : e);
+            error = (cause instanceof IOException) ? (Exception) cause : e;
+        }
+        if (metadata != null) {
+            builder.mergeMetadata(metadata, getLocale());
+        } else if (error != null) {
+            listeners.warning(cannotReadAuxiliaryFile("xml"), error);
         }
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RawRasterStoreProvider.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RawRasterStoreProvider.java
index f5b2a05a14..f46423d2dc 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RawRasterStoreProvider.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/esri/RawRasterStoreProvider.java
@@ -28,6 +28,7 @@ import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.base.Capability;
 import org.apache.sis.storage.base.StoreMetadata;
 import org.apache.sis.storage.base.PRJDataStore;
+import org.apache.sis.io.stream.IOUtilities;
 
 
 /**
@@ -92,8 +93,8 @@ public final class RawRasterStoreProvider extends 
PRJDataStore.Provider {
         Path path = connector.getStorageAs(Path.class);
         if (path != null) {
             String filename = path.getFileName().toString();
-            final int s = filename.lastIndexOf('.');
-            filename = ((s >= 0) ? filename.substring(0, s+1) : 
filename.concat(".")).concat(HDR);
+            final int s = 
filename.lastIndexOf(IOUtilities.EXTENSION_SEPARATOR);
+            filename = ((s >= 0) ? filename.substring(0, s+1) : filename + 
IOUtilities.EXTENSION_SEPARATOR) + HDR;
             path = path.resolveSibling(filename);
             if (Files.isRegularFile(path)) {
                 // TODO: maybe we should do more tests here (open the file?)
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/WritableStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/WritableStore.java
index 1f9f65e780..d89e0b6641 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/WritableStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/WritableStore.java
@@ -37,6 +37,7 @@ import org.apache.sis.storage.ReadOnlyStorageException;
 import org.apache.sis.storage.base.StoreUtilities;
 import org.apache.sis.storage.base.ResourceOnFileSystem;
 import org.apache.sis.storage.internal.Resources;
+import org.apache.sis.io.stream.IOUtilities;
 import org.apache.sis.util.ArgumentChecks;
 
 
@@ -99,7 +100,7 @@ final class WritableStore extends Store implements 
WritableAggregate {
         String filename = identifier.toString();
         final String[] suffixes = 
StoreUtilities.getFileSuffixes(componentProvider.getClass());
         if (suffixes.length != 0) {
-            filename += '.' + suffixes[0];
+            filename += IOUtilities.EXTENSION_SEPARATOR + suffixes[0];
         }
         /*
          * Create new store/resource for write access, provided that no store 
already exist for the path.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
index 5293f2c541..d6014cee80 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/WorldFileStore.java
@@ -38,6 +38,7 @@ import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.referencing.datum.PixelInCell;
 import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.io.stream.IOUtilities;
 import org.apache.sis.storage.Resource;
 import org.apache.sis.storage.Aggregate;
 import org.apache.sis.storage.StorageConnector;
@@ -50,10 +51,10 @@ import org.apache.sis.storage.UnsupportedStorageException;
 import org.apache.sis.storage.base.PRJDataStore;
 import org.apache.sis.storage.base.MetadataBuilder;
 import org.apache.sis.referencing.util.j2d.AffineTransform2D;
+import org.apache.sis.metadata.sql.MetadataStoreException;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.internal.ListOfUnknownSize;
-import org.apache.sis.metadata.sql.MetadataStoreException;
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.setup.OptionKey;
@@ -397,7 +398,7 @@ loop:   for (int convention=0;; convention++) {
             throw new 
EOFException(errors().getString(Errors.Keys.UnexpectedEndOfFile_1, filename));
         }
         if (filename != null) {
-            final int s = filename.lastIndexOf('.');
+            final int s = 
filename.lastIndexOf(IOUtilities.EXTENSION_SEPARATOR);
             if (s >= 0) {
                 suffixWLD = filename.substring(s+1);
             }
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
index 44b759565a..e1ebfc728b 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
@@ -26,7 +26,7 @@ import org.apache.sis.util.CharSequences;
 
 // Test dependencies
 import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 
@@ -122,15 +122,16 @@ public final class IOUtilitiesTest extends TestCase {
     }
 
     /**
-     * Tests {@link IOUtilities#toAuxiliaryURI(URI, int)}.
+     * Tests {@link IOUtilities#toAuxiliaryURI(URI, String, boolean)}.
      *
      * @throws URISyntaxException if a URI cannot be parsed.
      * @throws MalformedURLException if a URL cannot be parsed.
      */
     @Test
     public void testAuxiliaryURI() throws URISyntaxException, 
MalformedURLException {
-        assertEquals(new URI("http://localhost/directory/image.tfw";),
-                IOUtilities.toAuxiliaryURI(new 
URI("http://localhost/directory/image.tiff";), "tfw"));
+        final var src = new 
URI("http://localhost/directory/image.tiff?request=ignore.me";);
+        assertEquals(new URI("http://localhost/directory/image.tfw";),    
IOUtilities.toAuxiliaryURI(src, "tfw", true));
+        assertEquals(new URI("http://localhost/directory/metadata.xml";), 
IOUtilities.toAuxiliaryURI(src, "metadata.xml", false));
     }
 
     /**
@@ -210,11 +211,11 @@ public final class IOUtilitiesTest extends TestCase {
      * @throws IOException if a URL cannot be parsed.
      */
     private void testToFile(final String encoding, final String plus) throws 
IOException {
-        assertEquals("Unix absolute path.", new File("/Users/name/Map.png"),
+        assertEquals(new File("/Users/name/Map.png"),                   // 
Unix absolute path.
                 
IOUtilities.toFile(IOUtilities.toURL("file:/Users/name/Map.png", encoding)));
-        assertEquals("Path with space.", new File("/Users/name/Map with 
spaces.png"),
+        assertEquals(new File("/Users/name/Map with spaces.png"),       // 
Path with space.
                 IOUtilities.toFile(IOUtilities.toURL("file:/Users/name/Map 
with spaces.png", encoding)));
-        assertEquals("Path with + sign.", new 
File("/Users/name/++t--++est.shp"),
+        assertEquals(new File("/Users/name/++t--++est.shp"),            // 
Path with + sign.
                 IOUtilities.toFile(IOUtilities.toURL(
                         
CharSequences.replace("file:/Users/name/++t--++est.shp", "+", plus).toString(), 
encoding)));
     }

Reply via email to