github.com/cilki/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 }