github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/osutil/stat_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package osutil_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  	"syscall"
    29  
    30  	. "gopkg.in/check.v1"
    31  
    32  	"github.com/snapcore/snapd/osutil"
    33  )
    34  
    35  type StatTestSuite struct{}
    36  
    37  var _ = Suite(&StatTestSuite{})
    38  
    39  func (ts *StatTestSuite) TestFileDoesNotExist(c *C) {
    40  	c.Assert(osutil.FileExists("/i-do-not-exist"), Equals, false)
    41  }
    42  
    43  func (ts *StatTestSuite) TestFileExistsSimple(c *C) {
    44  	fname := filepath.Join(c.MkDir(), "foo")
    45  	err := ioutil.WriteFile(fname, []byte(fname), 0644)
    46  	c.Assert(err, IsNil)
    47  
    48  	c.Assert(osutil.FileExists(fname), Equals, true)
    49  }
    50  
    51  func (ts *StatTestSuite) TestFileExistsExistsOddPermissions(c *C) {
    52  	fname := filepath.Join(c.MkDir(), "foo")
    53  	err := ioutil.WriteFile(fname, []byte(fname), 0100)
    54  	c.Assert(err, IsNil)
    55  
    56  	c.Assert(osutil.FileExists(fname), Equals, true)
    57  }
    58  
    59  func (ts *StatTestSuite) TestIsDirectoryDoesNotExist(c *C) {
    60  	c.Assert(osutil.IsDirectory("/i-do-not-exist"), Equals, false)
    61  }
    62  
    63  func (ts *StatTestSuite) TestIsDirectorySimple(c *C) {
    64  	dname := filepath.Join(c.MkDir(), "bar")
    65  	err := os.Mkdir(dname, 0700)
    66  	c.Assert(err, IsNil)
    67  
    68  	c.Assert(osutil.IsDirectory(dname), Equals, true)
    69  }
    70  
    71  func (ts *StatTestSuite) TestIsSymlink(c *C) {
    72  	sname := filepath.Join(c.MkDir(), "symlink")
    73  	err := os.Symlink("/", sname)
    74  	c.Assert(err, IsNil)
    75  
    76  	c.Assert(osutil.IsSymlink(sname), Equals, true)
    77  }
    78  
    79  func (ts *StatTestSuite) TestIsSymlinkNoSymlink(c *C) {
    80  	c.Assert(osutil.IsSymlink(c.MkDir()), Equals, false)
    81  }
    82  
    83  func (ts *StatTestSuite) TestExecutableExists(c *C) {
    84  	oldPath := os.Getenv("PATH")
    85  	defer os.Setenv("PATH", oldPath)
    86  	d := c.MkDir()
    87  	os.Setenv("PATH", d)
    88  	c.Check(osutil.ExecutableExists("xyzzy"), Equals, false)
    89  
    90  	fname := filepath.Join(d, "xyzzy")
    91  	c.Assert(ioutil.WriteFile(fname, []byte{}, 0644), IsNil)
    92  	c.Check(osutil.ExecutableExists("xyzzy"), Equals, false)
    93  
    94  	c.Assert(os.Chmod(fname, 0755), IsNil)
    95  	c.Check(osutil.ExecutableExists("xyzzy"), Equals, true)
    96  }
    97  
    98  func (ts *StatTestSuite) TestLookPathDefaultGivesCorrectPath(c *C) {
    99  	r := osutil.MockLookPath(func(name string) (string, error) { return "/bin/true", nil })
   100  	defer r()
   101  	c.Assert(osutil.LookPathDefault("true", "/bin/foo"), Equals, "/bin/true")
   102  }
   103  
   104  func (ts *StatTestSuite) TestLookPathDefaultReturnsDefaultWhenNotFound(c *C) {
   105  	r := osutil.MockLookPath(func(name string) (string, error) { return "", fmt.Errorf("Not found") })
   106  	defer r()
   107  	c.Assert(osutil.LookPathDefault("bar", "/bin/bla"), Equals, "/bin/bla")
   108  }
   109  
   110  func makeTestPath(c *C, path string, mode os.FileMode) string {
   111  	return makeTestPathInDir(c, c.MkDir(), path, mode)
   112  }
   113  
   114  func makeTestPathInDir(c *C, dir, path string, mode os.FileMode) string {
   115  	mkdir := strings.HasSuffix(path, "/")
   116  	path = filepath.Join(dir, path)
   117  
   118  	if mkdir {
   119  		// request for directory
   120  		c.Assert(os.MkdirAll(path, mode), IsNil)
   121  	} else {
   122  		// request for a file
   123  		c.Assert(os.MkdirAll(filepath.Dir(path), 0755), IsNil)
   124  		c.Assert(ioutil.WriteFile(path, nil, mode), IsNil)
   125  	}
   126  
   127  	return path
   128  }
   129  
   130  func (ts *StatTestSuite) TestIsWritableDir(c *C) {
   131  	for _, t := range []struct {
   132  		path       string
   133  		mode       os.FileMode
   134  		isWritable bool
   135  	}{
   136  		{"dir/", 0755, true},
   137  		{"dir/", 0555, false},
   138  		{"dir/", 0750, true},
   139  		{"dir/", 0550, false},
   140  		{"dir/", 0700, true},
   141  		{"dir/", 0500, false},
   142  
   143  		{"file", 0644, true},
   144  		{"file", 0444, false},
   145  		{"file", 0640, true},
   146  		{"file", 0440, false},
   147  		{"file", 0600, true},
   148  		{"file", 0400, false},
   149  	} {
   150  		writable := osutil.IsWritable(makeTestPath(c, t.path, t.mode))
   151  		c.Check(writable, Equals, t.isWritable, Commentf("incorrect result for %q (%s), got %v, expected %v", t.path, t.mode, writable, t.isWritable))
   152  	}
   153  }
   154  
   155  func (ts *StatTestSuite) TestIsDirNotExist(c *C) {
   156  	for _, e := range []error{
   157  		os.ErrNotExist,
   158  		syscall.ENOENT,
   159  		syscall.ENOTDIR,
   160  		&os.PathError{Err: syscall.ENOENT},
   161  		&os.PathError{Err: syscall.ENOTDIR},
   162  		&os.LinkError{Err: syscall.ENOENT},
   163  		&os.LinkError{Err: syscall.ENOTDIR},
   164  		&os.SyscallError{Err: syscall.ENOENT},
   165  		&os.SyscallError{Err: syscall.ENOTDIR},
   166  	} {
   167  		c.Check(osutil.IsDirNotExist(e), Equals, true, Commentf("%#v (%v)", e, e))
   168  	}
   169  
   170  	for _, e := range []error{
   171  		nil,
   172  		fmt.Errorf("hello"),
   173  	} {
   174  		c.Check(osutil.IsDirNotExist(e), Equals, false)
   175  	}
   176  }
   177  
   178  func (ts *StatTestSuite) TestDirExists(c *C) {
   179  	for _, t := range []struct {
   180  		make   string
   181  		path   string
   182  		exists bool
   183  		isDir  bool
   184  	}{
   185  		{"", "foo", false, false},
   186  		{"", "foo/bar", false, false},
   187  		{"foo", "foo/bar", false, false},
   188  		{"foo", "foo", true, false},
   189  		{"foo/", "foo", true, true},
   190  	} {
   191  		base := c.MkDir()
   192  		comm := Commentf("path:%q make:%q", t.path, t.make)
   193  		if t.make != "" {
   194  			makeTestPathInDir(c, base, t.make, 0755)
   195  		}
   196  		exists, isDir, err := osutil.DirExists(filepath.Join(base, t.path))
   197  		c.Check(exists, Equals, t.exists, comm)
   198  		c.Check(isDir, Equals, t.isDir, comm)
   199  		c.Check(err, IsNil, comm)
   200  	}
   201  
   202  	p := makeTestPath(c, "foo/bar", 0)
   203  	c.Assert(os.Chmod(filepath.Dir(p), 0), IsNil)
   204  	defer os.Chmod(filepath.Dir(p), 0755)
   205  	exists, isDir, err := osutil.DirExists(p)
   206  	c.Check(exists, Equals, false)
   207  	c.Check(isDir, Equals, false)
   208  	c.Check(err, NotNil)
   209  }
   210  
   211  func (ts *StatTestSuite) TestIsExecutable(c *C) {
   212  	c.Check(osutil.IsExecutable("non-existent"), Equals, false)
   213  	c.Check(osutil.IsExecutable("."), Equals, false)
   214  	dir := c.MkDir()
   215  	c.Check(osutil.IsExecutable(dir), Equals, false)
   216  
   217  	for _, tc := range []struct {
   218  		mode os.FileMode
   219  		is   bool
   220  	}{
   221  		{0644, false},
   222  		{0444, false},
   223  		{0444, false},
   224  		{0000, false},
   225  		{0100, true},
   226  		{0010, true},
   227  		{0001, true},
   228  		{0755, true},
   229  	} {
   230  		c.Logf("tc: %v %v", tc.mode, tc.is)
   231  		p := filepath.Join(dir, "foo")
   232  		err := os.Remove(p)
   233  		c.Check(err == nil || os.IsNotExist(err), Equals, true)
   234  
   235  		err = ioutil.WriteFile(p, []byte(""), tc.mode)
   236  		c.Assert(err, IsNil)
   237  		c.Check(osutil.IsExecutable(p), Equals, tc.is)
   238  	}
   239  }
   240  
   241  func (ts *StatTestSuite) TestRegularFileExists(c *C) {
   242  	tt := []struct {
   243  		make           bool
   244  		makeNonRegular bool
   245  		path           string
   246  		expExists      bool
   247  		expIsReg       bool
   248  		expErr         string
   249  		comment        string
   250  	}{
   251  		{
   252  			make:      true,
   253  			path:      "foo",
   254  			expExists: true,
   255  			expIsReg:  true,
   256  			comment:   "file is regular",
   257  		},
   258  		{
   259  			make:           true,
   260  			makeNonRegular: true,
   261  			path:           "bar",
   262  			expExists:      true,
   263  			comment:        "file is symlink",
   264  		},
   265  		{
   266  			path:      "not-exists",
   267  			expExists: false,
   268  			expErr:    ".*no such file or directory",
   269  			comment:   "file doesn't exist",
   270  		},
   271  	}
   272  
   273  	for _, t := range tt {
   274  		fullpath := filepath.Join(c.MkDir(), t.path)
   275  		comment := Commentf(t.comment)
   276  
   277  		if t.make {
   278  			if t.makeNonRegular {
   279  				// make it a symlink
   280  				err := os.Symlink("foo", fullpath)
   281  				c.Assert(err, IsNil, comment)
   282  			} else {
   283  				// make it a normal file
   284  				err := ioutil.WriteFile(fullpath, nil, 0644)
   285  				c.Assert(err, IsNil, comment)
   286  			}
   287  		}
   288  
   289  		exists, isReg, err := osutil.RegularFileExists(fullpath)
   290  		if t.expErr != "" {
   291  			c.Assert(err, ErrorMatches, t.expErr, comment)
   292  			continue
   293  		}
   294  		c.Assert(exists, Equals, t.expExists, comment)
   295  		c.Assert(isReg, Equals, t.expIsReg, comment)
   296  	}
   297  }