github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/ls/ls_test.go (about) 1 // Copyright 2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "errors" 10 "fmt" 11 "os" 12 "path/filepath" 13 "strings" 14 "testing" 15 16 "github.com/mvdan/u-root-coreutils/pkg/ls" 17 "golang.org/x/sys/unix" 18 ) 19 20 type ttflags struct { 21 all bool 22 human bool 23 directory bool 24 long bool 25 quoted bool 26 recurse bool 27 classify bool 28 } 29 30 // Test listName func 31 func TestListName(t *testing.T) { 32 // Create some directorys. 33 tmpDir := t.TempDir() 34 if err := os.Mkdir(filepath.Join(tmpDir, "d1"), 0777); err != nil { 35 t.Fatalf("err in os.Mkdir: %v", err) 36 } 37 // Create some files. 38 files := []string{"f1", "f2", "f3\nline 2", ".f4", "d1/f4"} 39 for _, file := range files { 40 if _, err := os.Create(filepath.Join(tmpDir, file)); err != nil { 41 t.Fatalf("err in os.Create: %v", err) 42 } 43 } 44 45 // Creating test table 46 for _, tt := range []struct { 47 name string 48 input string 49 want string 50 flag ttflags 51 prefix bool 52 }{ 53 { 54 name: "ls without arguments", 55 input: tmpDir, 56 want: fmt.Sprintf("%s\n%s\n%s\n%s\n", "d1", "f1", "f2", "f3?line 2"), 57 flag: ttflags{}, 58 }, 59 { 60 name: "ls osfi.IsDir() path, quoted = true", 61 input: tmpDir, 62 want: fmt.Sprintf("\"%s\"\n\"%s\"\n\"%s\"\n\"%s\"\n", "d1", "f1", "f2", "f3\\nline 2"), 63 flag: ttflags{ 64 quoted: true, 65 }, 66 }, 67 { 68 name: "ls osfi.IsDir() path, quoted = true, prefix = true ", 69 input: tmpDir, 70 want: fmt.Sprintf("\"%s\":\n\"%s\"\n\"%s\"\n\"%s\"\n\"%s\"\n", tmpDir, "d1", "f1", "f2", "f3\\nline 2"), 71 flag: ttflags{ 72 quoted: true, 73 }, 74 prefix: true, 75 }, 76 { 77 name: "ls osfi.IsDir() path, quoted = false, prefix = true ", 78 input: tmpDir, 79 want: fmt.Sprintf("%s:\n%s\n%s\n%s\n%s\n", tmpDir, "d1", "f1", "f2", "f3?line 2"), 80 prefix: true, 81 }, 82 { 83 name: "ls recurse = true", 84 input: tmpDir, 85 want: fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n", tmpDir, filepath.Join(tmpDir, ".f4"), filepath.Join(tmpDir, "d1"), 86 filepath.Join(tmpDir, "d1/f4"), filepath.Join(tmpDir, "f1"), filepath.Join(tmpDir, "f2"), filepath.Join(tmpDir, "f3?line 2")), 87 flag: ttflags{ 88 all: true, 89 recurse: true, 90 }, 91 }, 92 { 93 name: "ls directory = true", 94 input: tmpDir, 95 want: fmt.Sprintf("%s\n", "tmpDir"), 96 flag: ttflags{ 97 directory: true, 98 }, 99 }, 100 { 101 name: "ls classify = true", 102 input: tmpDir, 103 want: fmt.Sprintf("%s\n%s\n%s\n%s\n", "d1/", "f1", "f2", "f3?line 2"), 104 flag: ttflags{ 105 classify: true, 106 }, 107 }, 108 { 109 name: "file does not exist", 110 input: "dir", 111 flag: ttflags{}, 112 }, 113 } { 114 // Setting the flags 115 *all = tt.flag.all 116 *human = tt.flag.human 117 *directory = tt.flag.directory 118 *long = tt.flag.long 119 *quoted = tt.flag.quoted 120 *recurse = tt.flag.recurse 121 *classify = tt.flag.classify 122 123 // Running the tests 124 t.Run(tt.name, func(t *testing.T) { 125 // Write output in buffer. 126 var buf bytes.Buffer 127 var s ls.Stringer = ls.NameStringer{} 128 if *quoted { 129 s = ls.QuotedStringer{} 130 } 131 if *long { 132 s = ls.LongStringer{Human: *human, Name: s} 133 } 134 if err := listName(s, tt.input, &buf, tt.prefix); err != nil { 135 if buf.String() != tt.want { 136 t.Errorf("listName() = '%v', want: '%v'", buf.String(), tt.want) 137 } 138 } 139 }) 140 } 141 } 142 143 // Test list func 144 func TestList(t *testing.T) { 145 // Creating test table 146 for _, tt := range []struct { 147 name string 148 input []string 149 err error 150 flag ttflags 151 prefix bool 152 }{ 153 { 154 name: "input empty, quoted = true, long = true", 155 input: []string{}, 156 err: nil, 157 flag: ttflags{ 158 quoted: true, 159 long: true, 160 }, 161 }, 162 { 163 name: "input empty, quoted = true, long = true", 164 input: []string{"dir"}, 165 err: os.ErrNotExist, 166 }, 167 } { 168 169 // Setting the flags 170 *long = tt.flag.long 171 *quoted = tt.flag.quoted 172 173 // Running the tests 174 t.Run(tt.name, func(t *testing.T) { 175 var buf bytes.Buffer 176 if err := list(&buf, tt.input); err != nil { 177 if !errors.Is(err, tt.err) { 178 t.Errorf("list() = '%v', want: '%v'", err, tt.err) 179 } 180 } 181 }) 182 } 183 } 184 185 // Test indicator func 186 func TestIndicator(t *testing.T) { 187 // Creating test table 188 for _, test := range []struct { 189 lsInfo ls.FileInfo 190 symbol string 191 }{ 192 { 193 ls.FileInfo{ 194 Mode: os.ModeDir, 195 }, 196 "/", 197 }, 198 { 199 ls.FileInfo{ 200 Mode: os.ModeNamedPipe, 201 }, 202 "|", 203 }, 204 { 205 ls.FileInfo{ 206 Mode: os.ModeSymlink, 207 }, 208 "@", 209 }, 210 { 211 ls.FileInfo{ 212 Mode: os.ModeSocket, 213 }, 214 "=", 215 }, 216 { 217 ls.FileInfo{ 218 Mode: 0b110110100, 219 }, 220 "", 221 }, 222 { 223 ls.FileInfo{ 224 Mode: 0b111111101, 225 }, 226 "*", 227 }, 228 } { 229 // Run tests 230 got := indicator(test.lsInfo) 231 if got != test.symbol { 232 t.Errorf("for mode '%b' expected '%q', got '%q'", test.lsInfo.Mode, test.symbol, got) 233 } 234 } 235 } 236 237 // Make sure if perms fail in a dir, we still list the dir. 238 func TestPermHandling(t *testing.T) { 239 d := t.TempDir() 240 for _, v := range []string{"a", "c", "d"} { 241 if err := os.Mkdir(filepath.Join(d, v), 0777); err != nil { 242 t.Fatal(err) 243 } 244 } 245 if err := os.Mkdir(filepath.Join(d, "b"), 0); err != nil { 246 t.Fatal(err) 247 } 248 for _, v := range []string{"0", "1", "2"} { 249 if err := os.Mkdir(filepath.Join(d, v), 0777); err != nil { 250 t.Fatal(err) 251 } 252 } 253 b := &bytes.Buffer{} 254 if err := listName(ls.NameStringer{}, d, b, false); err != nil { 255 t.Fatalf("listName(ls.NameString{}, %q, w, false): %v != nil", d, err) 256 } 257 // the output varies very widely between kernels and Go versions :-( 258 // Just look for 'permission denied' and more than 6 lines of output ... 259 if !strings.Contains(b.String(), "0\n1\n2\na\nb\nc\nd\n") { 260 t.Errorf("ls %q: output %q did not contain %q", d, b.String(), "0\n1\n2\na\nb\nc\nd\n") 261 } 262 } 263 264 func TestNotExist(t *testing.T) { 265 d := t.TempDir() 266 b := &bytes.Buffer{} 267 if err := listName(ls.NameStringer{}, filepath.Join(d, "b"), b, false); err != nil { 268 t.Fatalf("listName(ls.NameString{}, %q/b, w, false): nil != %v", d, err) 269 } 270 // yeesh. 271 // errors not consistent and ... the error has this gratuitous 'lstat ' in front 272 // of the filename ... 273 eexist := fmt.Sprintf("%s:%v", filepath.Join(d, "b"), os.ErrNotExist) 274 enoent := fmt.Sprintf("%s: %v", filepath.Join(d, "b"), unix.ENOENT) 275 if !strings.Contains(b.String(), eexist) && !strings.Contains(b.String(), enoent) { 276 t.Fatalf("ls of bad name: %q does not contain %q or %q", b.String(), eexist, enoent) 277 } 278 }