diff --git a/gclc/src/main/java/net/bigeon/gclc/command/CommandParameters.java b/gclc/src/main/java/net/bigeon/gclc/command/CommandParameters.java index 23a01b1..1a88464 100644 --- a/gclc/src/main/java/net/bigeon/gclc/command/CommandParameters.java +++ b/gclc/src/main/java/net/bigeon/gclc/command/CommandParameters.java @@ -102,7 +102,7 @@ public final class CommandParameters { * * @param key the key * @return if the key was specified */ - public boolean getBool(final String key) { + public boolean isActive(final String key) { Boolean val = booleanArguments.get(key); return val != null && val.booleanValue(); } diff --git a/gclc/src/main/java/net/bigeon/gclc/command/ParametrizedCommandData.java b/gclc/src/main/java/net/bigeon/gclc/command/ParametrizedCommandData.java index 61b1421..40731f5 100644 --- a/gclc/src/main/java/net/bigeon/gclc/command/ParametrizedCommandData.java +++ b/gclc/src/main/java/net/bigeon/gclc/command/ParametrizedCommandData.java @@ -85,7 +85,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.bigeon.gclc.exception.CommandParsingException; import net.bigeon.gclc.exception.InvalidParameterException; import net.bigeon.gclc.manager.ConsoleInput; -import net.bigeon.gclc.manager.EmptyInput; +import net.bigeon.gclc.utils.EmptyInput; /** An object to handle standardized command parameters. * diff --git a/gclc/src/main/java/net/bigeon/gclc/prompt/CLIPrompter.java b/gclc/src/main/java/net/bigeon/gclc/prompt/CLIPrompter.java index 62b896b..29da40c 100644 --- a/gclc/src/main/java/net/bigeon/gclc/prompt/CLIPrompter.java +++ b/gclc/src/main/java/net/bigeon/gclc/prompt/CLIPrompter.java @@ -70,6 +70,7 @@ package net.bigeon.gclc.prompt; * #L% */ import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -162,33 +163,27 @@ public final class CLIPrompter { * @throws IOException if the manager was closed */ public static boolean promptBoolean(final ConsoleOutput manager, final ConsoleInput input, final String message) throws IOException { - String result = input - .prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES)); + String booleanChoices = message + CLIPrompterMessages.getString(BOOL_CHOICES); + String result = input.prompt(booleanChoices); boolean first = true; - final String choices = CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1) - + ", " + //$NON-NLS-1$ - CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_NO1); - while (!(result - .equalsIgnoreCase(CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1)) - || CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_NO1) - .equalsIgnoreCase(result) - || CLIPrompterMessages.getString("promptbool.choices.no2") //$NON-NLS-1$ - .equalsIgnoreCase(result) - || CLIPrompterMessages.getString("promptbool.choices.yes2") //$NON-NLS-1$ - .equalsIgnoreCase(result))) { + String booleanYesChoice = CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1); + String booleanNoChoice = CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_NO1); + final String choices = MessageFormat.format("{0}, {1}", booleanYesChoice, + booleanNoChoice); + String yes2 = CLIPrompterMessages.getString("promptbool.choices.yes2"); + String no2 = CLIPrompterMessages.getString("promptbool.choices.no2"); + while (!(result.equalsIgnoreCase(booleanYesChoice) + || booleanNoChoice.equalsIgnoreCase(result) + || no2.equalsIgnoreCase(result) || yes2.equalsIgnoreCase(result))) { if (!first) { manager.println(CLIPrompterMessages .getString("promptbool.choices.invalid", choices)); //$NON-NLS-1$ - result = input - .prompt(message + CLIPrompterMessages.getString(BOOL_CHOICES)); + result = input.prompt(booleanChoices); } first = false; } - return result - .equalsIgnoreCase(CLIPrompterMessages.getString(PROMPTBOOL_CHOICES_YES1)) - || result.equalsIgnoreCase( - CLIPrompterMessages.getString("promptbool.choices.yes2")); //$NON-NLS-1$ + return result.equalsIgnoreCase(booleanYesChoice) || result.equalsIgnoreCase(yes2); // $NON-NLS-1$ } /** Prompt for a choice. diff --git a/gclc/src/main/java/net/bigeon/gclc/manager/EmptyInput.java b/gclc/src/main/java/net/bigeon/gclc/utils/EmptyInput.java similarity index 93% rename from gclc/src/main/java/net/bigeon/gclc/manager/EmptyInput.java rename to gclc/src/main/java/net/bigeon/gclc/utils/EmptyInput.java index 86b43e7..8625122 100644 --- a/gclc/src/main/java/net/bigeon/gclc/manager/EmptyInput.java +++ b/gclc/src/main/java/net/bigeon/gclc/utils/EmptyInput.java @@ -36,7 +36,9 @@ * gclc:net.bigeon.gclc.manager.EmptyInput.java * Created on: Nov 13, 2017 */ -package net.bigeon.gclc.manager; +package net.bigeon.gclc.utils; + +import net.bigeon.gclc.manager.ConsoleInput; /*- * #%L @@ -80,6 +82,7 @@ import net.bigeon.gclc.tools.StringProvider; * @author Emmanuel Bigeon */ public final class EmptyInput implements ConsoleInput { + private static final ConstantString CONSTANT_STRING = new ConstantString(""); /** The empty prompter. */ public static final ConsoleInput INSTANCE = new EmptyInput(); @@ -99,7 +102,7 @@ public final class EmptyInput implements ConsoleInput { * @see net.bigeon.gclc.manager.ConsoleInput#getPrompt() */ @Override public StringProvider getPrompt() { - return new ConstantString(""); //$NON-NLS-1$ + return CONSTANT_STRING; //$NON-NLS-1$ } /* (non-Javadoc) diff --git a/gclc/src/main/java/net/bigeon/gclc/utils/PipedConsoleOutput.java b/gclc/src/main/java/net/bigeon/gclc/utils/PipedConsoleOutput.java index 4602509..235fa2a 100644 --- a/gclc/src/main/java/net/bigeon/gclc/utils/PipedConsoleOutput.java +++ b/gclc/src/main/java/net/bigeon/gclc/utils/PipedConsoleOutput.java @@ -143,10 +143,10 @@ public final class PipedConsoleOutput implements ConsoleOutput { * may not be the next line of data. * * @param message the message - * @return the thread to join to wait for message delivery - * @see net.bigeon.gclc.utils.ReadingRunnable#getWaitForDelivery(java.lang.String) */ - public Thread getWaitForDelivery(final String message) { - return reading.getWaitForDelivery(message); + * @throws InterruptedException if the wait on the message was interrupted + * @see net.bigeon.gclc.utils.ReadingRunnable#waitForDelivery(String) */ + public void waitForDelivery(final String message) throws InterruptedException { + reading.waitForDelivery(message); } /* (non-Javadoc) diff --git a/gclc/src/main/java/net/bigeon/gclc/utils/ReadingRunnable.java b/gclc/src/main/java/net/bigeon/gclc/utils/ReadingRunnable.java index f3876aa..24a2034 100644 --- a/gclc/src/main/java/net/bigeon/gclc/utils/ReadingRunnable.java +++ b/gclc/src/main/java/net/bigeon/gclc/utils/ReadingRunnable.java @@ -86,64 +86,6 @@ import java.util.logging.Logger; * @author Emmanuel Bigeon */ public final class ReadingRunnable implements Runnable { - /** The runnable to wait for arrival of a message in the queue. - * - * @author Emmanuel Bigeon */ - private final class ToWaitRunnable implements Runnable { - /** The Object. */ - private final Object obj; - /** The locking object. */ - private final Object start; - /** The message. */ - private final String message; - /** The started status. */ - private boolean started; - - /** Create the waiting runnable. - * - * @param obj the object to lock on - * @param start the object to notify when ready to wait - * @param message the message to wait for */ - public ToWaitRunnable(final Object obj, final Object start, - final String message) { - this.obj = obj; - this.start = start; - this.message = message; - } - - /** Test if the waiting runnable is started. - * - * @return the started */ - public boolean isStarted() { - synchronized (start) { - return started; - } - } - - /* (non-Javadoc) - * @see java.lang.Runnable#run() */ - @Override - public void run() { - synchronized (obj) { - synchronized (start) { - started = true; - start.notifyAll(); - } - while (isRunning()) { - try { - obj.wait(); - if (delivering.equals(message)) { - return; - } - } catch (final InterruptedException e) { - LOGGER.log(Level.SEVERE, THREAD_INTERRUPTION_EXCEPTION, e); - Thread.currentThread().interrupt(); - } - } - } - } - } - /** The thread intteruption logging message. */ private static final String THREAD_INTERRUPTION_EXCEPTION = "Thread interruption exception."; //$NON-NLS-1$ /** The closed pipe message. */ @@ -169,9 +111,6 @@ public final class ReadingRunnable implements Runnable { private final Map messageBlocker = new ConcurrentHashMap<>(); /** The lock. */ private final Object messageBlockerLock = new Object(); - /** The message being delivered. */ - private String delivering; - /** Create a reading runnable. * * @param reader the input to read from */ @@ -237,37 +176,20 @@ public final class ReadingRunnable implements Runnable { return messages.poll(); } } - - /** Get a waiting thread for a specific message delivery. - * - * @param message the message - * @return the thread to join to wait for message delivery */ - public Thread getWaitForDelivery(final String message) { + + public void waitForDelivery(String message) throws InterruptedException { + Object mLock; synchronized (messageBlockerLock) { if (!messageBlocker.containsKey(message)) { messageBlocker.put(message, new Object()); } - final Object obj = messageBlocker.get(message); - final Object start = new Object(); - final ToWaitRunnable waitRunn = new ToWaitRunnable(obj, start, message); - final Thread th = new Thread(waitRunn); - - // Wait for the thread to actually start before unlocking the message queue. - synchronized (start) { - th.start(); - while (!waitRunn.isStarted()) { - try { - start.wait(TIMEOUT); - } catch (final InterruptedException e) { - LOGGER.log(Level.SEVERE, THREAD_INTERRUPTION_EXCEPTION, e); - Thread.currentThread().interrupt(); - } - } - } - return th; + mLock = messageBlocker.get(message); + } + synchronized (mLock) { + mLock.wait(); } } - + /** Test if some data is available. * * @return if a message is waiting @@ -305,7 +227,6 @@ public final class ReadingRunnable implements Runnable { * @param message the message */ private void notifyMessage(final String message) { synchronized (messageBlockerLock) { - delivering = message; final Object mLock = messageBlocker.get(message); if (mLock!=null) { synchronized (mLock) { diff --git a/gclc/src/test/java/net/bigeon/gclc/command/CommandParametersTest.java b/gclc/src/test/java/net/bigeon/gclc/command/CommandParametersTest.java index a6615a3..1074d0b 100644 --- a/gclc/src/test/java/net/bigeon/gclc/command/CommandParametersTest.java +++ b/gclc/src/test/java/net/bigeon/gclc/command/CommandParametersTest.java @@ -154,7 +154,8 @@ public class CommandParametersTest { } /** Test method for - * {@link net.bigeon.gclc.command.CommandParameters#getAdditionals()}. */ + * {@link net.bigeon.gclc.command.CommandParameters#getAdditionals()}. + * @throws CommandParsingException if the parameter parsing failed*/ @Test public final void testGetAdditionals() throws CommandParsingException { final Set strings = new HashSet<>(); @@ -187,7 +188,7 @@ public class CommandParametersTest { } /** Test method for - * {@link net.bigeon.gclc.command.CommandParameters#getBool(java.lang.String)}. + * {@link net.bigeon.gclc.command.CommandParameters#isActive(String)}. * * @throws CommandParsingException if a command parsing failed */ @Test @@ -200,12 +201,12 @@ public class CommandParametersTest { CommandParameters parameters = new CommandParameters(bools, strings, true); - assertFalse(parameters.getBool("ungiven")); - assertFalse(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertFalse(parameters.isActive("boolFlag")); parameters.parseArgs("-boolFlag"); - assertTrue(parameters.getBool("boolFlag")); - assertFalse(parameters.getBool("ungiven")); + assertTrue(parameters.isActive("boolFlag")); + assertFalse(parameters.isActive("ungiven")); try { parameters.parseArgs("-ungiven"); @@ -213,29 +214,29 @@ public class CommandParametersTest { } catch (final CommandParsingException e) { // ok } - assertFalse(parameters.getBool("ungiven")); - assertTrue(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertTrue(parameters.isActive("boolFlag")); parameters = new CommandParameters(bools, strings, false); - assertFalse(parameters.getBool("ungiven")); - assertFalse(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertFalse(parameters.isActive("boolFlag")); try { parameters.parseArgs("-boolFlag"); } catch (final CommandParsingException e) { // ok } - assertTrue(parameters.getBool("boolFlag")); - assertFalse(parameters.getBool("ungiven")); + assertTrue(parameters.isActive("boolFlag")); + assertFalse(parameters.isActive("ungiven")); try { parameters.parseArgs("-ungiven"); } catch (final CommandParsingException e) { // ok } - assertFalse(parameters.getBool("ungiven")); - assertTrue(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertTrue(parameters.isActive("boolFlag")); } /** Test method for @@ -281,29 +282,29 @@ public class CommandParametersTest { CommandParameters parameters = new CommandParameters(bools, strings, true); - assertFalse(parameters.getBool("ungiven")); - assertFalse(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertFalse(parameters.isActive("boolFlag")); parameters.set("boolFlag", true); - assertTrue(parameters.getBool("boolFlag")); - assertFalse(parameters.getBool("ungiven")); + assertTrue(parameters.isActive("boolFlag")); + assertFalse(parameters.isActive("ungiven")); parameters.set("ungiven", true); - assertFalse(parameters.getBool("ungiven")); - assertTrue(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertTrue(parameters.isActive("boolFlag")); parameters = new CommandParameters(bools, strings, false); - assertFalse(parameters.getBool("ungiven")); - assertFalse(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertFalse(parameters.isActive("boolFlag")); parameters.set("boolFlag", true); - assertTrue(parameters.getBool("boolFlag")); - assertFalse(parameters.getBool("ungiven")); + assertTrue(parameters.isActive("boolFlag")); + assertFalse(parameters.isActive("ungiven")); parameters.set("ungiven", true); - assertFalse(parameters.getBool("ungiven")); - assertTrue(parameters.getBool("boolFlag")); + assertFalse(parameters.isActive("ungiven")); + assertTrue(parameters.isActive("boolFlag")); } /** Test method for diff --git a/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandDataTest.java b/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandDataTest.java new file mode 100644 index 0000000..a1d06f0 --- /dev/null +++ b/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandDataTest.java @@ -0,0 +1,29 @@ +package net.bigeon.gclc.command; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import net.bigeon.gclc.exception.InvalidParameterException; + +public class ParametrizedCommandDataTest { + + @Test + public void testAddParameter() throws InvalidParameterException { + ParametrizedCommandData data = new ParametrizedCommandData(); + data.addBooleanParameter("flag"); + data.addStringParameter("arg", false); + try { + data.addBooleanParameter("arg"); + fail("String parameter cannot be converted to flag"); + } catch (InvalidParameterException e) { + // ok + } + try { + data.addStringParameter("flag", false); + fail("Flag parameter cannot be converted to string"); + } catch (InvalidParameterException e) { + // ok + } + } +} diff --git a/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandTest.java b/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandTest.java index 830877f..f220aea 100644 --- a/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandTest.java +++ b/gclc/src/test/java/net/bigeon/gclc/command/ParametrizedCommandTest.java @@ -241,22 +241,22 @@ public class ParametrizedCommandTest { case 3: assertNull(parameters.get(str1)); assertNull(parameters.get(str2)); - assertFalse(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertFalse(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call++; break; case 4: assertEquals(str2, parameters.get(str1)); assertNull(parameters.get(str2)); - assertFalse(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertFalse(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call++; break; case 5: assertEquals(str2, parameters.get(str1)); assertNull(parameters.get(str2)); - assertTrue(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertTrue(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call = 0; break; default: @@ -304,22 +304,22 @@ public class ParametrizedCommandTest { case 0: assertNull(parameters.get(str1)); assertNull(parameters.get(str2)); - assertFalse(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertFalse(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call++; break; case 1: assertEquals(str2, parameters.get(str1)); assertNull(parameters.get(str2)); - assertFalse(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertFalse(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call++; break; case 2: assertEquals(str2, parameters.get(str1)); assertNull(parameters.get(str2)); - assertTrue(parameters.getBool(bool1)); - assertFalse(parameters.getBool(bool2)); + assertTrue(parameters.isActive(bool1)); + assertFalse(parameters.isActive(bool2)); call = 0; break; default: diff --git a/gclc/src/test/java/net/bigeon/gclc/manager/ReadingRunnableTest.java b/gclc/src/test/java/net/bigeon/gclc/manager/ReadingRunnableTest.java index a780fb8..d41a52a 100644 --- a/gclc/src/test/java/net/bigeon/gclc/manager/ReadingRunnableTest.java +++ b/gclc/src/test/java/net/bigeon/gclc/manager/ReadingRunnableTest.java @@ -118,7 +118,7 @@ public class ReadingRunnableTest { } /** Test method for - * {@link net.bigeon.gclc.utils.ReadingRunnable#getWaitForDelivery(java.lang.String)}. + * {@link net.bigeon.gclc.utils.ReadingRunnable#waitForDelivery(String)}. * * @throws InterruptedException if the test failed * @throws IOException if the test failed */ @@ -131,7 +131,19 @@ public class ReadingRunnableTest { final ReadingRunnable runnable = new ReadingRunnable(reader); final Thread th0 = new Thread(runnable, "read"); th0.start(); - final Thread th = runnable.getWaitForDelivery("msg"); + Thread th = new Thread(new Runnable() { + + @Override + public void run() { + try { + runnable.waitForDelivery("msg"); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }); + th.start(); out.write(Charset.forName("UTF-8").encode("msg" + System.lineSeparator()) .array()); diff --git a/gclc/src/test/java/net/bigeon/gclc/utils/EmptyInputTest.java b/gclc/src/test/java/net/bigeon/gclc/utils/EmptyInputTest.java new file mode 100644 index 0000000..3a25426 --- /dev/null +++ b/gclc/src/test/java/net/bigeon/gclc/utils/EmptyInputTest.java @@ -0,0 +1,67 @@ +package net.bigeon.gclc.utils; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import net.bigeon.gclc.manager.ConsoleInput; +import net.bigeon.gclc.tools.ConstantString; +import net.bigeon.gclc.utils.EmptyInput; + +public class EmptyInputTest { + + @Test + public void testClose() throws IOException { + ConsoleInput input = EmptyInput.INSTANCE; + // several close operation shold create no error + input.close(); + input.close(); + assertFalse("This source input should never be closed", input.isClosed()); + } + + @Test + public void testGetPrompt() { + + ConsoleInput input = EmptyInput.INSTANCE; + String init = input.getPrompt().apply(); + input.setPrompt("some prompt different from "+init); + assertEquals("Prompts should not be changed", init, input.getPrompt().apply()); + + input.setPrompt(new ConstantString("some other prompt different from "+init)); + assertEquals("Prompts should not be changed", init, input.getPrompt().apply()); + } + + @Test + public void testInterruptPrompt() { + // Nothing to test, really... + ConsoleInput input = EmptyInput.INSTANCE; + // several close operation shold create no error + input.interruptPrompt(); + assertFalse("This source input should never be closed", input.isClosed()); + } + + @Test + public void testIsClosed() throws IOException { + ConsoleInput input = EmptyInput.INSTANCE; + // several close operation shold create no error + assertFalse("This source input should never be closed", input.isClosed()); + input.close(); + assertFalse("This source input should never be closed", input.isClosed()); + input.close(); + assertFalse("This source input should never be closed", input.isClosed()); + } + + @Test + public void testPrompt() throws IOException { + ConsoleInput input = EmptyInput.INSTANCE; + // several close operation shold create no error + assertEquals("Any prompt should return the empty value", "", input.prompt()); + assertEquals("Any prompt should return the empty value", "", input.prompt(0)); + assertEquals("Any prompt should return the empty value", "", input.prompt(12)); + assertEquals("Any prompt should return the empty value", "", input.prompt("Test")); + assertEquals("Any prompt should return the empty value", "", input.prompt("Test", 0)); + assertEquals("Any prompt should return the empty value", "", input.prompt("Test", 12)); + } +} diff --git a/gclc/src/test/java/net/bigeon/gclc/utils/SinkOutputTest.java b/gclc/src/test/java/net/bigeon/gclc/utils/SinkOutputTest.java new file mode 100644 index 0000000..cbbc0b6 --- /dev/null +++ b/gclc/src/test/java/net/bigeon/gclc/utils/SinkOutputTest.java @@ -0,0 +1,31 @@ +package net.bigeon.gclc.utils; + +import static org.junit.Assert.assertFalse; + +import java.io.IOException; + +import org.junit.Test; + +import net.bigeon.gclc.manager.ConsoleOutput; + +public class SinkOutputTest { + + @Test + public void testClose() throws Exception { + ConsoleOutput output = SinkOutput.INSTANCE; + // several close operation shold create no error + output.close(); + output.close(); + assertFalse("This source input should never be closed", output.isClosed()); + } + + @Test + public void testPrint() throws IOException { + ConsoleOutput output = SinkOutput.INSTANCE; + // several close operation shold create no error + output.print("Anything"); + output.println("Anything"); + output.println(); + assertFalse("This source input should never be closed", output.isClosed()); + } +}