Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions shell/src/main/java/org/unigrid/janus/shell/Janus.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,16 @@ private Janus() {
}

public static void main(final String[] args) throws Exception {
final Optional<LaunchOptions> options = options(args);
final CommandLine command = command();
final Optional<LaunchOptions> options;

try {
options = options(command, args);
} catch (IllegalArgumentException | CommandLine.ParameterException e) {
refuse(command, e);
System.exit(USAGE_ERROR);
return;
}

if (options.isPresent()) {
start(application(), options.get());
Expand All @@ -66,28 +75,36 @@ public static void main(final String[] args) throws Exception {

/*
* The command line is Janus's: Oriel takes out the window system and Janus reads what is left, refusing what
* it does not know so that a mistyped option is never quietly ignored. Empty when the help was asked for.
* it does not know so that a mistyped option is never quietly ignored. Empty when the help was asked for,
* which is printed plainly on the command's own output; an option Janus or Oriel does not take is thrown,
* so that main alone decides how Janus ends.
*/
private static Optional<LaunchOptions> options(final String... args) {
final CommandLine command = new CommandLine(new Arguments());
static Optional<LaunchOptions> options(final CommandLine command, final String... args) {
final LaunchOptions options = LaunchOptions.of(args);

LaunchOptions.help().ifPresent(line -> command.getCommandSpec().usageMessage().footer("", "Window:",
" " + line));
if (command.parseArgs(options.remaining().toArray(String[]::new)).isUsageHelpRequested()) {
command.usage(command.getOut());
command.getOut().flush();
return Optional.empty();
}

try {
final LaunchOptions options = LaunchOptions.of(args);
return Optional.of(options);
}

if (command.parseArgs(options.remaining().toArray(String[]::new)).isUsageHelpRequested()) {
LOG.info("{}", command.getUsageMessage());
return Optional.empty();
}
/* A refused command line is answered on the command's error output, the way picocli answers it itself. */
static void refuse(final CommandLine command, final RuntimeException refused) {
command.getErr().println(refused.getMessage());
command.usage(command.getErr());
command.getErr().flush();
}

return Optional.of(options);
} catch (IllegalArgumentException | CommandLine.ParameterException e) {
LOG.error("{}{}{}", e.getMessage(), System.lineSeparator(), command.getUsageMessage());
System.exit(USAGE_ERROR);
return Optional.empty();
}
/* What Janus takes, with the window system Oriel takes listed in the help where it can be chosen. */
static CommandLine command() {
final CommandLine command = new CommandLine(new Arguments());

LaunchOptions.help().ifPresent(line -> command.getCommandSpec().usageMessage().footer("", "Window:",
" " + line));
return command;
}

/* The window and the message shown when it cannot open both go by this name. */
Expand Down
74 changes: 74 additions & 0 deletions shell/src/test/java/org/unigrid/janus/shell/JanusTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
The Janus Wallet
Copyright © 2021-2026 Stiftelsen The Unigrid Foundation

This program is free software: you can redistribute it and/or modify it under the terms of the
addended GNU Affero General Public License as published by the Free Software Foundation, version 3
of the License (see COPYING and COPYING.addendum).

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received an addended copy of the GNU Affero General Public License with this program.
If not, see <http://www.gnu.org/licenses/> and <https://github.com/unigrid-project/janus-java>.
*/

package org.unigrid.janus.shell;

import java.io.PrintWriter;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import picocli.CommandLine;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class JanusTest {
/* What a log line starts with, so that plain output can be told from what went through the logger. */
private static final String LOG_PREFIX = "^\\d{2}:\\d{2}:\\d{2}\\.\\d{3} .*";

private final StringWriter out = new StringWriter();
private final StringWriter err = new StringWriter();
private CommandLine command;

/* picocli colours the help where it takes the console to understand colours, as on the Windows runners, which
puts escape codes inside the text, so the tests read it without them. */
@BeforeEach
public void captureWhatJanusPrints() {
command = Janus.command();
command.setColorScheme(CommandLine.Help.defaultColorScheme(CommandLine.Help.Ansi.OFF));
command.setOut(new PrintWriter(out));
command.setErr(new PrintWriter(err));
}

@Test
public void shouldPrintTheHelpPlainlyAndNotStart() {
assertTrue(Janus.options(command, "--help").isEmpty(), "Janus would start after showing the help");
assertTrue(out.toString().startsWith("Usage: Unigrid"), out.toString());
assertFalse(out.toString().lines().anyMatch(line -> line.matches(LOG_PREFIX)), out.toString());
}

@Test
public void shouldRefuseAnOptionItDoesNotTakeAndSayWhyPlainly() {
final CommandLine.ParameterException refused = assertThrows(CommandLine.ParameterException.class,
() -> Janus.options(command, "--bogus")
);

Janus.refuse(command, refused);
assertTrue(err.toString().startsWith(refused.getMessage()), err.toString());
assertTrue(err.toString().contains("--bogus"), err.toString());
assertTrue(err.toString().contains("Usage: Unigrid"), err.toString());
}

/* Oriel reads the window system on every desktop, even where it hides it from the help, so this holds anywhere. */
@Test
public void shouldRefuseAWindowSystemOrielDoesNotKnow() {
final IllegalArgumentException refused = assertThrows(IllegalArgumentException.class,
() -> Janus.options(command, "--window-system=bogus")
);

assertTrue(refused.getMessage().contains("bogus"), refused.getMessage());
}
}
Loading