github.com/clusterize-io/tusk@v0.6.3-0.20211001020217-cfe8a8cd0d4a/appcli/install_completion_test.go (about)

     1  package appcli
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"regexp"
     9  	"testing"
    10  
    11  	"github.com/clusterize-io/tusk/runner"
    12  	"github.com/clusterize-io/tusk/ui"
    13  	"gotest.tools/v3/assert"
    14  	"gotest.tools/v3/assert/cmp"
    15  	"gotest.tools/v3/env"
    16  	"gotest.tools/v3/fs"
    17  )
    18  
    19  func TestInstallCompletionUnsupported(t *testing.T) {
    20  	err := InstallCompletion(
    21  		&runner.Metadata{
    22  			InstallCompletion: "fake",
    23  		},
    24  	)
    25  	assert.ErrorContains(t, err, `tab completion for "fake" is not supported`)
    26  }
    27  
    28  func TestUninstallCompletionUnsupported(t *testing.T) {
    29  	err := UninstallCompletion(
    30  		&runner.Metadata{
    31  			UninstallCompletion: "fake",
    32  		},
    33  	)
    34  	assert.ErrorContains(t, err, `tab completion for "fake" is not supported`)
    35  }
    36  
    37  func TestInstallBashCompletion(t *testing.T) {
    38  	homedir := fs.NewDir(t, "home")
    39  	defer homedir.Remove()
    40  
    41  	datadir := fs.NewDir(t, "data", fs.WithDir("tusk"))
    42  	defer datadir.Remove()
    43  
    44  	defer env.PatchAll(t, map[string]string{
    45  		"HOME":          homedir.Path(),
    46  		"USERPROFILE":   homedir.Path(),
    47  		"XDG_DATA_HOME": datadir.Path(),
    48  	})()
    49  
    50  	err := installBashCompletion(ui.Noop())
    51  	assert.NilError(t, err)
    52  
    53  	completionFile := filepath.Join(datadir.Path(), "tusk", "tusk-completion.bash")
    54  	contents, err := ioutil.ReadFile(completionFile)
    55  	assert.NilError(t, err)
    56  
    57  	assert.Check(t, cmp.Equal(string(contents), rawBashCompletion))
    58  
    59  	rcfile := filepath.Join(homedir.Path(), ".bashrc")
    60  	rcContents, err := ioutil.ReadFile(rcfile)
    61  	assert.NilError(t, err)
    62  
    63  	command := fmt.Sprintf("source %q", filepath.ToSlash(completionFile))
    64  	assert.Check(t, cmp.Contains(string(rcContents), command))
    65  }
    66  
    67  func TestGetBashRCFile(t *testing.T) {
    68  	tests := []struct {
    69  		name   string
    70  		ops    []fs.PathOp
    71  		expect string
    72  	}{
    73  		{
    74  			"no-files",
    75  			[]fs.PathOp{},
    76  			".bashrc",
    77  		},
    78  		{
    79  			"all-files",
    80  			[]fs.PathOp{
    81  				fs.WithFile(".bashrc", ""),
    82  				fs.WithFile(".bash_profile", ""),
    83  				fs.WithFile(".profile", ""),
    84  			},
    85  			".bashrc",
    86  		},
    87  		{
    88  			"bash-profile-only",
    89  			[]fs.PathOp{
    90  				fs.WithFile(".bash_profile", ""),
    91  			},
    92  			".bash_profile",
    93  		},
    94  		{
    95  			"profile-only",
    96  			[]fs.PathOp{
    97  				fs.WithFile(".profile", ""),
    98  			},
    99  			".profile",
   100  		},
   101  	}
   102  
   103  	for _, tt := range tests {
   104  		t.Run(tt.name, func(t *testing.T) {
   105  			homedir := fs.NewDir(t, "home", tt.ops...)
   106  			defer homedir.Remove()
   107  
   108  			defer env.PatchAll(t, map[string]string{
   109  				"HOME":        homedir.Path(),
   110  				"USERPROFILE": homedir.Path(),
   111  			})()
   112  
   113  			rcfile, err := getBashRCFile()
   114  			assert.NilError(t, err)
   115  
   116  			want := filepath.Join(homedir.Path(), tt.expect)
   117  			assert.Check(t, cmp.Equal(want, rcfile))
   118  		})
   119  	}
   120  }
   121  
   122  func TestAppendIfAbsent_trailing_newlines(t *testing.T) {
   123  	existing := "# First Line\n\n"
   124  	f := fs.NewFile(t, "bashrc", fs.WithContent(existing))
   125  	defer f.Remove()
   126  
   127  	text := "# Second Line"
   128  	err := appendIfAbsent(f.Path(), text)
   129  	assert.NilError(t, err)
   130  
   131  	want := existing + text + "\n"
   132  	got, err := ioutil.ReadFile(f.Path())
   133  	assert.NilError(t, err)
   134  
   135  	assert.Check(t, cmp.Equal(want, string(got)))
   136  }
   137  
   138  func TestAppendIfAbsent_no_trailing_newline(t *testing.T) {
   139  	existing := "# First Line"
   140  	f := fs.NewFile(t, "bashrc", fs.WithContent(existing))
   141  	defer f.Remove()
   142  
   143  	text := "# Second Line"
   144  	err := appendIfAbsent(f.Path(), text)
   145  	assert.NilError(t, err)
   146  
   147  	want := existing + "\n" + text + "\n"
   148  	got, err := ioutil.ReadFile(f.Path())
   149  	assert.NilError(t, err)
   150  
   151  	assert.Check(t, cmp.Equal(want, string(got)))
   152  }
   153  
   154  func TestAppendIfAbsent_exists(t *testing.T) {
   155  	text := "# Existing Line"
   156  	f := fs.NewFile(t, "bashrc", fs.WithContent(text))
   157  	defer f.Remove()
   158  
   159  	err := appendIfAbsent(f.Path(), text)
   160  	assert.NilError(t, err)
   161  
   162  	got, err := ioutil.ReadFile(f.Path())
   163  	assert.NilError(t, err)
   164  
   165  	assert.Check(t, cmp.Equal(text, string(got)))
   166  }
   167  
   168  func TestAppendIfAbsent_no_file(t *testing.T) {
   169  	f := fs.NewFile(t, "bashrc")
   170  	defer f.Remove() // Will be recreated
   171  
   172  	f.Remove()
   173  
   174  	text := "# Target Line"
   175  	err := appendIfAbsent(f.Path(), text)
   176  	assert.NilError(t, err)
   177  
   178  	got, err := ioutil.ReadFile(f.Path())
   179  	assert.NilError(t, err)
   180  
   181  	assert.Check(t, cmp.Equal(text+"\n", string(got)))
   182  }
   183  
   184  func TestUninstallBashCompletion(t *testing.T) {
   185  	datadir := fs.NewDir(
   186  		t,
   187  		"data",
   188  		fs.WithDir("tusk",
   189  			fs.WithFile("tusk-completion.bash", rawBashCompletion),
   190  		),
   191  	)
   192  	defer datadir.Remove()
   193  
   194  	rcfile := filepath.Join(datadir.Path(), "tusk", "tusk-completion.bash")
   195  
   196  	contents := fmt.Sprintf("# Preamble\nsource %q", filepath.ToSlash(rcfile))
   197  	homedir := fs.NewDir(t, "home", fs.WithFile(".bashrc", contents))
   198  	defer homedir.Remove()
   199  
   200  	defer env.PatchAll(t, map[string]string{
   201  		"HOME":          homedir.Path(),
   202  		"USERPROFILE":   homedir.Path(),
   203  		"XDG_DATA_HOME": datadir.Path(),
   204  	})()
   205  
   206  	err := uninstallBashCompletion()
   207  	assert.NilError(t, err)
   208  
   209  	_, err = os.Stat(rcfile)
   210  	assert.Check(t, os.IsNotExist(err))
   211  
   212  	got, err := ioutil.ReadFile(filepath.Join(homedir.Path(), ".bashrc"))
   213  	assert.NilError(t, err)
   214  
   215  	assert.Check(t, cmp.Equal("# Preamble\n", string(got)))
   216  }
   217  
   218  func TestRemoveLineInFile(t *testing.T) {
   219  	content := `# First
   220  match
   221  
   222  # Second
   223  
   224  match`
   225  	want := `# First
   226  
   227  # Second
   228  `
   229  
   230  	file := fs.NewFile(t, "file", fs.WithContent(content))
   231  	defer file.Remove()
   232  
   233  	err := removeLineInFile(file.Path(), regexp.MustCompile("match"))
   234  	assert.NilError(t, err)
   235  
   236  	got, err := ioutil.ReadFile(file.Path())
   237  	assert.NilError(t, err)
   238  
   239  	assert.Check(t, cmp.Equal(want, string(got)))
   240  }
   241  
   242  func TestInstallFishCompletion(t *testing.T) {
   243  	cfgdir := fs.NewDir(t, "data")
   244  	defer cfgdir.Remove()
   245  
   246  	defer env.PatchAll(t, map[string]string{
   247  		"XDG_CONFIG_HOME": cfgdir.Path(),
   248  	})()
   249  
   250  	err := installFishCompletion(ui.Noop())
   251  	assert.NilError(t, err)
   252  
   253  	completionFile := filepath.Join(cfgdir.Path(), "fish", "completions", "tusk.fish")
   254  	contents, err := ioutil.ReadFile(completionFile)
   255  	assert.NilError(t, err)
   256  
   257  	assert.Check(t, cmp.Equal(string(contents), rawFishCompletion))
   258  }
   259  
   260  func TestUninstallFishCompletion(t *testing.T) {
   261  	cfgdir := fs.NewDir(
   262  		t,
   263  		"data",
   264  		fs.WithDir(
   265  			"fish",
   266  			fs.WithDir(
   267  				"completions",
   268  				fs.WithFile("tusk.fish", rawFishCompletion),
   269  			),
   270  		),
   271  	)
   272  	defer cfgdir.Remove()
   273  
   274  	completionFile := filepath.Join(cfgdir.Path(), "fish", "completions", "tusk.fish")
   275  	_, err := os.Stat(completionFile)
   276  	assert.NilError(t, err)
   277  
   278  	defer env.PatchAll(t, map[string]string{
   279  		"XDG_CONFIG_HOME": cfgdir.Path(),
   280  	})()
   281  
   282  	err = uninstallFishCompletion()
   283  	assert.NilError(t, err)
   284  
   285  	_, err = os.Stat(completionFile)
   286  	assert.Check(t, os.IsNotExist(err))
   287  }
   288  
   289  func TestGetDataDir_xdg(t *testing.T) {
   290  	xdgDataHome := "/foo/bar/baz"
   291  	defer env.Patch(t, "XDG_DATA_HOME", xdgDataHome)()
   292  
   293  	want := filepath.Join(xdgDataHome, "tusk")
   294  
   295  	got, err := getDataDir()
   296  	assert.NilError(t, err)
   297  
   298  	assert.Equal(t, want, got)
   299  }
   300  
   301  func TestGetDataDir_default(t *testing.T) {
   302  	home, err := os.UserHomeDir()
   303  	assert.NilError(t, err)
   304  
   305  	want := filepath.Join(home, ".local", "share", "tusk")
   306  
   307  	got, err := getDataDir()
   308  	assert.NilError(t, err)
   309  
   310  	assert.Equal(t, want, got)
   311  }
   312  
   313  func TestGetFishCompletionsDir_xdg(t *testing.T) {
   314  	cfgHome := "/foo/bar/baz"
   315  	defer env.Patch(t, "XDG_CONFIG_HOME", cfgHome)()
   316  
   317  	want := filepath.Join(cfgHome, "fish", "completions")
   318  
   319  	got, err := getFishCompletionsDir()
   320  	assert.NilError(t, err)
   321  
   322  	assert.Equal(t, want, got)
   323  }
   324  
   325  func TestGetFishCompletionsDir_default(t *testing.T) {
   326  	home, err := os.UserHomeDir()
   327  	assert.NilError(t, err)
   328  
   329  	want := filepath.Join(home, ".config", "fish", "completions")
   330  
   331  	got, err := getFishCompletionsDir()
   332  	assert.NilError(t, err)
   333  
   334  	assert.Equal(t, want, got)
   335  }
   336  
   337  func TestInstallZshCompletion(t *testing.T) {
   338  	dir := fs.NewDir(t, "project-dir")
   339  	defer dir.Remove()
   340  
   341  	err := installZshCompletion(ui.Noop(), dir.Path())
   342  	assert.NilError(t, err)
   343  
   344  	contents, err := ioutil.ReadFile(filepath.Join(dir.Path(), "_tusk"))
   345  	assert.NilError(t, err)
   346  
   347  	assert.Check(t, cmp.Equal(string(contents), rawZshCompletion))
   348  }
   349  
   350  func TestUninstallZshCompletion(t *testing.T) {
   351  	dir := fs.NewDir(t, "project-dir", fs.WithFile("_tusk", rawZshCompletion))
   352  	defer dir.Remove()
   353  
   354  	err := uninstallZshCompletion(dir.Path())
   355  	assert.NilError(t, err)
   356  
   357  	_, err = os.Stat(filepath.Join(dir.Path(), "_tusk"))
   358  	assert.Assert(t, os.IsNotExist(err))
   359  }
   360  
   361  func TestUninstallZshCompletion_empty(t *testing.T) {
   362  	dir := fs.NewDir(t, "project-dir")
   363  	defer dir.Remove()
   364  
   365  	err := uninstallZshCompletion(dir.Path())
   366  	assert.NilError(t, err)
   367  
   368  	_, err = os.Stat(filepath.Join(dir.Path(), "_tusk"))
   369  	assert.Assert(t, os.IsNotExist(err))
   370  }