Mercurial > hg > release > thermostat-0.13
changeset 208:e2342d02286f
Implement help command.
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-April/000707.html
line wrap: on
line diff
--- a/cli/src/main/java/com/redhat/thermostat/cli/Command.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/Command.java Thu Apr 05 14:29:15 2012 +0200 @@ -42,4 +42,7 @@ String getName(); + String getDescription(); + + String getUsage(); }
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContext.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/CommandContext.java Thu Apr 05 14:29:15 2012 +0200 @@ -42,4 +42,6 @@ String[] getArguments(); + CommandRegistry getCommandRegistry(); + }
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/CommandContextFactory.java Thu Apr 05 14:29:15 2012 +0200 @@ -36,9 +36,9 @@ package com.redhat.thermostat.cli; -abstract class CommandContextFactory { +class CommandContextFactory { - private static CommandContextFactory instance = new CommandContextFactoryImpl(); + private static CommandContextFactory instance = new CommandContextFactory(); static CommandContextFactory getInstance() { return instance; @@ -48,6 +48,14 @@ instance = ctxFactory; } - abstract CommandContext createContext(String[] args); + private CommandRegistry commandRegistry = new CommandRegistry(); + + CommandContext createContext(final String[] args) { + return new CommandContextImpl(args, commandRegistry); + } + + CommandRegistry getCommandRegistry() { + return commandRegistry; + } }
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContextFactoryImpl.java Thu Apr 05 00:36:28 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.cli; - -class CommandContextFactoryImpl extends CommandContextFactory { - - @Override - CommandContext createContext(final String[] args) { - return new CommandContextImpl(args); - } - -}
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/CommandContextImpl.java Thu Apr 05 14:29:15 2012 +0200 @@ -39,9 +39,11 @@ class CommandContextImpl implements CommandContext { private String[] arguments; + private CommandRegistry commandRegistry; - CommandContextImpl(String[] args) { + CommandContextImpl(String[] args, CommandRegistry cmdReg) { arguments = args; + commandRegistry = cmdReg; } @Override @@ -54,4 +56,9 @@ return arguments; } + @Override + public CommandRegistry getCommandRegistry() { + return commandRegistry; + } + }
--- a/cli/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/CommandRegistry.java Thu Apr 05 14:29:15 2012 +0200 @@ -36,21 +36,13 @@ package com.redhat.thermostat.cli; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; class CommandRegistry { - private static CommandRegistry instance = new CommandRegistry(); - - static CommandRegistry getInstance() { - return instance; - } - - static void setInstance(CommandRegistry commandRegistry) { - instance = commandRegistry; - } - private Map<String,Command> commands; CommandRegistry() { @@ -61,7 +53,7 @@ commands.put(cmd.getName(), cmd); } - void registerCommands(Iterable<Command> cmds) { + void registerCommands(Iterable<? extends Command> cmds) { for (Command cmd : cmds) { registerCommand(cmd); } @@ -71,4 +63,8 @@ return commands.get(name); } + Collection<Command> getRegisteredCommands() { + return Collections.unmodifiableCollection(commands.values()); + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cli/src/main/java/com/redhat/thermostat/cli/HelpCommand.java Thu Apr 05 14:29:15 2012 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import java.util.Collection; + +public class HelpCommand implements Command { + + private static final String NAME = "help"; + private static final String DESCRIPTION = "show help for a given command or help overview"; + private static final String USAGE = "help [COMMAND]\n\n" + + DESCRIPTION + "\n\n" + + " With no arguments, print a list of commands with short help messages.\n\n" + + " Given a command, print help for that command."; + + @Override + public void run(CommandContext ctx) { + String[] args = ctx.getArguments(); + if (args.length == 0) { + printCommandSummaries(ctx); + } else { + printCommandUsage(ctx, args[0]); + } + } + + private void printCommandSummaries(CommandContext ctx) { + CommandRegistry cmdRegistry = ctx.getCommandRegistry(); + + StringBuilder out = new StringBuilder(); + out.append("list of commands:\n\n"); + + Collection<Command> commands = cmdRegistry.getRegisteredCommands(); + for (Command cmd : commands) { + printCommandSummary(out, cmd); + } + ctx.getConsole().getOutput().print(out); + } + + private void printCommandSummary(StringBuilder out, Command cmd) { + out.append(" "); + out.append(cmd.getName()); + out.append("\t\t"); + out.append(cmd.getDescription()); + out.append("\n"); + } + + private void printCommandUsage(CommandContext ctx, String cmdName) { + Command cmd = ctx.getCommandRegistry().getCommand(cmdName); + if (cmd != null) { + ctx.getConsole().getOutput().print(cmd.getUsage()); + } else { + printCommandSummaries(ctx); + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getDescription() { + return DESCRIPTION; + } + + @Override + public String getUsage() { + return USAGE; + } + +}
--- a/cli/src/main/java/com/redhat/thermostat/cli/Main.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/java/com/redhat/thermostat/cli/Main.java Thu Apr 05 14:29:15 2012 +0200 @@ -42,15 +42,48 @@ public class Main { public static void main(String[] args) { - new Main().run(args); + new Main(args).run(); + } + + private Main(String[] args) { + this.args = args; + } + + private String[] args; + + private void run() { + registerDefaultCommands(); + if (hasNoArguments()) { + runHelpCommand(); + } else { + runCommandFromArguments(); + } + } + + private boolean hasNoArguments() { + return args.length == 0; } - private void run(String[] args) { - ServiceLoader<Command> cmds = ServiceLoader.load(Command.class); - CommandRegistry registry = CommandRegistry.getInstance(); - registry.registerCommands(cmds); - Command cmd = registry.getCommand(args[0]); - CommandContext ctx = CommandContextFactory.getInstance().createContext(Arrays.copyOfRange(args, 1, args.length)); + private void runHelpCommand() { + runCommand("help", new String[0]); + } + + private void runCommandFromArguments() { + runCommand(args[0], Arrays.copyOfRange(args, 1, args.length)); + } + + private void runCommand(String cmdName, String[] cmdArgs) { + CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance(); + CommandRegistry registry = cmdCtxFactory.getCommandRegistry(); + Command cmd = registry.getCommand(cmdName); + CommandContext ctx = cmdCtxFactory.createContext(cmdArgs); cmd.run(ctx); } + + private void registerDefaultCommands() { + CommandContextFactory cmdCtxFactory = CommandContextFactory.getInstance(); + CommandRegistry registry = cmdCtxFactory.getCommandRegistry(); + ServiceLoader<Command> cmds = ServiceLoader.load(Command.class); + registry.registerCommands(cmds); + } }
--- a/cli/src/main/resources/META-INF/services/com.redhat.thermostat.cli.Command Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/main/resources/META-INF/services/com.redhat.thermostat.cli.Command Thu Apr 05 14:29:15 2012 +0200 @@ -1,1 +1,1 @@ - +com.redhat.thermostat.cli.HelpCommand
--- a/cli/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/test/java/com/redhat/thermostat/cli/CLITestEnvironment.java Thu Apr 05 14:29:15 2012 +0200 @@ -47,8 +47,7 @@ } private static void reset() { - CommandContextFactory.setInstance(new CommandContextFactoryImpl()); - CommandRegistry.setInstance(new CommandRegistry()); + CommandContextFactory.setInstance(new CommandContextFactory()); } }
--- a/cli/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/test/java/com/redhat/thermostat/cli/CommandContextFactoryTest.java Thu Apr 05 14:29:15 2012 +0200 @@ -50,6 +50,9 @@ assertSame(System.err, ctx.getConsole().getError()); assertSame(System.in, ctx.getConsole().getInput()); assertArrayEquals(new String[] {"arg1", "arg2"}, ctx.getArguments()); + assertNotNull(cmdCtxFactory.getCommandRegistry()); + assertNotNull(ctx.getCommandRegistry()); + assertSame(cmdCtxFactory.getCommandRegistry(), ctx.getCommandRegistry()); } }
--- a/cli/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/test/java/com/redhat/thermostat/cli/CommandRegistryTest.java Thu Apr 05 14:29:15 2012 +0200 @@ -36,12 +36,18 @@ package com.redhat.thermostat.cli; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.util.Arrays; +import java.util.Collection; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.mockito.Mockito.*; public class CommandRegistryTest { @@ -83,4 +89,12 @@ actualCmd.run(ctx); verify(cmd).run(ctx); } + + @Test + public void testGetCommands() { + Collection<Command> cmds = registry.getRegisteredCommands(); + assertTrue(cmds.contains(cmd1)); + assertTrue(cmds.contains(cmd2)); + assertEquals(2, cmds.size()); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cli/src/test/java/com/redhat/thermostat/cli/HelpCommandTest.java Thu Apr 05 14:29:15 2012 +0200 @@ -0,0 +1,146 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class HelpCommandTest { + + private TestCommandContextFactory ctxFactory; + + @Before + public void setUp() { + + CLITestEnvironment.setUp(); + ctxFactory = new TestCommandContextFactory(); + CommandContextFactory.setInstance(ctxFactory); + + + } + + @After + public void tearDown() { + CLITestEnvironment.tearDown(); + } + + @Test + public void testName() { + HelpCommand cmd = new HelpCommand(); + assertEquals("help", cmd.getName()); + } + + @Test + public void verifyHelpNoArgPrintsListOfCommandsNoCommands() { + + HelpCommand cmd = new HelpCommand(); + cmd.run(ctxFactory.createContext(new String[0])); + String expected = "list of commands:\n\n"; + String actual = ctxFactory.getOutput(); + assertEquals(expected, actual); + } + + @Test + public void verifyHelpNoArgPrintsListOfCommands2Commands() { + + TestCommand cmd1 = new TestCommand("test1"); + cmd1.setDescription("test command 1"); + TestCommand cmd2 = new TestCommand("test2"); + cmd2.setDescription("test command 2"); + ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2)); + + HelpCommand cmd = new HelpCommand(); + cmd.run(ctxFactory.createContext(new String[0])); + String expected = "list of commands:\n\n" + + " test1\t\ttest command 1\n" + + " test2\t\ttest command 2\n"; + String actual = ctxFactory.getOutput(); + assertEquals(expected, actual); + } + + @Test + public void verifyHelpKnownCmdPrintsCommandUsage() { + TestCommand cmd1 = new TestCommand("test1"); + String usage = "test usage command 1"; + cmd1.setUsage(usage); + ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1)); + + HelpCommand cmd = new HelpCommand(); + cmd.run(ctxFactory.createContext(new String[] { "test1" })); + + String actual = ctxFactory.getOutput(); + assertEquals(usage, actual); + } + + @Test + public void verifyHelpUnknownCmdPrintsSummaries() { + TestCommand cmd1 = new TestCommand("test1"); + cmd1.setUsage("test usage command 1"); + cmd1.setDescription("test command 1"); + ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1)); + + HelpCommand cmd = new HelpCommand(); + cmd.run(ctxFactory.createContext(new String[] { "test12" })); + + String expected = "list of commands:\n\n" + + " test1\t\ttest command 1\n"; + String actual = ctxFactory.getOutput(); + assertEquals(expected, actual); + } + + @Test + public void testDescription() { + HelpCommand cmd = new HelpCommand(); + assertEquals("show help for a given command or help overview", cmd.getDescription()); + } + + @Test + public void testUsage() { + HelpCommand cmd = new HelpCommand(); + String expected = "help [COMMAND]\n\n" + + "show help for a given command or help overview\n\n" + + " With no arguments, print a list of commands with short help messages.\n\n" + + " Given a command, print help for that command."; + + assertEquals(expected, cmd.getUsage()); + } +}
--- a/cli/src/test/java/com/redhat/thermostat/cli/MainTest.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/test/java/com/redhat/thermostat/cli/MainTest.java Thu Apr 05 14:29:15 2012 +0200 @@ -36,7 +36,7 @@ package com.redhat.thermostat.cli; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.util.Arrays; @@ -46,36 +46,20 @@ public class MainTest { - private static class TestCmd1 implements Command { + private static class TestCmd1 implements TestCommand.Handle { @Override public void run(CommandContext ctx) { - String arg1 = ctx.getArguments()[0]; - String arg2 = ctx.getArguments()[1]; - ctx.getConsole().getOutput().print(arg1 + ", " + arg2); - } - - @Override - public String getName() { - return "test1"; + ctx.getConsole().getOutput().print(ctx.getArguments()[0] + ", " + ctx.getArguments()[1]); } } - private static class TestCmd2 implements Command { - + private static class TestCmd2 implements TestCommand.Handle { @Override public void run(CommandContext ctx) { - String arg1 = ctx.getArguments()[0]; - String arg2 = ctx.getArguments()[1]; - ctx.getConsole().getOutput().print(arg2 + ": " + arg1); + ctx.getConsole().getOutput().print(ctx.getArguments()[1] + ": " + ctx.getArguments()[0]); } - - @Override - public String getName() { - return "test2"; - } - } private TestCommandContextFactory ctxFactory; @@ -87,7 +71,11 @@ ctxFactory = new TestCommandContextFactory(); CommandContextFactory.setInstance(ctxFactory); - CommandRegistry.getInstance().registerCommands(Arrays.asList(new TestCmd1(), new TestCmd2())); + TestCommand cmd1 = new TestCommand("test1", new TestCmd1()); + cmd1.setDescription("description 1"); + TestCommand cmd2 = new TestCommand("test2", new TestCmd2()); + cmd2.setDescription("description 2"); + ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(cmd1, cmd2)); } @@ -105,6 +93,15 @@ runAndVerifyCommand(new String[] {"test2", "Hello", "World"}, "World: Hello"); } + @Test + public void testMainNoArgs() { + String expected = "list of commands:\n\n" + + " help\t\tshow help for a given command or help overview\n" + + " test1\t\tdescription 1\n" + + " test2\t\tdescription 2\n"; + runAndVerifyCommand(new String[0], expected); + } + private void runAndVerifyCommand(String[] args, String expected) { Main.main(args); assertEquals(expected, ctxFactory.getOutput());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cli/src/test/java/com/redhat/thermostat/cli/TestCommand.java Thu Apr 05 14:29:15 2012 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.cli; + + +class TestCommand implements Command { + + private String name; + private Handle handle; + private String description; + private String usage; + + static interface Handle { + public void run(CommandContext ctx); + } + + TestCommand(String name) { + this(name, null); + } + + TestCommand(String name, Handle r) { + this.name = name; + this.handle = r; + } + + @Override + public void run(CommandContext ctx) { + handle.run(ctx); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return description; + } + + void setDescription(String desc) { + description = desc; + } + + @Override + public String getUsage() { + return usage; + } + + void setUsage(String usage) { + this.usage = usage; + } +}
--- a/cli/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java Thu Apr 05 00:36:28 2012 +0200 +++ b/cli/src/test/java/com/redhat/thermostat/cli/TestCommandContextFactory.java Thu Apr 05 14:29:15 2012 +0200 @@ -43,9 +43,15 @@ class TestCommandContextFactory extends CommandContextFactory { - private ByteArrayOutputStream out = new ByteArrayOutputStream(); - private ByteArrayOutputStream err = new ByteArrayOutputStream(); - private ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); + private ByteArrayOutputStream out; + private ByteArrayOutputStream err; + private ByteArrayInputStream in; + + TestCommandContextFactory() { + reset(); + } + + private CommandRegistry commandRegistry = new CommandRegistry(); private class TestConsole implements Console { @@ -79,24 +85,35 @@ public String[] getArguments() { return args; } + + @Override + public CommandRegistry getCommandRegistry() { + return commandRegistry; + } }; } - public Object getOutput() { + @Override + CommandRegistry getCommandRegistry() { + return commandRegistry; + } + + String getOutput() { return new String(out.toByteArray()); } - public void setInput(String input) { + void setInput(String input) { in = new ByteArrayInputStream(input.getBytes()); } - public Object getError() { + Object getError() { return new String(err.toByteArray()); } - public void reset() { + void reset() { out = new ByteArrayOutputStream(); err = new ByteArrayOutputStream(); + in = new ByteArrayInputStream(new byte[0]); } }