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  }