github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/datafs/wdfs_test.go (about)

     1  package datafs
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/fs"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  
    12  	"github.com/hack-pad/hackpadfs"
    13  	"github.com/hack-pad/hackpadfs/mem"
    14  	osfs "github.com/hack-pad/hackpadfs/os"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  	tfs "gotest.tools/v3/fs"
    18  )
    19  
    20  func TestWDFS_ReadOps(t *testing.T) {
    21  	wd, _ := os.Getwd()
    22  	t.Cleanup(func() {
    23  		_ = os.Chdir(wd)
    24  	})
    25  	_ = os.Chdir("/")
    26  
    27  	memfs, _ := mem.NewFS()
    28  
    29  	_ = memfs.Mkdir("tmp", 0o777)
    30  	_ = hackpadfs.WriteFullFile(memfs, "tmp/foo", []byte("hello world"), 0o777)
    31  	_ = hackpadfs.WriteFullFile(memfs, "tmp/one.txt", []byte("one"), 0o644)
    32  	_ = hackpadfs.WriteFullFile(memfs, "tmp/two.txt", []byte("two"), 0o644)
    33  	_ = hackpadfs.WriteFullFile(memfs, "tmp/three.txt", []byte("three"), 0o644)
    34  	_ = memfs.Mkdir("tmp/sub", 0o777)
    35  	_ = hackpadfs.WriteFullFile(memfs, "tmp/sub/bar", []byte("goodnight moon"), 0o777)
    36  
    37  	fsys := WrapWdFS(memfs).(*wdFS)
    38  
    39  	f, err := fsys.Open("/tmp/foo")
    40  	require.NoError(t, err)
    41  
    42  	b, err := io.ReadAll(f)
    43  	require.NoError(t, err)
    44  	assert.Equal(t, "hello world", string(b))
    45  
    46  	fi, err := fs.Stat(fsys, "/tmp/sub/bar")
    47  	require.NoError(t, err)
    48  	assert.True(t, fi.Mode().IsRegular())
    49  
    50  	b, err = fs.ReadFile(fsys, "/tmp/sub/bar")
    51  	require.NoError(t, err)
    52  	assert.Equal(t, "goodnight moon", string(b))
    53  
    54  	des, err := fs.ReadDir(fsys, "/tmp")
    55  	require.NoError(t, err)
    56  	assert.Len(t, des, 5)
    57  
    58  	// note the relative path here, a requirement of fsys.Sub
    59  	subfs, err := fs.Sub(fsys, "tmp/sub")
    60  	require.NoError(t, err)
    61  
    62  	b, err = fs.ReadFile(subfs, "bar")
    63  	require.NoError(t, err)
    64  	assert.Equal(t, "goodnight moon", string(b))
    65  }
    66  
    67  func TestWDFS_WriteOps(t *testing.T) {
    68  	// this test is backed by the real filesystem so we can test permissions
    69  	// and have some confidence it'll run on Windows
    70  	tmpDir := tfs.NewDir(t, "gomplate-wdfs-test")
    71  	tmpPath := tmpDir.Path()
    72  	vol := filepath.VolumeName(tmpPath)
    73  	if vol != "" {
    74  		tmpPath = tmpPath[len(vol):]
    75  	} else if tmpPath[0] == '/' {
    76  		vol = "/"
    77  		tmpPath = tmpPath[1:]
    78  	}
    79  
    80  	var osfsys fs.FS
    81  	var err error
    82  	if vol != "/" {
    83  		osfsys, err = osfs.NewFS().SubVolume(vol)
    84  		require.NoError(t, err)
    85  	} else {
    86  		osfsys = osfs.NewFS()
    87  	}
    88  
    89  	osfsys, err = hackpadfs.Sub(osfsys, tmpPath)
    90  	require.NoError(t, err)
    91  
    92  	fsys := &wdFS{
    93  		vol:  vol,
    94  		fsys: osfsys,
    95  	}
    96  
    97  	err = fsys.Mkdir("/tmp", 0o700)
    98  	require.NoError(t, err, "failed to create /tmp: %q", tmpDir.Path())
    99  
   100  	// use os.Stat to make sure the directory was created in the right place
   101  	fi, err := os.Stat(filepath.Join(vol, tmpPath, "tmp"))
   102  	require.NoError(t, err)
   103  	assert.True(t, fi.Mode().IsDir())
   104  
   105  	err = hackpadfs.WriteFullFile(fsys, "/tmp/foo", []byte("hello world"), 0o600)
   106  	require.NoError(t, err)
   107  	err = hackpadfs.WriteFullFile(fsys, "/tmp/one.txt", []byte("one"), 0o644)
   108  	require.NoError(t, err)
   109  	err = hackpadfs.WriteFullFile(fsys, "/tmp/two.txt", []byte("two"), 0o644)
   110  	require.NoError(t, err)
   111  	err = hackpadfs.WriteFullFile(fsys, "/tmp/three.txt", []byte("three"), 0o644)
   112  	require.NoError(t, err)
   113  
   114  	err = fsys.MkdirAll("/tmp/sub", 0o777)
   115  	require.NoError(t, err)
   116  	err = hackpadfs.WriteFullFile(fsys, "/tmp/sub/bar", []byte("goodnight moon"), 0o777)
   117  	require.NoError(t, err)
   118  
   119  	b, err := fs.ReadFile(fsys, "/tmp/foo")
   120  	require.NoError(t, err)
   121  	assert.Equal(t, "hello world", string(b))
   122  
   123  	b, err = fs.ReadFile(fsys, "/tmp/sub/bar")
   124  	require.NoError(t, err)
   125  	assert.Equal(t, "goodnight moon", string(b))
   126  
   127  	err = fsys.Chmod("/tmp/foo", 0o444)
   128  	require.NoError(t, err)
   129  
   130  	// check permissions
   131  	fi, err = fsys.Stat("/tmp/foo")
   132  	require.NoError(t, err)
   133  	assert.True(t, fi.Mode().IsRegular())
   134  	assert.Equal(t, "0444", fmt.Sprintf("%#o", fi.Mode().Perm()))
   135  
   136  	// now delete it
   137  	err = fsys.Remove("/tmp/foo")
   138  	require.NoError(t, err)
   139  
   140  	// and check that it's gone
   141  	_, err = fsys.Stat("/tmp/foo")
   142  	require.ErrorIs(t, err, fs.ErrNotExist)
   143  
   144  	// make sure we can write to a subfs
   145  	subfs, err := fs.Sub(fsys, "tmp")
   146  	require.NoError(t, err)
   147  	require.NotNil(t, subfs)
   148  
   149  	// this is no longer a wdFS so we need to make sure not to use absolute
   150  	// paths - the path is relative to the root of the subfs
   151  	err = hackpadfs.WriteFullFile(subfs, "foo", []byte("hello world"), 0o600)
   152  	require.NoError(t, err)
   153  
   154  	b, err = fs.ReadFile(subfs, "foo")
   155  	require.NoError(t, err)
   156  	assert.Equal(t, "hello world", string(b))
   157  }
   158  
   159  func skipWindows(t *testing.T) {
   160  	t.Helper()
   161  	if runtime.GOOS == "windows" {
   162  		t.Skip("skipping non-Windows test")
   163  	}
   164  }
   165  
   166  func skipNonWindows(t *testing.T) {
   167  	t.Helper()
   168  	if runtime.GOOS != "windows" {
   169  		t.Skip("skipping Windows test")
   170  	}
   171  }
   172  
   173  func TestResolveLocalPath_NonWindows(t *testing.T) {
   174  	skipWindows(t)
   175  
   176  	wd, _ := os.Getwd()
   177  	fsys := &wdFS{vol: "/", fsys: osfs.NewFS()}
   178  
   179  	wd = wd[1:]
   180  
   181  	testdata := []struct {
   182  		path     string
   183  		expected string
   184  	}{
   185  		{"/tmp/foo", "tmp/foo"},
   186  		{"tmp/foo", wd + "/tmp/foo"},
   187  		{"./tmp/foo", wd + "/tmp/foo"},
   188  		{"tmp/../foo", wd + "/foo"},
   189  		{"/", "."},
   190  	}
   191  
   192  	for _, td := range testdata {
   193  		td := td
   194  		t.Run(td.path, func(t *testing.T) {
   195  			root, path, err := ResolveLocalPath(fsys, td.path)
   196  			require.NoError(t, err)
   197  			assert.Equal(t, "/", root)
   198  			assert.Equal(t, td.expected, path)
   199  		})
   200  	}
   201  }
   202  
   203  func TestResolveLocalPath_Windows(t *testing.T) {
   204  	skipNonWindows(t)
   205  
   206  	wd, _ := os.Getwd()
   207  	volname := filepath.VolumeName(wd)
   208  	wd = filepath.ToSlash(wd)
   209  
   210  	fsys := &wdFS{vol: volname, fsys: osfs.NewFS()}
   211  
   212  	wd = wd[len(volname)+1:]
   213  
   214  	testdata := []struct {
   215  		path     string
   216  		expRoot  string
   217  		expected string
   218  	}{
   219  		{"C:/tmp/foo", "C:", "tmp/foo"},
   220  		{"D:\\tmp\\foo", "D:", "tmp/foo"},
   221  		{"/tmp/foo", volname, "tmp/foo"},
   222  		{"tmp/foo", volname, wd + "/tmp/foo"},
   223  		{"./tmp/foo", volname, wd + "/tmp/foo"},
   224  		{"tmp/../foo", volname, wd + "/foo"},
   225  	}
   226  
   227  	for _, td := range testdata {
   228  		td := td
   229  		t.Run(td.path, func(t *testing.T) {
   230  			root, path, err := ResolveLocalPath(fsys, td.path)
   231  			require.NoError(t, err)
   232  			assert.Equal(t, td.expRoot, root)
   233  			assert.Equal(t, td.expected, path)
   234  		})
   235  	}
   236  }
   237  
   238  func TestWdFS_ResolveLocalPath_NonWindows(t *testing.T) {
   239  	skipWindows(t)
   240  
   241  	wd, _ := os.Getwd()
   242  	wd = wd[1:]
   243  
   244  	testdata := []struct {
   245  		path     string
   246  		expected string
   247  	}{
   248  		{"/tmp/foo", "tmp/foo"},
   249  		{"tmp/foo", wd + "/tmp/foo"},
   250  		{"./tmp/foo", wd + "/tmp/foo"},
   251  		{"tmp/../foo", wd + "/foo"},
   252  		{"/", "."},
   253  	}
   254  
   255  	for _, td := range testdata {
   256  		root, path, err := resolveLocalPath("/", td.path)
   257  		require.NoError(t, err)
   258  		assert.Equal(t, "/", root)
   259  		assert.Equal(t, td.expected, path)
   260  	}
   261  }
   262  
   263  func TestWdFS_ResolveLocalPath_Windows(t *testing.T) {
   264  	skipNonWindows(t)
   265  
   266  	wd, _ := os.Getwd()
   267  	volname := filepath.VolumeName(wd)
   268  	wd = filepath.ToSlash(wd)
   269  	wd = wd[len(volname)+1:]
   270  
   271  	testdata := []struct {
   272  		path     string
   273  		expRoot  string
   274  		expected string
   275  	}{
   276  		{"C:/tmp/foo", "C:", "tmp/foo"},
   277  		{`D:\tmp\foo`, "D:", "tmp/foo"},
   278  		{"/tmp/foo", volname, "tmp/foo"},
   279  		{"tmp/foo", volname, wd + "/tmp/foo"},
   280  		{"./tmp/foo", volname, wd + "/tmp/foo"},
   281  		{"tmp/../foo", volname, wd + "/foo"},
   282  		{`\\?\C:\tmp\foo`, "C:", "tmp/foo"},
   283  		{`\\somehost\share\foo\bar`, "//somehost/share", "foo/bar"},
   284  		{`//?/C:/tmp/foo`, "C:", "tmp/foo"},
   285  		{`//somehost/share/foo/bar`, "//somehost/share", "foo/bar"},
   286  	}
   287  
   288  	for _, td := range testdata {
   289  		td := td
   290  		t.Run(td.path, func(t *testing.T) {
   291  			root, path, err := resolveLocalPath(volname, td.path)
   292  			require.NoError(t, err)
   293  			assert.Equal(t, td.expRoot, root)
   294  			assert.Equal(t, td.expected, path)
   295  		})
   296  	}
   297  }
   298  
   299  func TestWin32PathType(t *testing.T) {
   300  	testdata := []struct {
   301  		path     string
   302  		expected winPathtype
   303  	}{
   304  		{"", winPathUnknown},
   305  		{`\`, winPathRooted},
   306  		{`\\`, winPathUncAbsolute},
   307  		{`x`, winPathRelative},
   308  		{`x:`, winPathDriveRelative},
   309  		{"C:/tmp/foo", winPathDriveAbsolute},
   310  		{`D:\tmp\foo`, winPathDriveAbsolute},
   311  		{"/tmp/foo", winPathRooted},
   312  		{"tmp/foo", winPathRelative},
   313  		{"./tmp/foo", winPathRelative},
   314  		{"tmp/../foo", winPathRelative},
   315  		{`\\?\C:\tmp\foo`, winPathLocalDevice},
   316  		{`\\somehost\share\foo\bar`, winPathUncAbsolute},
   317  		{`//./C:/tmp/foo`, winPathLocalDevice},
   318  		{`//./pipe/foo`, winPathLocalDevice},
   319  		{`//./COM2`, winPathLocalDevice},
   320  		{`\\.`, winPathRootLocalDevice},
   321  		{`//?`, winPathRootLocalDevice},
   322  		{`/??/C:/`, winPathNT},
   323  		{`/??/UNC/server/foo`, winPathNT},
   324  	}
   325  
   326  	for _, td := range testdata {
   327  		td := td
   328  		t.Run(td.path, func(t *testing.T) {
   329  			assert.Equal(t, td.expected, win32PathType(td.path))
   330  		})
   331  	}
   332  }