github.com/insomniacslk/u-root@v0.0.0-20200717035308-96b791510d76/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  }