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