github.com/fhs/u-root@v7.0.0+incompatible/cmds/core/ln/ln_test.go (about) 1 // Copyright 2016 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 // created by Manoel Vilela <manoel_vilela@engineer.com> 6 7 package main 8 9 import ( 10 "io/ioutil" 11 "os" 12 "path/filepath" 13 "strings" 14 "testing" 15 ) 16 17 type create struct { 18 name string 19 dir bool 20 } 21 22 type result struct { 23 symlink bool 24 name, linksTo string 25 } 26 27 type test struct { 28 conf config // conf with flags 29 args []string // to pass for ln 30 results []result // expected results 31 files []create // previous files for testing 32 cmdline string // cmdline ln equivalent 33 } 34 35 // prepareTestName prepares a custom testname for creating file/folder 36 // using a cmdline, for that remove chars whose conflicts with unix paths 37 func prepareTestName(cmdline string) string { 38 d := strings.Replace(cmdline, " ", "_", -1) 39 return strings.Replace(d, "/", "|", -1) 40 } 41 42 // loadTests loads the main table driven tests 43 // for ln command tests 44 func loadTests() []test { 45 return []test{ 46 { 47 // covers usage: 48 // ln [OPTIONS]... [-T] TARGET LINK_NAME (1st form) (posix) 49 config{}, 50 []string{"a", "b"}, 51 []result{{name: "b", linksTo: "a"}}, 52 []create{{name: "a"}}, 53 "ln a b", 54 }, 55 { 56 config{symlink: true}, 57 []string{"a", "b"}, 58 []result{{symlink: true, name: "b", linksTo: "a"}}, 59 []create{{name: "a"}}, 60 "ln -s a b", 61 }, 62 { 63 // covers usage: 64 // ln [OPTIONS]... TARGET (2nd form) (gnu) 65 config{symlink: true}, 66 []string{"bin/cp"}, 67 []result{ 68 {symlink: true, name: "cp", linksTo: "bin/cp"}, 69 }, 70 []create{ 71 {name: "bin", dir: true}, 72 {name: "bin/cp"}, 73 }, 74 "ln -s bin/cp", 75 }, 76 { 77 // covers usage: 78 // ln [OPTIONS]... TARGET... DIRECTORY (3rd form) (posix) 79 config{symlink: true}, 80 []string{"bin/cp", "bin/ls", "bin/ln", "."}, 81 []result{ 82 {symlink: true, name: "cp", linksTo: "bin/cp"}, 83 {symlink: true, name: "ls", linksTo: "bin/ls"}, 84 {symlink: true, name: "ln", linksTo: "bin/ln"}, 85 }, 86 []create{ 87 {name: "bin", dir: true}, 88 {name: "bin/cp"}, 89 {name: "bin/ls"}, 90 {name: "bin/ln"}, 91 }, 92 "ln -s bin/cp bin/ls bin/ln .", 93 }, 94 { 95 // covers usage: 96 // ln [OPTIONS]... -t DIRECTORY TARGET... (4th form) (gnu) 97 config{symlink: true, dirtgt: "."}, 98 []string{"bin/cp", "bin/ls", "bin/ln"}, 99 []result{ 100 {symlink: true, name: "cp", linksTo: "bin/cp"}, 101 {symlink: true, name: "ls", linksTo: "bin/ls"}, 102 {symlink: true, name: "ln", linksTo: "bin/ln"}, 103 }, 104 []create{ 105 {name: "bin", dir: true}, 106 {name: "bin/cp"}, 107 {name: "bin/ls"}, 108 {name: "bin/ln"}, 109 }, 110 "ln -s bin/cp bin/ls bin/ln -t .", 111 }, 112 { 113 // covers usage: 114 // ln [OPTIONS]... -t DIRECTORY TARGET... (4th form) (gnu) 115 config{symlink: true, dirtgt: "folder", relative: true}, 116 []string{"cp", "ls", "ln"}, 117 []result{ 118 {symlink: true, name: "folder/cp", linksTo: "../cp"}, 119 {symlink: true, name: "folder/ls", linksTo: "../ls"}, 120 {symlink: true, name: "folder/ln", linksTo: "../ln"}, 121 }, 122 []create{ 123 {name: "folder", dir: true}, 124 {name: "cp"}, 125 {name: "ls"}, 126 {name: "ln"}, 127 }, 128 "ln -s -v -r -t folder cp ls ln", 129 }, 130 { 131 // -i -f mutually exclusive (f overwrite evers) 132 config{force: true, prompt: true}, 133 []string{"a", "overwrite"}, 134 []result{ 135 {name: "overwrite", linksTo: "a"}, 136 }, 137 []create{ 138 {name: "overwrite"}, 139 {name: "a"}, 140 }, 141 "ln -i -f a overwrite", 142 }, 143 } 144 } 145 146 // newDir create a temp dir 147 func newDir(testName string, t *testing.T) (name string) { 148 name, err := ioutil.TempDir("", "Go_"+testName) 149 if err != nil { 150 t.Fatalf("TempDir %s: %s", testName, err) 151 } 152 return 153 } 154 155 // testHardLink test if hardlink creation was successful 156 // 'target' and 'linkName' must exists 157 // linkName -> target 158 func testHardLink(linkName, target string, t *testing.T) { 159 linkStat, err := os.Stat(linkName) 160 if err != nil { 161 t.Errorf("stat %q failed: %v", linkName, err) 162 } 163 targetStat, err := os.Stat(target) 164 if err != nil { 165 t.Errorf("stat %q failed: %v", target, err) 166 } 167 if !os.SameFile(linkStat, targetStat) { 168 t.Errorf("link %q, %q did not create hard link", linkName, target) 169 } 170 } 171 172 // testSymllink test if symlink creation was successful 173 // 'target' and 'linkName' must exists 174 // linkName -> target 175 func testSymlink(linkName, linksTo string, t *testing.T) { 176 target := linksTo 177 if !filepath.IsAbs(target) { 178 target = filepath.Base(target) 179 } 180 181 linkStat, err := os.Stat(linkName) 182 if err != nil { 183 t.Errorf("stat %q failed: %v", linkName, err) 184 } 185 targetStat, err := os.Stat(target) 186 if err != nil { 187 t.Errorf("stat %q failed: %v", target, err) 188 } 189 if !os.SameFile(linkStat, targetStat) { 190 t.Errorf("symlink %q, %q did not create symlink", linkName, target) 191 } 192 targetStat, err = os.Stat(target) 193 if err != nil { 194 t.Errorf("lstat %q failed: %v", target, err) 195 } 196 197 if targetStat.Mode()&os.ModeSymlink == os.ModeSymlink { 198 t.Errorf("symlink %q, %q did not create symlink", linkName, target) 199 } 200 201 targetStat, err = os.Stat(target) 202 if err != nil { 203 t.Errorf("stat %q failed: %v", target, err) 204 } 205 if targetStat.Mode()&os.ModeSymlink != 0 { 206 t.Errorf("stat %q did not follow symlink", target) 207 } 208 s, err := os.Readlink(linkName) 209 if err != nil { 210 t.Errorf("readlink %q failed: %v", target, err) 211 } 212 if s != linksTo { 213 t.Errorf("after symlink %q != %q", s, target) 214 } 215 file, err := os.Open(target) 216 if err != nil { 217 t.Errorf("open %q failed: %v", target, err) 218 } 219 file.Close() 220 } 221 222 // TestLn make a general tests based on 223 // tabDriven tests (see loadTests()) 224 func TestLn(t *testing.T) { 225 tabDriven := loadTests() 226 testDir := newDir("TestLnGeneric", t) 227 defer os.RemoveAll(testDir) 228 229 // executing ln on isolated testDir 230 if err := os.Chdir(testDir); err != nil { 231 t.Fatalf("Changing directory for %q fails: %v", testDir, err) 232 } 233 defer os.Chdir("..") // after defer to go back to the original root 234 235 for caseNum, testCase := range tabDriven { 236 d := newDir(prepareTestName(testCase.cmdline), t) 237 if err := os.Chdir(d); err != nil { 238 t.Fatalf("Changing directory for %q fails: %v", d, err) 239 } 240 241 for _, f := range testCase.files { 242 t.Logf("Creating: %v (dir: %v)", f.name, f.dir) 243 p := filepath.Join(f.name) 244 if f.dir { 245 if err := os.Mkdir(p, 0750); err != nil && err == os.ErrExist { 246 t.Skipf("Creation of dir %q fails: %v", p, err) 247 } 248 } else { 249 if err := ioutil.WriteFile(p, []byte{'.'}, 0640); err != nil { 250 t.Fatal(err) 251 } 252 } 253 254 } 255 256 if err := testCase.conf.ln(testCase.args); err != nil { 257 t.Errorf("Fails: test [%d]. %v", caseNum+1, err) 258 continue 259 } 260 261 t.Logf("Testing cmdline: %q", testCase.cmdline) 262 for _, expected := range testCase.results { 263 if expected.symlink { 264 t.Logf("%q -> %q (symlink)", expected.name, expected.linksTo) 265 testSymlink(expected.name, expected.linksTo, t) 266 } else { 267 t.Logf("%q -> %q (hardlink)", expected.name, expected.linksTo) 268 testHardLink(expected.name, expected.linksTo, t) 269 } 270 271 } 272 273 // backing to testDir folder 274 os.Chdir("..") 275 } 276 }