github.com/teddydd/sh@v2.6.4+incompatible/cmd/shfmt/main_test.go (about)

     1  // Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
     2  // See LICENSE for licensing information
     3  
     4  package main
     5  
     6  import (
     7  	"bufio"
     8  	"bytes"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"strings"
    14  	"testing"
    15  
    16  	"mvdan.cc/sh/syntax"
    17  )
    18  
    19  func TestMain(m *testing.M) {
    20  	dir, err := ioutil.TempDir("", "shfmt-walk")
    21  	if err != nil {
    22  		panic(err)
    23  	}
    24  	if err := os.Chdir(dir); err != nil {
    25  		panic(err)
    26  	}
    27  	parser = syntax.NewParser(syntax.KeepComments)
    28  	printer = syntax.NewPrinter()
    29  
    30  	exit := m.Run()
    31  	os.RemoveAll(dir)
    32  	os.Exit(exit)
    33  }
    34  
    35  func TestStdin(t *testing.T) {
    36  	var buf bytes.Buffer
    37  	out = &buf
    38  	t.Run("Regular", func(t *testing.T) {
    39  		in = strings.NewReader(" foo")
    40  		buf.Reset()
    41  		if err := formatStdin(); err != nil {
    42  			t.Fatal(err)
    43  		}
    44  		if got, want := buf.String(), "foo\n"; got != want {
    45  			t.Fatalf("got=%q want=%q", got, want)
    46  		}
    47  	})
    48  
    49  	t.Run("List", func(t *testing.T) {
    50  		*list = true
    51  		defer func() { *list = false }()
    52  		in = strings.NewReader(" foo")
    53  		buf.Reset()
    54  		if err := formatStdin(); err != nil {
    55  			t.Fatal(err)
    56  		}
    57  		if got, want := buf.String(), "<standard input>\n"; got != want {
    58  			t.Fatalf("got=%q want=%q", got, want)
    59  		}
    60  	})
    61  
    62  	t.Run("Diff", func(t *testing.T) {
    63  		*diff = true
    64  		defer func() { *diff = false }()
    65  		in = strings.NewReader(" foo\nbar\n\n")
    66  		buf.Reset()
    67  		if err := formatStdin(); err != errChangedWithDiff {
    68  			t.Fatalf("got=%q want=%q", err, errChangedWithDiff)
    69  		}
    70  		want := `diff -u <standard input>.orig <standard input>
    71  @@ -1,3 +1,2 @@
    72  - foo
    73  +foo
    74   bar
    75  -
    76  `
    77  		if got := buf.String(); got != want {
    78  			t.Fatalf("got:\n%swant:\n%s", got, want)
    79  		}
    80  	})
    81  }
    82  
    83  type action uint
    84  
    85  const (
    86  	None action = iota
    87  	Modify
    88  	Error
    89  )
    90  
    91  var walkTests = []struct {
    92  	want       action
    93  	symlink    bool
    94  	path, body string
    95  }{
    96  	{Modify, false, "shebang-1", "#!/bin/sh\n foo"},
    97  	{Modify, false, "shebang-2", "#!/bin/bash\n foo"},
    98  	{Modify, false, "shebang-3", "#!/usr/bin/sh\n foo"},
    99  	{Modify, false, "shebang-4", "#!/usr/bin/env bash\n foo"},
   100  	{Modify, false, "shebang-5", "#!/bin/env sh\n foo"},
   101  	{Modify, false, "shebang-space", "#! /bin/sh\n foo"},
   102  	{Modify, false, "shebang-tabs", "#!\t/bin/env\tsh\n foo"},
   103  	{Modify, false, "shebang-args", "#!/bin/bash -e -x\nfoo"},
   104  	{Modify, false, "ext.sh", " foo"},
   105  	{Modify, false, "ext.bash", " foo"},
   106  	{Modify, false, "ext-shebang.sh", "#!/bin/sh\n foo"},
   107  	{Modify, false, filepath.Join("dir", "ext.sh"), " foo"},
   108  	{None, false, ".hidden", " foo long enough"},
   109  	{None, false, ".hidden-shebang", "#!/bin/sh\n foo"},
   110  	{None, false, "..hidden-shebang", "#!/bin/sh\n foo"},
   111  	{None, false, "noext-empty", " foo"},
   112  	{None, false, "noext-noshebang", " foo long enough"},
   113  	{None, false, "shebang-nonewline", "#!/bin/shfoo"},
   114  	{None, false, "ext.other", " foo"},
   115  	{None, false, "ext-shebang.other", "#!/bin/sh\n foo"},
   116  	{None, false, "shebang-nospace", "#!/bin/envsh\n foo"},
   117  	{None, false, filepath.Join(".git", "ext.sh"), " foo"},
   118  	{None, false, filepath.Join(".svn", "ext.sh"), " foo"},
   119  	{None, false, filepath.Join(".hg", "ext.sh"), " foo"},
   120  	{Error, false, "parse-error.sh", " foo("},
   121  	{None, true, "reallylongdir/symlink-file", "ext-shebang.sh"},
   122  	{None, true, "symlink-dir", "reallylongdir"},
   123  	{None, true, "symlink-none", "reallylongdir/nonexistent"},
   124  }
   125  
   126  var errPathMentioned = regexp.MustCompile(`([^ :]+):`)
   127  
   128  func TestWalk(t *testing.T) {
   129  	t.Parallel()
   130  	for _, wt := range walkTests {
   131  		if dir, _ := filepath.Split(wt.path); dir != "" {
   132  			dir = dir[:len(dir)-1]
   133  			os.Mkdir(dir, 0777)
   134  		}
   135  		if wt.symlink {
   136  			if err := os.Symlink(wt.body, wt.path); err != nil {
   137  				t.Fatal(err)
   138  			}
   139  			continue
   140  		}
   141  		err := ioutil.WriteFile(wt.path, []byte(wt.body), 0666)
   142  		if err != nil {
   143  			t.Fatal(err)
   144  		}
   145  	}
   146  	var outBuf bytes.Buffer
   147  	out = &outBuf
   148  	*list, *write = true, true
   149  	*simple = true
   150  	gotError := false
   151  	errored := map[string]bool{}
   152  	onError := func(err error) {
   153  		gotError = true
   154  		line := err.Error()
   155  		if sub := errPathMentioned.FindStringSubmatch(line); sub != nil {
   156  			errored[sub[1]] = true
   157  		}
   158  	}
   159  	doWalk := func(path string) {
   160  		gotError = false
   161  		outBuf.Reset()
   162  		walk(path, onError)
   163  	}
   164  	doWalk(".")
   165  	modified := map[string]bool{}
   166  	outScan := bufio.NewScanner(&outBuf)
   167  	for outScan.Scan() {
   168  		path := outScan.Text()
   169  		modified[path] = true
   170  	}
   171  	for _, wt := range walkTests {
   172  		t.Run(wt.path, func(t *testing.T) {
   173  			mod := modified[wt.path]
   174  			if mod && wt.want != Modify {
   175  				t.Fatalf("walk had to not run on %s but did", wt.path)
   176  			} else if !mod && wt.want == Modify {
   177  				t.Fatalf("walk had to run on %s but didn't", wt.path)
   178  			}
   179  			err := errored[wt.path]
   180  			if err && wt.want != Error {
   181  				t.Fatalf("walk had to not err on %s but did", wt.path)
   182  			} else if !err && wt.want == Error {
   183  				t.Fatalf("walk had to err on %s but didn't", wt.path)
   184  			}
   185  		})
   186  	}
   187  	if doWalk("."); outBuf.Len() > 0 {
   188  		t.Fatal("shfmt -l -w printed paths on a duplicate run")
   189  	}
   190  	*list, *write = false, false
   191  	if doWalk("."); outBuf.Len() == 0 {
   192  		t.Fatal("shfmt without -l nor -w did not print anything")
   193  	}
   194  	if doWalk(".hidden"); outBuf.Len() == 0 {
   195  		t.Fatal("`shfmt .hidden` did not print anything")
   196  	}
   197  	if doWalk("nonexistent"); !gotError {
   198  		t.Fatal("`shfmt nonexistent` did not error")
   199  	}
   200  	*find = true
   201  	doWalk(".")
   202  	numFound := strings.Count(outBuf.String(), "\n")
   203  	if want := 13; numFound != want {
   204  		t.Fatalf("shfmt -f printed %d paths, but wanted %d", numFound, want)
   205  	}
   206  	*find = false
   207  }