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 c55ad2acaa894eb5d58831616bfc3a217baa8eca Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Sat Dec 2 14:59:14 2023 +0100 "SIS" command-line accept arguments of type `Object` instead of being restricted to `String` instances. The intend is to allow invocations from JShell, where the user could pass File, Path, URI, URL, etc. This commit contains also an opportunistic migration of JUnit 4 to JUnit 5 for the impacted tests. --- .../main/org/apache/sis/console/AboutCommand.java | 14 +++-- .../main/org/apache/sis/console/CRSCommand.java | 9 ++- .../main/org/apache/sis/console/Command.java | 37 ++++++++----- .../main/org/apache/sis/console/CommandRunner.java | 64 +++++++++++++++------- .../apache/sis/console/FormattedOutputCommand.java | 18 +++--- .../main/org/apache/sis/console/HelpCommand.java | 3 +- .../org/apache/sis/console/IdentifierCommand.java | 14 ++++- .../main/org/apache/sis/console/InfoCommand.java | 6 +- .../org/apache/sis/console/MetadataCommand.java | 9 ++- .../org/apache/sis/console/MimeTypeCommand.java | 27 +++++---- .../main/org/apache/sis/console/Option.java | 12 ++-- .../org/apache/sis/console/TransformCommand.java | 61 +++++++++++++-------- .../org/apache/sis/console/TranslateCommand.java | 13 ++--- .../org/apache/sis/console/AboutCommandTest.java | 20 +++---- .../org/apache/sis/console/CRSCommandTest.java | 20 +++---- .../org/apache/sis/console/CommandRunnerTest.java | 55 ++++++++----------- .../org/apache/sis/console/HelpCommandTest.java | 54 +++++++++--------- .../apache/sis/console/MetadataCommandTest.java | 14 ++--- .../apache/sis/console/MimeTypeCommandTest.java | 14 ++--- .../org.apache.sis.storage/main/module-info.java | 1 + .../main/org/apache/sis/io/stream/IOUtilities.java | 22 +++++++- 21 files changed, 288 insertions(+), 199 deletions(-) diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/AboutCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/AboutCommand.java index abbb44a5e1..115fbec3b0 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/AboutCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/AboutCommand.java @@ -36,18 +36,19 @@ import org.apache.sis.util.resources.Messages; import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.collection.TreeTable; import org.apache.sis.util.collection.TableColumn; +import org.apache.sis.util.internal.StandardDateFormat; +import org.apache.sis.util.internal.X364; import org.apache.sis.system.Loggers; import org.apache.sis.system.Supervisor; import org.apache.sis.system.SupervisorMBean; import org.apache.sis.system.DataDirectory; -import org.apache.sis.util.internal.StandardDateFormat; -import org.apache.sis.util.internal.X364; +import org.apache.sis.io.stream.IOUtilities; /** * The "about" subcommand. * By default this sub-command prints all information except the {@link About#LIBRARIES} section, - * because the latter is considered too verbose. Available options are: + * because the latter is considered too verbose. Some available options are: * * <ul> * <li>{@code --brief}: prints only Apache SIS version number.</li> @@ -69,7 +70,7 @@ final class AboutCommand extends CommandRunner { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - AboutCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + AboutCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, EnumSet.of(Option.LOCALE, Option.TIMEZONE, Option.ENCODING, Option.BRIEF, Option.VERBOSE, Option.HELP, Option.DEBUG)); } @@ -115,7 +116,10 @@ final class AboutCommand extends CommandRunner { * * Tutorial: http://docs.oracle.com/javase/tutorial/jmx/remote/custom.html */ - final String address = files.get(0); + final String address = IOUtilities.toString(files.get(0)); + if (address == null) { + return Command.INVALID_ARGUMENT_EXIT_CODE; + } final String path = toRemoteURL(address); final long time = System.nanoTime(); final TreeTable table; diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java index 0b2238708e..6baf13a77d 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java @@ -23,7 +23,12 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * The "crs" sub-command. - * CRS are considered as a kind of metadata here. + * CRS are considered as a kind of metadata. + * Some available options are: + * + * <ul> + * <li>{@code --format}: the output format (WKT or XML).</li> + * </ul> * * @author Martin Desruisseaux (Geomatys) */ @@ -31,7 +36,7 @@ final class CRSCommand extends FormattedOutputCommand { /** * Creates the {@code "crs"} sub-command. */ - CRSCommand(final int commandIndex, final String... args) throws InvalidOptionException { + CRSCommand(final int commandIndex, final Object[] args) throws InvalidOptionException { super(commandIndex, args, MetadataCommand.options(), OutputFormat.WKT, OutputFormat.XML); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java index adf3405508..5c1bde2fcd 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java @@ -124,26 +124,34 @@ public final class Command { * Creates a new command for the given arguments. The first value in the given array which is * not an option is taken as the command name. All other values are options or filenames. * + * <p>Arguments should be instances of {@link String}, except the arguments for input or output files + * which can be any types accepted by {@link org.apache.sis.storage.StorageConnector}. This includes, + * for example, {@link String}, {@link java.io.File}, {@link java.nio.file.Path}, {@link java.net.URL}, + * <i>etc.</i></p> + * * @param args the command-line arguments. * @throws InvalidCommandException if an invalid command has been given. * @throws InvalidOptionException if the given arguments contain an invalid option. */ - protected Command(final String[] args) throws InvalidCommandException, InvalidOptionException { + protected Command(final Object[] args) throws InvalidCommandException, InvalidOptionException { int commandIndex = -1; String commandName = null; for (int i=0; i<args.length; i++) { - final String arg = args[i]; - if (arg.startsWith(Option.PREFIX)) { - final String name = arg.substring(Option.PREFIX.length()); - final Option option = Option.forLabel(name); - if (option.hasValue) { - i++; // Skip the next argument. + final Object arg = args[i]; + if (arg instanceof CharSequence) { + final String s = arg.toString(); + if (s.startsWith(Option.PREFIX)) { + final String name = s.substring(Option.PREFIX.length()); + final Option option = Option.forLabel(name); + if (option.hasValue) { + i++; // Skip the next argument. + } + } else { + // Takes the first non-argument option as the command name. + commandName = s; + commandIndex = i; + break; } - } else { - // Takes the first non-argument option as the command name. - commandName = arg; - commandIndex = i; - break; } } if (commandName == null) { @@ -182,7 +190,9 @@ public final class Command { if (command.options.containsKey(Option.HELP)) { command.help(command.commandName.toLowerCase(Locale.US)); } else try { - return command.run(); + int status = command.run(); + command.flush(); + return status; } catch (Exception e) { command.error(null, e); throw e; @@ -280,7 +290,6 @@ public final class Command { } catch (Exception e) { status = exitCodeFor(e); } - c.command.flush(); if (status != 0) { System.exit(status); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CommandRunner.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CommandRunner.java index e76c930c70..44bdc42425 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CommandRunner.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CommandRunner.java @@ -72,8 +72,10 @@ abstract class CommandRunner { /** * The command-line options allowed by this sub-command, together with their values. + * Values are usually instances of {@link String}, but other types are allowed when + * the values is expected to be a file. */ - protected final EnumMap<Option,String> options; + protected final EnumMap<Option,Object> options; /** * The locale specified by the {@code "--locale"} option. If no such option was provided, @@ -128,8 +130,10 @@ abstract class CommandRunner { /** * Any remaining parameters that are not command name or option. * They are typically file names, but can occasionally be other types like URL. + * Values are always instances of {@link String} when SIS is executed from bash, + * but may be other kinds of object when {@link SIS} is executed from JShell. */ - protected final List<String> files; + protected final List<Object> files; /** * Copies the configuration of the given sub-command. This constructor is used @@ -162,10 +166,10 @@ abstract class CommandRunner { * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ @SuppressWarnings("UseOfSystemOutOrSystemErr") - protected CommandRunner(final int commandIndex, final String[] arguments, final EnumSet<Option> validOptions) + protected CommandRunner(final int commandIndex, final Object[] arguments, final EnumSet<Option> validOptions) throws InvalidOptionException { - commandName = (commandIndex >= 0) ? arguments[commandIndex] : null; + commandName = (commandIndex >= 0) ? arguments[commandIndex].toString() : null; this.validOptions = validOptions; options = new EnumMap<>(Option.class); files = new ArrayList<>(arguments.length); @@ -173,14 +177,15 @@ abstract class CommandRunner { if (i == commandIndex) { continue; } - final String arg = arguments[i]; - if (arg.startsWith(Option.PREFIX)) { - final String name = arg.substring(Option.PREFIX.length()); + final Object arg = arguments[i]; + final String s; + if (arg instanceof CharSequence && (s = arg.toString()).startsWith(Option.PREFIX)) { + final String name = s.substring(Option.PREFIX.length()); final Option option = Option.forLabel(name); if (!validOptions.contains(option)) { throw new InvalidOptionException(Errors.format(Errors.Keys.UnknownOption_1, name), name); } - String value = null; + Object value = null; if (option.hasValue) { if (++i >= arguments.length) { throw new InvalidOptionException(Errors.format(Errors.Keys.MissingValueForOption_1, name), name); @@ -199,21 +204,22 @@ abstract class CommandRunner { * Process the --locale, --encoding and --colors options. */ Option option = null; // In case of IllegalArgumentException. - String value = null; + Object value = null; final Console console; final boolean explicitEncoding; try { debug = options.containsKey(option = Option.DEBUG); - value = options.get(option = Option.LOCALE); - locale = (value != null) ? Locales.parse(value) : Locale.getDefault(Locale.Category.DISPLAY); + String s; + value = s = getOptionAsString(option = Option.LOCALE); + locale = (s != null) ? Locales.parse(s) : Locale.getDefault(Locale.Category.DISPLAY); - value = options.get(option = Option.TIMEZONE); - timezone = (value != null) ? TimeZone.getTimeZone(value) : TimeZone.getDefault(); + value = s = getOptionAsString(option = Option.TIMEZONE); + timezone = (s != null) ? TimeZone.getTimeZone(s) : TimeZone.getDefault(); - value = options.get(option = Option.ENCODING); - explicitEncoding = (value != null); - encoding = explicitEncoding ? Charset.forName(value) : Charset.defaultCharset(); + value = s = getOptionAsString(option = Option.ENCODING); + explicitEncoding = (s != null); + encoding = explicitEncoding ? Charset.forName(s) : Charset.defaultCharset(); value = options.get(option = Option.COLORS); console = System.console(); @@ -248,6 +254,23 @@ abstract class CommandRunner { } } + /** + * Returns the value of the specified option as a character string. + * + * @param key the option for which to get a value. + * @return the requested option, or {@code null} if not present. + * @throws InvalidOptionException if the value is not a character string. + */ + final String getOptionAsString(final Option key) throws InvalidOptionException { + final Object value = options.get(key); + if (value == null) return null; + if (value instanceof CharSequence) { + return value.toString(); + } + final String name = key.label(); + throw new InvalidOptionException(Errors.format(Errors.Keys.IllegalOptionValue_2, name, value), name); + } + /** * Return the value of a mandatory option. * @@ -255,8 +278,8 @@ abstract class CommandRunner { * @return the option value, never {@code null}. * @throws InvalidOptionException if the option is missing. */ - final String getMandatoryOption(final Option option) throws InvalidOptionException { - final String value = options.get(option); + final Object getMandatoryOption(final Option option) throws InvalidOptionException { + final Object value = options.get(option); if (value == null) { final String name = option.label(); throw new InvalidOptionException(Errors.format(Errors.Keys.MissingValueForOption_1, name), name); @@ -341,6 +364,7 @@ abstract class CommandRunner { } else { err.println(Exceptions.formatChainedMessages(locale, message, e)); } + err.flush(); } /** @@ -365,8 +389,8 @@ abstract class CommandRunner { public abstract int run() throws Exception; /** - * Invoked before to exit the JVM for flushing and pending information to the output streams. - * The default information flushed {@link #out} and {@link #err} in that order. + * Flushes any pending information to the output streams. + * The default information flushes {@link #out} and {@link #err} in that order. * Subclasses may override if there is more things to flush. */ protected void flush() { diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java index fab233f71c..70c1ceb5a9 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java @@ -95,7 +95,7 @@ abstract class FormattedOutputCommand extends CommandRunner { * @param supportedFormats the output formats to accept. The first format is the default one. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - FormattedOutputCommand(final int commandIndex, final String[] arguments, final EnumSet<Option> validOptions, + FormattedOutputCommand(final int commandIndex, final Object[] arguments, final EnumSet<Option> validOptions, final OutputFormat... supportedFormats) throws InvalidOptionException { super(commandIndex, arguments, validOptions); @@ -104,7 +104,7 @@ abstract class FormattedOutputCommand extends CommandRunner { * Output format can be either "text" (the default) or "xml". * In the case of "crs" sub-command, we accept also WKT variants. */ - final String format = options.get(Option.FORMAT); + final String format = getOptionAsString(Option.FORMAT); if (format == null) { outputFormat = supportedFormats[0]; convention = Convention.WKT2_SIMPLIFIED; @@ -190,14 +190,16 @@ abstract class FormattedOutputCommand extends CommandRunner { hasUnexpectedFileCount = true; return null; } else { - final String file = files.get(0); - if (CodeType.guess(file).isCRS) { - return CRS.forCode(file); - } else { - try (DataStore store = DataStores.open(file)) { - return store.getMetadata(); + final Object file = files.get(0); + if (file instanceof CharSequence) { + final String c = file.toString(); + if (CodeType.guess(c).isCRS) { + return CRS.forCode(c); } } + try (DataStore store = DataStores.open(file)) { + return store.getMetadata(); + } } } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/HelpCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/HelpCommand.java index bbcee10ed0..f374e83e01 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/HelpCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/HelpCommand.java @@ -25,6 +25,7 @@ import org.apache.sis.util.resources.Vocabulary; /** * The "help" subcommand. + * This sub-command prints the same text than when {@code SIS} is invoked on the command-line without arguments. * * @author Martin Desruisseaux (Geomatys) */ @@ -58,7 +59,7 @@ final class HelpCommand extends CommandRunner { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - HelpCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + HelpCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, EnumSet.of(Option.LOCALE, Option.ENCODING, Option.HELP, Option.DEBUG)); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/IdentifierCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/IdentifierCommand.java index 6e0313be3d..60ad797a9a 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/IdentifierCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/IdentifierCommand.java @@ -39,6 +39,11 @@ import org.apache.sis.util.resources.Vocabulary; /** * The "identifier" sub-command. + * Some available options are: + * + * <ul> + * <li>{@code --format}: the output format (text).</li> + * </ul> * * @author Martin Desruisseaux (Geomatys) */ @@ -100,7 +105,7 @@ final class IdentifierCommand extends FormattedOutputCommand { /** * Creates the {@code "identifier"} sub-command. */ - IdentifierCommand(final int commandIndex, final String... args) throws InvalidOptionException { + IdentifierCommand(final int commandIndex, final Object[] args) throws InvalidOptionException { super(commandIndex, args, options(), OutputFormat.TEXT); } @@ -126,7 +131,12 @@ final class IdentifierCommand extends FormattedOutputCommand { final Identifier id = ((Metadata) metadata).getMetadataIdentifier(); if (id != null) { CharSequence desc = id.getDescription(); - if (desc != null && !files.isEmpty()) desc = files.get(0); + if (desc == null && !files.isEmpty()) { + final Object c = files.get(0); + if (c instanceof CharSequence) { + desc = c.toString(); + } + } rows.add(new Row(State.VALID, IdentifiedObjects.toString(id), desc)); } for (final ReferenceSystem rs : ((Metadata) metadata).getReferenceSystemInfo()) { diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java index 4ed829c9b0..b09ab42c2f 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java @@ -63,7 +63,7 @@ final class InfoCommand extends FormattedOutputCommand { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - InfoCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + InfoCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, options(), OutputFormat.TEXT); gridBitMask = GridGeometry.EXTENT | GridGeometry.GEOGRAPHIC_EXTENT | GridGeometry.TEMPORAL_EXTENT | GridGeometry.CRS | GridGeometry.RESOLUTION; @@ -80,15 +80,13 @@ final class InfoCommand extends FormattedOutputCommand { @Override public int run() throws Exception { final Object input; - final String name; if (useStandardInput()) { input = System.in; - name = "stdin"; } else { if (hasUnexpectedFileCount = hasUnexpectedFileCount(1, 1)) { return Command.INVALID_ARGUMENT_EXIT_CODE; } - input = name = files.get(0); + input = files.get(0); } final var tree = new DefaultTreeTable(TableColumn.VALUE_AS_TEXT); try (DataStore store = DataStores.open(input)) { diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java index 61c64bbaad..b12a6b4010 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java @@ -28,7 +28,12 @@ import org.apache.sis.util.collection.TreeTable; /** * The "metadata" sub-command. - * This command shows ISO 19115 metadata for the content of a file. + * This sub-command shows ISO 19115 metadata for the content of a file. + * Some available options are: + * + * <ul> + * <li>{@code --format}: the output format (text, XML or GPX).</li> + * </ul> * * @author Martin Desruisseaux (Geomatys) */ @@ -48,7 +53,7 @@ final class MetadataCommand extends FormattedOutputCommand { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - MetadataCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + MetadataCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, options(), OutputFormat.TEXT, OutputFormat.XML, OutputFormat.GPX); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MimeTypeCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MimeTypeCommand.java index 6119c92b93..5ee89f7c6e 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MimeTypeCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MimeTypeCommand.java @@ -16,6 +16,7 @@ */ package org.apache.sis.console; +import java.util.Arrays; import java.net.URI; import java.net.URISyntaxException; import java.util.EnumSet; @@ -26,6 +27,7 @@ import java.nio.file.FileSystemNotFoundException; import org.apache.sis.storage.DataStores; import org.apache.sis.util.CharSequences; import org.apache.sis.util.resources.Errors; +import org.apache.sis.io.stream.IOUtilities; /** @@ -50,7 +52,7 @@ final class MimeTypeCommand extends CommandRunner { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - MimeTypeCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + MimeTypeCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, EnumSet.of(Option.ENCODING, Option.HELP, Option.DEBUG)); } @@ -66,28 +68,24 @@ final class MimeTypeCommand extends CommandRunner { return Command.INVALID_ARGUMENT_EXIT_CODE; } /* - * Computes the width of the first column, which will contain file names. + * Computes the width of the first column, which will contain the URIs. */ - int width = 0; - for (final String file : files) { - final int length = file.length() + 1; - if (length > width) { - width = length; - } - } + final String[] names = files.stream().map(IOUtilities::toString).toArray(String[]::new); + final int width = Arrays.stream(names).mapToInt(String::length).max().orElse(0) + 1; /* * Now detect and print MIME type. */ - for (final String file : files) { + for (int i=0; i<names.length; i++) { + final Object file = files.get(i); final URI uri; try { - uri = new URI(file); + uri = IOUtilities.toURI(file); } catch (URISyntaxException e) { canNotOpen(0, e); return Command.IO_EXCEPTION_EXIT_CODE; } String type; - if (!uri.isAbsolute()) { + if (uri == null || !uri.isAbsolute()) { /* * If the URI is not absolute, we will not be able to convert to Path. * Open as a String, leaving the conversion to DataStore implementations. @@ -107,9 +105,10 @@ final class MimeTypeCommand extends CommandRunner { * file: type */ if (type != null) { - out.print(file); + final String name = names[i]; + out.print(name); out.print(':'); - out.print(CharSequences.spaces(width - file.length())); + out.print(CharSequences.spaces(width - name.length())); out.println(type); out.flush(); } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Option.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Option.java index 2e9f7537d9..90dd4ca0e2 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Option.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Option.java @@ -99,7 +99,7 @@ enum Option { * Boolean values accepted on the command line. Values at even indices are {@code false} * and values at odd indices are {@code true}. * - * @see #parseBoolean(String) + * @see #parseBoolean(Object) */ private static final String[] BOOLEAN_VALUES = { "false", "true", @@ -166,13 +166,17 @@ enum Option { * @return the value as a boolean. * @throws InvalidOptionException if the given value is not recognized as a boolean. */ - boolean parseBoolean(final String value) throws InvalidOptionException { + boolean parseBoolean(final Object value) throws InvalidOptionException { + if (value instanceof Boolean) { + return (Boolean) value; + } + final String s = value.toString(); for (int i=0; i<BOOLEAN_VALUES.length; i++) { - if (value.equalsIgnoreCase(BOOLEAN_VALUES[i])) { + if (s.equalsIgnoreCase(BOOLEAN_VALUES[i])) { return (i & 1) != 0; } } - final String name = name().toLowerCase(Locale.US); + final String name = label(); throw new InvalidOptionException(Errors.format(Errors.Keys.IllegalOptionValue_2, name, value), name); } } diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java index 2c243135c5..ea45f0ee88 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TransformCommand.java @@ -22,9 +22,10 @@ import java.util.Collection; import java.util.EnumSet; import java.util.Locale; import java.io.IOException; -import java.io.FileInputStream; import java.io.LineNumberReader; import java.io.InputStreamReader; +import java.io.Reader; +import java.io.BufferedReader; import java.text.NumberFormat; import static java.util.logging.Logger.getLogger; import javax.measure.Unit; @@ -57,12 +58,14 @@ import org.apache.sis.referencing.util.ReferencingUtilities; import org.apache.sis.storage.DataStore; import org.apache.sis.storage.DataStores; import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.StorageConnector; import org.apache.sis.storage.base.CodeType; import org.apache.sis.system.Modules; import org.apache.sis.util.CharSequences; import org.apache.sis.util.internal.X364; import org.apache.sis.io.LineAppender; import org.apache.sis.io.TableAppender; +import org.apache.sis.io.stream.IOUtilities; import org.apache.sis.io.wkt.Colors; import org.apache.sis.io.wkt.Transliterator; import org.apache.sis.io.wkt.WKTFormat; @@ -74,6 +77,7 @@ import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox; import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.logging.Logging; +import org.apache.sis.setup.OptionKey; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.referencing.ObjectDomain; @@ -82,6 +86,13 @@ import org.opengis.referencing.ObjectDomain; /** * The "transform" subcommand. * The output is a comma separated values (CSV) file, with {@code '#'} as the first character of comment lines. + * The source and target CRS are mandatory and can be specified as EPSG codes, WKT strings, or read from data files. + * Those information are passed as options: + * + * <ul> + * <li>{@code --sourceCRS}: the coordinate reference system of input points.</li> + * <li>{@code --targetCRS}: the coordinate reference system of output points.</li> + * </ul> * * @author Martin Desruisseaux (Geomatys) */ @@ -147,7 +158,7 @@ final class TransformCommand extends FormattedOutputCommand { /** * Creates the {@code "transform"} sub-command. */ - TransformCommand(final int commandIndex, final String... args) throws InvalidOptionException { + TransformCommand(final int commandIndex, final Object[] args) throws InvalidOptionException { super(commandIndex, args, options(), OutputFormat.WKT, OutputFormat.TEXT); resources = Vocabulary.getResources(locale); } @@ -161,26 +172,28 @@ final class TransformCommand extends FormattedOutputCommand { * @throws FactoryException if the operation failed for another reason. */ private CoordinateReferenceSystem fetchCRS(final Option option) throws InvalidOptionException, FactoryException, DataStoreException { - final String identifier = getMandatoryOption(option); - if (CodeType.guess(identifier).isCRS) try { - return CRS.forCode(identifier); - } catch (NoSuchAuthorityCodeException e) { - final String name = option.label(); - throw new InvalidOptionException(Errors.format(Errors.Keys.IllegalOptionValue_2, name, identifier), e, name); - } else { - final Metadata metadata; - try (DataStore store = DataStores.open(identifier)) { - metadata = store.getMetadata(); + final Object identifier = getMandatoryOption(option); + if (identifier instanceof CharSequence) { + final String c = identifier.toString(); + if (CodeType.guess(c).isCRS) try { + return CRS.forCode(c); + } catch (NoSuchAuthorityCodeException e) { + final String name = option.label(); + throw new InvalidOptionException(Errors.format(Errors.Keys.IllegalOptionValue_2, name, identifier), e, name); } - if (metadata != null) { - for (final ReferenceSystem rs : metadata.getReferenceSystemInfo()) { - if (rs instanceof CoordinateReferenceSystem) { - return (CoordinateReferenceSystem) rs; - } + } + final Metadata metadata; + try (DataStore store = DataStores.open(identifier)) { + metadata = store.getMetadata(); + } + if (metadata != null) { + for (final ReferenceSystem rs : metadata.getReferenceSystemInfo()) { + if (rs instanceof CoordinateReferenceSystem) { + return (CoordinateReferenceSystem) rs; } } - throw new InvalidOptionException(Errors.format(Errors.Keys.UnspecifiedCRS), option.label()); } + throw new InvalidOptionException(Errors.format(Errors.Keys.UnspecifiedCRS), option.label()); } /** @@ -205,8 +218,10 @@ final class TransformCommand extends FormattedOutputCommand { points = readCoordinates(in, "stdin"); } } else { - for (final String file : files) { - try (LineNumberReader in = new LineNumberReader(new InputStreamReader(new FileInputStream(file), encoding))) { + for (final Object file : files) { + final var c = new StorageConnector(file); + c.setOption(OptionKey.ENCODING, encoding); + try (BufferedReader in = IOUtilities.toBuffered(c.commit(Reader.class, "transform"))) { points = readCoordinates(in, file); } } @@ -518,7 +533,7 @@ final class TransformCommand extends FormattedOutputCommand { * @param filename the filename, for error reporting only. * @return the coordinate values. */ - private List<double[]> readCoordinates(final LineNumberReader in, final String filename) throws IOException { + private List<double[]> readCoordinates(final BufferedReader in, Object filename) throws IOException { final List<double[]> points = new ArrayList<>(); try { String line; @@ -529,7 +544,9 @@ final class TransformCommand extends FormattedOutputCommand { } } } catch (NumberFormatException e) { - errorMessage = Errors.format(Errors.Keys.ErrorInFileAtLine_2, filename, in.getLineNumber()); + if ((filename = IOUtilities.toString(filename)) == null) filename = "?"; + Object line = (in instanceof LineNumberReader) ? ((LineNumberReader) in).getLineNumber() : "?"; + errorMessage = Errors.format(Errors.Keys.ErrorInFileAtLine_2, filename, line); errorCause = e; } return points; diff --git a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TranslateCommand.java b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TranslateCommand.java index 0c49519a3d..38864f912e 100644 --- a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TranslateCommand.java +++ b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/TranslateCommand.java @@ -17,7 +17,6 @@ package org.apache.sis.console; import java.util.EnumSet; -import java.nio.file.Path; import java.nio.file.StandardOpenOption; import org.apache.sis.setup.OptionKey; import org.apache.sis.storage.StorageConnector; @@ -35,7 +34,7 @@ import org.apache.sis.util.resources.Errors; /** * The "translate" sub-command. - * This command reads resources and rewrites them in another format. + * This sub-command reads resources and rewrites them in another format. * If more than one source file is specified, then all those files are aggregated in the output file. * This is possible only if the output format supports the storage of an arbitrary number of resources. * @@ -49,7 +48,7 @@ final class TranslateCommand extends CommandRunner { * @param arguments the command-line arguments provided by the user. * @throws InvalidOptionException if an illegal option has been provided, or the option has an illegal value. */ - TranslateCommand(final int commandIndex, final String... arguments) throws InvalidOptionException { + TranslateCommand(final int commandIndex, final Object[] arguments) throws InvalidOptionException { super(commandIndex, arguments, EnumSet.of(Option.OUTPUT, Option.FORMAT, Option.HELP, Option.DEBUG)); } @@ -64,15 +63,15 @@ final class TranslateCommand extends CommandRunner { if (hasUnexpectedFileCount(1, Integer.MAX_VALUE)) { return Command.INVALID_ARGUMENT_EXIT_CODE; } - final String output = getMandatoryOption(Option.OUTPUT); - final String format = options.get(Option.FORMAT); - final var connector = new StorageConnector(Path.of(output)); + final Object output = getMandatoryOption(Option.OUTPUT); + final String format = getOptionAsString(Option.FORMAT); + final var connector = new StorageConnector(output); connector.setOption(OptionKey.OPEN_OPTIONS, new StandardOpenOption[] { StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE }); try (DataStore target = DataStores.openWritable(connector, format)) { - for (final String file : files) { + for (final Object file : files) { try (DataStore source = DataStores.open(file)) { if (target instanceof WritableAggregate) { ((WritableAggregate) target).add(source); diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/AboutCommandTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/AboutCommandTest.java index f1ff81f4ba..18d7eca1b7 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/AboutCommandTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/AboutCommandTest.java @@ -21,7 +21,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.DependsOn; import org.apache.sis.test.TestCase; import static org.apache.sis.test.TestUtilities.getSingleton; @@ -47,7 +47,7 @@ public final class AboutCommandTest extends TestCase { */ @Test public void testDefault() throws Exception { - final AboutCommand test = new AboutCommand(0, CommandRunner.TEST); + final AboutCommand test = new AboutCommand(0, new String[] {CommandRunner.TEST}); test.run(); verify(test.outputBuffer.toString()); } @@ -57,16 +57,16 @@ public final class AboutCommandTest extends TestCase { */ private static void verify(final String result) { String expected = Version.SIS.toString(); - assertTrue(expected, result.contains(expected)); + assertTrue(result.contains(expected), expected); expected = System.getProperty("java.version"); - assertTrue(expected, result.contains(expected)); + assertTrue(result.contains(expected), expected); expected = System.getProperty("os.name"); - assertTrue(expected, result.contains(expected)); + assertTrue(result.contains(expected), expected); expected = System.getProperty("user.home"); - assertTrue(expected, result.contains(expected)); + assertTrue(result.contains(expected), expected); } /** @@ -76,10 +76,10 @@ public final class AboutCommandTest extends TestCase { */ @Test public void testBrief() throws Exception { - final AboutCommand test = new AboutCommand(0, CommandRunner.TEST, "--brief"); + var test = new AboutCommand(0, new String[] {CommandRunner.TEST, "--brief"}); test.run(); - final String result = getSingleton(CharSequences.splitOnEOL(test.outputBuffer.toString().trim())).toString(); - assertTrue(result, result.contains(Version.SIS.toString())); + String result = getSingleton(CharSequences.splitOnEOL(test.outputBuffer.toString().trim())).toString(); + assertTrue(result.contains(Version.SIS.toString()), result); } /** @@ -91,7 +91,7 @@ public final class AboutCommandTest extends TestCase { */ @Test public void testVerbose() throws Exception { - final AboutCommand test = new AboutCommand(0, CommandRunner.TEST, "--verbose"); + var test = new AboutCommand(0, new String[] {CommandRunner.TEST, "--verbose"}); test.run(); verify(test.outputBuffer.toString()); } diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java index e64ca632b1..7eeea70fa0 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java @@ -20,7 +20,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.DependsOn; import org.apache.sis.test.TestCase; @@ -73,10 +73,10 @@ public final class CRSCommandTest extends TestCase { */ @Test public void testCode() throws Exception { - final CRSCommand test = new CRSCommand(0, CommandRunner.TEST, "EPSG:4326"); + var test = new CRSCommand(0, new String[] {CommandRunner.TEST, "EPSG:4326"}); test.run(); - final String wkt = test.outputBuffer.toString(); - assertTrue(wkt, wkt.matches(WGS84)); + String wkt = test.outputBuffer.toString(); + assertTrue(wkt.matches(WGS84), wkt); } /** @@ -87,10 +87,10 @@ public final class CRSCommandTest extends TestCase { @Test @DependsOnMethod("testCode") public void testURN() throws Exception { - final CRSCommand test = new CRSCommand(0, CommandRunner.TEST, "urn:ogc:def:crs:epsg::4326"); + var test = new CRSCommand(0, new String[] {CommandRunner.TEST, "urn:ogc:def:crs:epsg::4326"}); test.run(); - final String wkt = test.outputBuffer.toString(); - assertTrue(wkt, wkt.matches(WGS84)); + String wkt = test.outputBuffer.toString(); + assertTrue(wkt.matches(WGS84), wkt); } /** @@ -101,9 +101,9 @@ public final class CRSCommandTest extends TestCase { @Test @DependsOnMethod("testURN") public void testHTTP() throws Exception { - final CRSCommand test = new CRSCommand(0, CommandRunner.TEST, "http://www.opengis.net/gml/srs/epsg.xml#4326"); + var test = new CRSCommand(0, new String[] {CommandRunner.TEST, "http://www.opengis.net/gml/srs/epsg.xml#4326"}); test.run(); - final String wkt = test.outputBuffer.toString(); - assertTrue(wkt, wkt.matches(WGS84)); + String wkt = test.outputBuffer.toString(); + assertTrue(wkt.matches(WGS84), wkt); } } diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CommandRunnerTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CommandRunnerTest.java index 25afc306d2..c8286f0aa2 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CommandRunnerTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CommandRunnerTest.java @@ -24,7 +24,7 @@ import java.nio.charset.StandardCharsets; // 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; import static org.apache.sis.test.TestUtilities.getSingleton; @@ -74,8 +74,8 @@ public final class CommandRunnerTest extends TestCase { public void testLocale() throws InvalidOptionException { final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--locale", "ja"); assertEquals(Option.LOCALE, getSingleton(c.options.keySet())); - assertSame("locale", Locale.JAPANESE, c.locale); - assertTrue("files.isEmpty()", c.files.isEmpty()); + assertSame(Locale.JAPANESE, c.locale, "locale"); + assertTrue(c.files.isEmpty(), "files.isEmpty()"); } /** @@ -87,9 +87,9 @@ public final class CommandRunnerTest extends TestCase { public void testTimeZone() throws InvalidOptionException { final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--timezone", "JST"); assertEquals(Option.TIMEZONE, getSingleton(c.options.keySet())); - assertEquals("timezone", TimeZone.getTimeZone("JST"), c.timezone); - assertEquals("rawoffset", TimeUnit.HOURS.toMillis(9), c.timezone.getRawOffset()); - assertTrue("files.isEmpty()", c.files.isEmpty()); + assertEquals(TimeZone.getTimeZone("JST"), c.timezone, "timezone"); + assertEquals(TimeUnit.HOURS.toMillis(9), c.timezone.getRawOffset(), "rawoffset"); + assertTrue(c.files.isEmpty(), "files.isEmpty()"); } /** @@ -101,8 +101,8 @@ public final class CommandRunnerTest extends TestCase { public void testEncoding() throws InvalidOptionException { final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--encoding", "UTF-16"); assertEquals(Option.ENCODING, getSingleton(c.options.keySet())); - assertEquals("encoding", StandardCharsets.UTF_16, c.encoding); - assertTrue("files.isEmpty()", c.files.isEmpty()); + assertEquals(StandardCharsets.UTF_16, c.encoding, "encoding"); + assertTrue(c.files.isEmpty(), "files.isEmpty()"); } /** @@ -115,13 +115,12 @@ public final class CommandRunnerTest extends TestCase { public void testOptionMix() throws InvalidOptionException { final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief", "--locale", "ja", "--verbose", "--timezone", "JST"); - assertEquals("options", EnumSet.of( - Option.BRIEF, Option.LOCALE, Option.VERBOSE, Option.TIMEZONE), c.options.keySet()); + assertEquals(EnumSet.of(Option.BRIEF, Option.LOCALE, Option.VERBOSE, Option.TIMEZONE), c.options.keySet(), "options"); // Test specific values. - assertSame ("locale", Locale.JAPANESE, c.locale); - assertEquals("timezone", TimeZone.getTimeZone("JST"), c.timezone); - assertTrue("files.isEmpty()", c.files.isEmpty()); + assertSame(Locale.JAPANESE, c.locale, "locale"); + assertEquals(TimeZone.getTimeZone("JST"), c.timezone, "timezone"); + assertTrue(c.files.isEmpty(), "files.isEmpty()"); } /** @@ -135,13 +134,10 @@ public final class CommandRunnerTest extends TestCase { public void testMissingOptionValue() throws InvalidOptionException { final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief"); // Should not comply. assertEquals(Option.BRIEF, getSingleton(c.options.keySet())); - try { - new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief", "--locale"); - fail("Expected InvalidOptionException"); - } catch (InvalidOptionException e) { - final String message = e.getMessage(); - assertTrue(message.contains("locale")); - } + String message = assertThrows(InvalidOptionException.class, + () -> new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief", "--locale")) + .getMessage(); + assertTrue(message.contains("locale")); } /** @@ -151,13 +147,10 @@ public final class CommandRunnerTest extends TestCase { */ @Test public void testUnexpectedOption() throws InvalidOptionException { - try { - new Dummy(EnumSet.of(Option.HELP, Option.BRIEF), CommandRunner.TEST, "--brief", "--verbose", "--help"); - fail("Expected InvalidOptionException"); - } catch (InvalidOptionException e) { - final String message = e.getMessage(); - assertTrue(message.contains("verbose")); - } + String message = assertThrows(InvalidOptionException.class, + () -> new Dummy(EnumSet.of(Option.HELP, Option.BRIEF), CommandRunner.TEST, "--brief", "--verbose", "--help")) + .getMessage(); + assertTrue(message.contains("verbose")); } /** @@ -167,9 +160,9 @@ public final class CommandRunnerTest extends TestCase { */ @Test public void testHasContradictoryOptions() throws InvalidOptionException { - final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief", "--verbose"); + final var c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "--brief", "--verbose"); assertTrue(c.hasContradictoryOptions(Option.BRIEF, Option.VERBOSE)); - final String message = c.outputBuffer.toString(); + String message = c.outputBuffer.toString(); assertTrue(message.contains("brief")); assertTrue(message.contains("verbose")); } @@ -181,13 +174,13 @@ public final class CommandRunnerTest extends TestCase { */ @Test public void testHasUnexpectedFileCount() throws InvalidOptionException { - final CommandRunner c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "MyFile.txt"); + final var c = new Dummy(EnumSet.allOf(Option.class), CommandRunner.TEST, "MyFile.txt"); assertFalse(c.hasUnexpectedFileCount(0, 1)); assertEquals("", c.outputBuffer.toString()); assertFalse(c.hasUnexpectedFileCount(1, 2)); assertEquals("", c.outputBuffer.toString()); assertTrue(c.hasUnexpectedFileCount(2, 3)); - final String message = c.outputBuffer.toString(); + String message = c.outputBuffer.toString(); assertTrue(message.length() != 0); } } diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/HelpCommandTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/HelpCommandTest.java index 3f226ba49a..c9123f1c01 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/HelpCommandTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/HelpCommandTest.java @@ -20,7 +20,7 @@ import java.io.IOException; // Test dependencies import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import org.apache.sis.test.DependsOn; import org.apache.sis.test.TestCase; @@ -46,16 +46,16 @@ public final class HelpCommandTest extends TestCase { */ @Test public void testDefault() throws InvalidOptionException, IOException { - final HelpCommand test = new HelpCommand(0, CommandRunner.TEST); + var test = new HelpCommand(0, new String[] {CommandRunner.TEST}); test.run(); - final String result = test.outputBuffer.toString(); - assertTrue("Apache SIS", result.startsWith("Apache SIS")); - assertTrue("--locale", result.contains("--locale")); - assertTrue("--encoding", result.contains("--encoding")); - assertTrue("--timezone", result.contains("--timezone")); - assertTrue("--brief", result.contains("--brief")); - assertTrue("--verbose", result.contains("--verbose")); - assertTrue("--help", result.contains("--help")); + String result = test.outputBuffer.toString(); + assertTrue(result.startsWith("Apache SIS")); + assertTrue(result.contains("--locale")); + assertTrue(result.contains("--encoding")); + assertTrue(result.contains("--timezone")); + assertTrue(result.contains("--brief")); + assertTrue(result.contains("--verbose")); + assertTrue(result.contains("--help")); } /** @@ -67,16 +67,16 @@ public final class HelpCommandTest extends TestCase { */ @Test public void testHelp() throws InvalidOptionException, IOException { - final HelpCommand test = new HelpCommand(0, CommandRunner.TEST, "--help"); + var test = new HelpCommand(0, new String[] {CommandRunner.TEST, "--help"}); test.help("help"); - final String result = test.outputBuffer.toString(); - assertTrue ("help", result.startsWith("help")); - assertTrue ("--locale", result.contains("--locale")); - assertTrue ("--encoding", result.contains("--encoding")); - assertFalse("--timezone", result.contains("--timezone")); - assertFalse("--brief", result.contains("--brief")); - assertFalse("--verbose", result.contains("--verbose")); - assertTrue ("--help", result.contains("--help")); + String result = test.outputBuffer.toString(); + assertTrue (result.startsWith("help")); + assertTrue (result.contains("--locale")); + assertTrue (result.contains("--encoding")); + assertFalse(result.contains("--timezone")); + assertFalse(result.contains("--brief")); + assertFalse(result.contains("--verbose")); + assertTrue (result.contains("--help")); } /** @@ -87,11 +87,11 @@ public final class HelpCommandTest extends TestCase { */ @Test public void testEnglishLocale() throws InvalidOptionException, IOException { - final HelpCommand test = new HelpCommand(0, CommandRunner.TEST, "--help", "--locale", "en"); + var test = new HelpCommand(0, new String[] {CommandRunner.TEST, "--help", "--locale", "en"}); test.help("help"); - final String result = test.outputBuffer.toString(); - assertTrue(result, result.contains("Show a help overview.")); - assertTrue(result, result.contains("The locale to use")); + String result = test.outputBuffer.toString(); + assertTrue(result.contains("Show a help overview.")); + assertTrue(result.contains("The locale to use")); } /** @@ -102,10 +102,10 @@ public final class HelpCommandTest extends TestCase { */ @Test public void testFrenchLocale() throws InvalidOptionException, IOException { - final HelpCommand test = new HelpCommand(0, CommandRunner.TEST, "--help", "--locale", "fr"); + var test = new HelpCommand(0, new String[] {CommandRunner.TEST, "--help", "--locale", "fr"}); test.help("help"); - final String result = test.outputBuffer.toString(); - assertTrue(result, result.contains("Affiche un écran d’aide.")); - assertTrue(result, result.contains("Les paramètres régionaux")); + String result = test.outputBuffer.toString(); + assertTrue(result.contains("Affiche un écran d’aide.")); + assertTrue(result.contains("Les paramètres régionaux")); } } diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MetadataCommandTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MetadataCommandTest.java index 2d8fa33298..850072701a 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MetadataCommandTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MetadataCommandTest.java @@ -20,7 +20,7 @@ import java.net.URL; // 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.DependsOn; import org.apache.sis.test.TestCase; @@ -50,7 +50,7 @@ public final class MetadataCommandTest extends TestCase { @Test public void testNetCDF() throws Exception { final URL url = TestData.NETCDF_2D_GEOGRAPHIC.location(); - final MetadataCommand test = new MetadataCommand(0, CommandRunner.TEST, url.toString()); + var test = new MetadataCommand(0, new String[] {CommandRunner.TEST, url.toString()}); test.run(); verifyNetCDF("Metadata", test.outputBuffer.toString()); } @@ -60,10 +60,10 @@ public final class MetadataCommandTest extends TestCase { * This method will check only for some keyword - this is not an extensive check of the result. */ private static void verifyNetCDF(final String expectedHeader, final String result) { - assertTrue(expectedHeader, result.startsWith(expectedHeader)); - assertTrue("Sea Surface Temperature Analysis Model", result.contains("Sea Surface Temperature Analysis Model")); - assertTrue("GCMD Science Keywords", result.contains("GCMD Science Keywords")); - assertTrue("NOAA/NWS/NCEP", result.contains("NOAA/NWS/NCEP")); + assertTrue(result.startsWith(expectedHeader)); + assertTrue(result.contains("Sea Surface Temperature Analysis Model")); + assertTrue(result.contains("GCMD Science Keywords")); + assertTrue(result.contains("NOAA/NWS/NCEP")); } /** @@ -75,7 +75,7 @@ public final class MetadataCommandTest extends TestCase { @DependsOnMethod("testNetCDF") public void testFormatXML() throws Exception { final URL url = TestData.NETCDF_2D_GEOGRAPHIC.location(); - final MetadataCommand test = new MetadataCommand(0, CommandRunner.TEST, url.toString(), "--format", "XML"); + var test = new MetadataCommand(0, new String[] {CommandRunner.TEST, url.toString(), "--format", "XML"}); test.run(); verifyNetCDF("<?xml", test.outputBuffer.toString()); } diff --git a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MimeTypeCommandTest.java b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MimeTypeCommandTest.java index aea2cf35bb..4e53d12049 100644 --- a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MimeTypeCommandTest.java +++ b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/MimeTypeCommandTest.java @@ -20,7 +20,7 @@ import java.net.URL; // Test dependencies import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import org.apache.sis.storage.gpx.TestData; import org.apache.sis.metadata.iso.extent.DefaultExtentTest; import org.apache.sis.test.DependsOn; @@ -48,10 +48,10 @@ public final class MimeTypeCommandTest extends TestCase { @Test public void testWithMetadataXML() throws Exception { final URL url = DefaultExtentTest.getTestFileURL(); - final MimeTypeCommand test = new MimeTypeCommand(0, CommandRunner.TEST, url.toString()); + var test = new MimeTypeCommand(0, new String[] {CommandRunner.TEST, url.toString()}); test.run(); - final String output = test.outputBuffer.toString().trim(); - assertTrue(output, output.endsWith(".xml: application/vnd.iso.19139+xml")); + String output = test.outputBuffer.toString().trim(); + assertTrue(output.endsWith(".xml: application/vnd.iso.19139+xml"), output); } /** @@ -63,9 +63,9 @@ public final class MimeTypeCommandTest extends TestCase { public void testWithMetadataGPX() throws Exception { final URL url = TestData.V1_1.getURL(TestData.METADATA); assertNotNull(url); - final MimeTypeCommand test = new MimeTypeCommand(0, CommandRunner.TEST, url.toString()); + var test = new MimeTypeCommand(0, new String[] {CommandRunner.TEST, url.toString()}); test.run(); - final String output = test.outputBuffer.toString().trim(); - assertTrue(output, output.endsWith("metadata.xml: application/gpx+xml")); + String output = test.outputBuffer.toString().trim(); + assertTrue(output.endsWith("metadata.xml: application/gpx+xml"), output); } } diff --git a/endorsed/src/org.apache.sis.storage/main/module-info.java b/endorsed/src/org.apache.sis.storage/main/module-info.java index b7ce508e35..7e234050d7 100644 --- a/endorsed/src/org.apache.sis.storage/main/module-info.java +++ b/endorsed/src/org.apache.sis.storage/main/module-info.java @@ -68,6 +68,7 @@ module org.apache.sis.storage { org.apache.sis.storage.coveragejson, // In the "incubator" sub-project. org.apache.sis.storage.shapefile, // In the "incubator" sub-project. org.apache.sis.cloud.aws, + org.apache.sis.console, org.apache.sis.gui; // In the "optional" sub-project. exports org.apache.sis.storage.xml to 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 516a4cd6f5..a4232f2849 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 @@ -193,8 +193,8 @@ public final class IOUtilities extends Static { return path.toString(); } /* - * While toString() would work too on the default implementation, the following - * type is not final. So we are better to invoke the dedicated method. + * While `toString()` would work too on the default `File` implementation, + * the class is not final. So we are better to invoke the dedicated method. */ if (path instanceof File) { return ((File) path).getPath(); @@ -202,6 +202,24 @@ public final class IOUtilities extends Static { return null; } + /** + * Converts the given object to an URI if possible, or returns {@code null} otherwise. + * The current implementation recognizes the {@link Path}, {@link File}, {@link URL}, + * {@link URI} and {@link CharSequence} types. + * + * @param path the path for which to return an URI. + * @return the given path as an URI, or {@code null}. + * @throws URISyntaxException if the URI cannot be parsed. + */ + public static URI toURI(final Object path) throws URISyntaxException { + if (path instanceof URI) return (URI) path; + if (path instanceof URL) return ((URL) path).toURI(); + if (path instanceof File) return ((File) path).toURI(); + if (path instanceof Path) return ((Path) path).toUri(); + if (path instanceof CharSequence) return new URI(path.toString()); + return null; + } + /** * 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