launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/cmd/supercommand_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cmd_test 5 6 import ( 7 "bytes" 8 "fmt" 9 "strings" 10 11 "launchpad.net/gnuflag" 12 gc "launchpad.net/gocheck" 13 14 "launchpad.net/juju-core/cmd" 15 "launchpad.net/juju-core/testing" 16 "launchpad.net/juju-core/testing/testbase" 17 ) 18 19 func initDefenestrate(args []string) (*cmd.SuperCommand, *TestCommand, error) { 20 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest"}) 21 tc := &TestCommand{Name: "defenestrate"} 22 jc.Register(tc) 23 return jc, tc, testing.InitCommand(jc, args) 24 } 25 26 type SuperCommandSuite struct { 27 testbase.LoggingSuite 28 } 29 30 var _ = gc.Suite(&SuperCommandSuite{}) 31 32 const helpText = "\n help\\s+- show help on a command or other topic" 33 const helpCommandsText = "commands:" + helpText 34 35 func (s *SuperCommandSuite) TestDispatch(c *gc.C) { 36 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest"}) 37 info := jc.Info() 38 c.Assert(info.Name, gc.Equals, "jujutest") 39 c.Assert(info.Args, gc.Equals, "<command> ...") 40 c.Assert(info.Doc, gc.Matches, helpCommandsText) 41 42 jc, _, err := initDefenestrate([]string{"discombobulate"}) 43 c.Assert(err, gc.ErrorMatches, "unrecognized command: jujutest discombobulate") 44 info = jc.Info() 45 c.Assert(info.Name, gc.Equals, "jujutest") 46 c.Assert(info.Args, gc.Equals, "<command> ...") 47 c.Assert(info.Doc, gc.Matches, "commands:\n defenestrate - defenestrate the juju"+helpText) 48 49 jc, tc, err := initDefenestrate([]string{"defenestrate"}) 50 c.Assert(err, gc.IsNil) 51 c.Assert(tc.Option, gc.Equals, "") 52 info = jc.Info() 53 c.Assert(info.Name, gc.Equals, "jujutest defenestrate") 54 c.Assert(info.Args, gc.Equals, "<something>") 55 c.Assert(info.Doc, gc.Equals, "defenestrate-doc") 56 57 _, tc, err = initDefenestrate([]string{"defenestrate", "--option", "firmly"}) 58 c.Assert(err, gc.IsNil) 59 c.Assert(tc.Option, gc.Equals, "firmly") 60 61 _, tc, err = initDefenestrate([]string{"defenestrate", "gibberish"}) 62 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["gibberish"\]`) 63 64 // --description must be used on it's own. 65 _, _, err = initDefenestrate([]string{"--description", "defenestrate"}) 66 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["defenestrate"\]`) 67 } 68 69 func (s *SuperCommandSuite) TestRegister(c *gc.C) { 70 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest"}) 71 jc.Register(&TestCommand{Name: "flip"}) 72 jc.Register(&TestCommand{Name: "flap"}) 73 badCall := func() { jc.Register(&TestCommand{Name: "flap"}) } 74 c.Assert(badCall, gc.PanicMatches, "command already registered: flap") 75 } 76 77 func (s *SuperCommandSuite) TestRegisterAlias(c *gc.C) { 78 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest"}) 79 jc.Register(&TestCommand{Name: "flip", Aliases: []string{"flap", "flop"}}) 80 81 info := jc.Info() 82 c.Assert(info.Doc, gc.Equals, `commands: 83 flap - alias for flip 84 flip - flip the juju 85 flop - alias for flip 86 help - show help on a command or other topic`) 87 } 88 89 var commandsDoc = `commands: 90 flapbabble - flapbabble the juju 91 flip - flip the juju` 92 93 func (s *SuperCommandSuite) TestInfo(c *gc.C) { 94 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{ 95 Name: "jujutest", 96 Purpose: "to be purposeful", 97 Doc: "doc\nblah\ndoc", 98 }) 99 info := jc.Info() 100 c.Assert(info.Name, gc.Equals, "jujutest") 101 c.Assert(info.Purpose, gc.Equals, "to be purposeful") 102 // info doc starts with the jc.Doc and ends with the help command 103 c.Assert(info.Doc, gc.Matches, jc.Doc+"(.|\n)*") 104 c.Assert(info.Doc, gc.Matches, "(.|\n)*"+helpCommandsText) 105 106 jc.Register(&TestCommand{Name: "flip"}) 107 jc.Register(&TestCommand{Name: "flapbabble"}) 108 info = jc.Info() 109 c.Assert(info.Doc, gc.Matches, jc.Doc+"\n\n"+commandsDoc+helpText) 110 111 jc.Doc = "" 112 info = jc.Info() 113 c.Assert(info.Doc, gc.Matches, commandsDoc+helpText) 114 } 115 116 type testVersionFlagCommand struct { 117 cmd.CommandBase 118 version string 119 } 120 121 func (c *testVersionFlagCommand) Info() *cmd.Info { 122 return &cmd.Info{Name: "test"} 123 } 124 125 func (c *testVersionFlagCommand) SetFlags(f *gnuflag.FlagSet) { 126 f.StringVar(&c.version, "version", "", "") 127 } 128 129 func (c *testVersionFlagCommand) Run(_ *cmd.Context) error { 130 return nil 131 } 132 133 func (s *SuperCommandSuite) TestVersionFlag(c *gc.C) { 134 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{ 135 Name: "jujutest", 136 Purpose: "to be purposeful", 137 Doc: "doc\nblah\ndoc", 138 }) 139 testVersionFlagCommand := &testVersionFlagCommand{} 140 jc.Register(&cmd.VersionCommand{}) 141 jc.Register(testVersionFlagCommand) 142 143 var stdout, stderr bytes.Buffer 144 ctx := &cmd.Context{ 145 Stdout: &stdout, 146 Stderr: &stderr, 147 } 148 149 // baseline: juju version 150 code := cmd.Main(jc, ctx, []string{"version"}) 151 c.Check(code, gc.Equals, 0) 152 baselineStderr := stderr.String() 153 baselineStdout := stdout.String() 154 stderr.Reset() 155 stdout.Reset() 156 157 // juju --version output should match that of juju version. 158 code = cmd.Main(jc, ctx, []string{"--version"}) 159 c.Check(code, gc.Equals, 0) 160 c.Assert(stderr.String(), gc.Equals, baselineStderr) 161 c.Assert(stdout.String(), gc.Equals, baselineStdout) 162 stderr.Reset() 163 stdout.Reset() 164 165 // juju test --version should update testVersionFlagCommand.version, 166 // and there should be no output. The --version flag on the 'test' 167 // subcommand has a different type to the "juju --version" flag. 168 code = cmd.Main(jc, ctx, []string{"test", "--version=abc.123"}) 169 c.Check(code, gc.Equals, 0) 170 c.Assert(stderr.String(), gc.Equals, "") 171 c.Assert(stdout.String(), gc.Equals, "") 172 c.Assert(testVersionFlagCommand.version, gc.Equals, "abc.123") 173 } 174 175 func (s *SuperCommandSuite) TestLogging(c *gc.C) { 176 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest", Log: &cmd.Log{}}) 177 jc.Register(&TestCommand{Name: "blah"}) 178 ctx := testing.Context(c) 179 code := cmd.Main(jc, ctx, []string{"blah", "--option", "error", "--debug"}) 180 c.Assert(code, gc.Equals, 1) 181 c.Assert(bufferString(ctx.Stderr), gc.Matches, `^.* ERROR .* BAM! 182 `) 183 } 184 185 func (s *SuperCommandSuite) TestDescription(c *gc.C) { 186 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest", Purpose: "blow up the death star"}) 187 jc.Register(&TestCommand{Name: "blah"}) 188 ctx := testing.Context(c) 189 code := cmd.Main(jc, ctx, []string{"blah", "--description"}) 190 c.Assert(code, gc.Equals, 0) 191 c.Assert(bufferString(ctx.Stdout), gc.Equals, "blow up the death star\n") 192 } 193 194 func (s *SuperCommandSuite) TestHelp(c *gc.C) { 195 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest"}) 196 jc.Register(&TestCommand{Name: "blah"}) 197 ctx := testing.Context(c) 198 code := cmd.Main(jc, ctx, []string{"blah", "--help"}) 199 c.Assert(code, gc.Equals, 0) 200 stripped := strings.Replace(bufferString(ctx.Stdout), "\n", "", -1) 201 c.Assert(stripped, gc.Matches, ".*usage: jujutest blah.*blah-doc.*") 202 } 203 204 func (s *SuperCommandSuite) TestHelpWithPrefix(c *gc.C) { 205 jc := cmd.NewSuperCommand(cmd.SuperCommandParams{Name: "jujutest", UsagePrefix: "juju"}) 206 jc.Register(&TestCommand{Name: "blah"}) 207 ctx := testing.Context(c) 208 code := cmd.Main(jc, ctx, []string{"blah", "--help"}) 209 c.Assert(code, gc.Equals, 0) 210 stripped := strings.Replace(bufferString(ctx.Stdout), "\n", "", -1) 211 c.Assert(stripped, gc.Matches, ".*usage: juju jujutest blah.*blah-doc.*") 212 } 213 214 func NewSuperWithCallback(callback func(*cmd.Context, string, []string) error) cmd.Command { 215 return cmd.NewSuperCommand(cmd.SuperCommandParams{ 216 Name: "jujutest", 217 Log: &cmd.Log{}, 218 MissingCallback: callback, 219 }) 220 } 221 222 func (s *SuperCommandSuite) TestMissingCallback(c *gc.C) { 223 var calledName string 224 var calledArgs []string 225 226 callback := func(ctx *cmd.Context, subcommand string, args []string) error { 227 calledName = subcommand 228 calledArgs = args 229 return nil 230 } 231 232 code := cmd.Main( 233 NewSuperWithCallback(callback), 234 testing.Context(c), 235 []string{"foo", "bar", "baz", "--debug"}) 236 c.Assert(code, gc.Equals, 0) 237 c.Assert(calledName, gc.Equals, "foo") 238 c.Assert(calledArgs, gc.DeepEquals, []string{"bar", "baz", "--debug"}) 239 } 240 241 func (s *SuperCommandSuite) TestMissingCallbackErrors(c *gc.C) { 242 callback := func(ctx *cmd.Context, subcommand string, args []string) error { 243 return fmt.Errorf("command not found %q", subcommand) 244 } 245 246 ctx := testing.Context(c) 247 code := cmd.Main(NewSuperWithCallback(callback), ctx, []string{"foo"}) 248 c.Assert(code, gc.Equals, 1) 249 c.Assert(testing.Stdout(ctx), gc.Equals, "") 250 c.Assert(testing.Stderr(ctx), gc.Equals, "ERROR command not found \"foo\"\n") 251 } 252 253 func (s *SuperCommandSuite) TestMissingCallbackContextWiredIn(c *gc.C) { 254 callback := func(ctx *cmd.Context, subcommand string, args []string) error { 255 fmt.Fprintf(ctx.Stdout, "this is std out") 256 fmt.Fprintf(ctx.Stderr, "this is std err") 257 return nil 258 } 259 260 ctx := testing.Context(c) 261 code := cmd.Main(NewSuperWithCallback(callback), ctx, []string{"foo", "bar", "baz", "--debug"}) 262 c.Assert(code, gc.Equals, 0) 263 c.Assert(testing.Stdout(ctx), gc.Equals, "this is std out") 264 c.Assert(testing.Stderr(ctx), gc.Equals, "this is std err") 265 }