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  }