github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/cmd/snap/cmd_help_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package main_test 21 22 import ( 23 "bytes" 24 "fmt" 25 "os" 26 "reflect" 27 "regexp" 28 "strings" 29 30 "github.com/jessevdk/go-flags" 31 "gopkg.in/check.v1" 32 33 snap "github.com/snapcore/snapd/cmd/snap" 34 ) 35 36 func (s *SnapSuite) TestHelpPrintsHelp(c *check.C) { 37 origArgs := os.Args 38 defer func() { os.Args = origArgs }() 39 40 for _, cmdLine := range [][]string{ 41 {"snap"}, 42 {"snap", "help"}, 43 {"snap", "--help"}, 44 {"snap", "-h"}, 45 {"snap", "--help", "install"}, 46 } { 47 s.ResetStdStreams() 48 49 os.Args = cmdLine 50 comment := check.Commentf("%q", cmdLine) 51 52 err := snap.RunMain() 53 c.Assert(err, check.IsNil, comment) 54 c.Check(s.Stdout(), check.Matches, "(?s)"+strings.Join([]string{ 55 snap.LongSnapDescription, 56 "", 57 regexp.QuoteMeta(snap.SnapUsage), 58 "", 59 snap.SnapHelpCategoriesIntro, 60 ".*", "", 61 snap.SnapHelpAllFooter, 62 snap.SnapHelpFooter, 63 }, "\n")+`\s*`, comment) 64 c.Check(s.Stderr(), check.Equals, "", comment) 65 } 66 } 67 68 func (s *SnapSuite) TestHelpAllPrintsLongHelp(c *check.C) { 69 origArgs := os.Args 70 defer func() { os.Args = origArgs }() 71 72 os.Args = []string{"snap", "help", "--all"} 73 74 err := snap.RunMain() 75 c.Assert(err, check.IsNil) 76 c.Check(s.Stdout(), check.Matches, "(?sm)"+strings.Join([]string{ 77 snap.LongSnapDescription, 78 "", 79 regexp.QuoteMeta(snap.SnapUsage), 80 "", 81 snap.SnapHelpAllIntro, 82 "", ".*", "", 83 snap.SnapHelpAllFooter, 84 }, "\n")+`\s*`) 85 c.Check(s.Stderr(), check.Equals, "") 86 } 87 88 func nonHiddenCommands() map[string]bool { 89 parser := snap.Parser(snap.Client()) 90 commands := parser.Commands() 91 names := make(map[string]bool, len(commands)) 92 for _, cmd := range commands { 93 if cmd.Hidden { 94 continue 95 } 96 names[cmd.Name] = true 97 } 98 return names 99 } 100 101 // Helper that checks if goflags is old. The check for EnvNamespace is 102 // arbitrary, it just happened that support for this got added right after 103 // the v1.4.0 release with commit 1c38ed7. 104 func goFlagsFromBefore20200331() bool { 105 v := reflect.ValueOf(flags.Group{}) 106 f := v.FieldByName("EnvNamespace") 107 return !f.IsValid() 108 } 109 110 func (s *SnapSuite) testSubCommandHelp(c *check.C, sub, expected string) { 111 // Skip --help output tests for older versions of 112 // go-flags. Notably v1.4.0 from debian-sid will fail because 113 // the formating is slightly different. Note that the check here 114 // is not precise i.e. this is not the commit that added the change 115 // that changed the help output but this change is easy to test for 116 // with reflect and in practice this is fine. 117 if goFlagsFromBefore20200331() { 118 c.Skip("go flags too old") 119 } 120 121 parser := snap.Parser(snap.Client()) 122 rest, err := parser.ParseArgs([]string{sub, "--help"}) 123 c.Assert(err, check.DeepEquals, &flags.Error{Type: flags.ErrHelp}) 124 c.Assert(rest, check.HasLen, 0) 125 var buf bytes.Buffer 126 parser.WriteHelp(&buf) 127 c.Check(buf.String(), check.Equals, expected) 128 } 129 130 func (s *SnapSuite) TestSubCommandHelpPrintsHelp(c *check.C) { 131 origArgs := os.Args 132 defer func() { os.Args = origArgs }() 133 134 for cmd := range nonHiddenCommands() { 135 s.ResetStdStreams() 136 os.Args = []string{"snap", cmd, "--help"} 137 138 err := snap.RunMain() 139 comment := check.Commentf("%q", cmd) 140 c.Assert(err, check.IsNil, comment) 141 // regexp matches "Usage: snap <the command>" plus an arbitrary 142 // number of [<something>] plus an arbitrary number of 143 // <<something>> optionally ending in ellipsis 144 c.Check(s.Stdout(), check.Matches, fmt.Sprintf(`(?sm)Usage:\s+snap %s(?: \[[^][]+\])*(?:(?: <[^<>]+>)+(?:\.\.\.)?)?$.*`, cmd), comment) 145 c.Check(s.Stderr(), check.Equals, "", comment) 146 } 147 } 148 149 func (s *SnapSuite) TestHelpCategories(c *check.C) { 150 // non-hidden commands that are not expected to appear in the help summary 151 excluded := []string{ 152 "help", 153 } 154 all := nonHiddenCommands() 155 categorised := make(map[string]bool, len(all)+len(excluded)) 156 for _, cmd := range excluded { 157 categorised[cmd] = true 158 } 159 seen := make(map[string]string, len(all)) 160 seenCmds := func(cmds []string, label string) { 161 for _, cmd := range cmds { 162 categorised[cmd] = true 163 if seen[cmd] != "" { 164 c.Errorf("duplicated: %q in %q and %q", cmd, seen[cmd], label) 165 } 166 seen[cmd] = label 167 } 168 } 169 for _, categ := range snap.HelpCategories { 170 seenCmds(categ.Commands, categ.Label) 171 seenCmds(categ.AllOnlyCommands, categ.Label) 172 } 173 for cmd := range all { 174 if !categorised[cmd] { 175 c.Errorf("uncategorised: %q", cmd) 176 } 177 } 178 for cmd := range categorised { 179 if !all[cmd] { 180 c.Errorf("unknown (hidden?): %q", cmd) 181 } 182 } 183 } 184 185 func (s *SnapSuite) TestHelpCommandAllFails(c *check.C) { 186 origArgs := os.Args 187 defer func() { os.Args = origArgs }() 188 os.Args = []string{"snap", "help", "interfaces", "--all"} 189 190 err := snap.RunMain() 191 c.Assert(err, check.ErrorMatches, "help accepts a command, or '--all', but not both.") 192 } 193 194 func (s *SnapSuite) TestManpageInSection8(c *check.C) { 195 origArgs := os.Args 196 defer func() { os.Args = origArgs }() 197 os.Args = []string{"snap", "help", "--man"} 198 199 err := snap.RunMain() 200 c.Assert(err, check.IsNil) 201 202 c.Check(s.Stdout(), check.Matches, `\.TH snap 8 (?s).*`) 203 } 204 205 func (s *SnapSuite) TestManpageNoDoubleTP(c *check.C) { 206 origArgs := os.Args 207 defer func() { os.Args = origArgs }() 208 os.Args = []string{"snap", "help", "--man"} 209 210 err := snap.RunMain() 211 c.Assert(err, check.IsNil) 212 213 c.Check(s.Stdout(), check.Not(check.Matches), `(?s).*(?m-s)^\.TP\n\.TP$(?s-m).*`) 214 215 } 216 217 func (s *SnapSuite) TestBadSub(c *check.C) { 218 origArgs := os.Args 219 defer func() { os.Args = origArgs }() 220 os.Args = []string{"snap", "debug", "brotato"} 221 222 err := snap.RunMain() 223 c.Assert(err, check.ErrorMatches, `unknown command "brotato", see 'snap help debug'.`) 224 }