github.com/sdboyer/gps@v0.16.3/filesystem_test.go (about)

     1  package gps
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  )
     8  
     9  // This file contains utilities for running tests around file system state.
    10  
    11  // fspath represents a file system path in an OS-agnostic way.
    12  type fsPath []string
    13  
    14  func (f fsPath) String() string { return filepath.Join(f...) }
    15  
    16  func (f fsPath) prepend(prefix string) fsPath {
    17  	p := fsPath{filepath.FromSlash(prefix)}
    18  	return append(p, f...)
    19  }
    20  
    21  type fsTestCase struct {
    22  	before, after filesystemState
    23  }
    24  
    25  // filesystemState represents the state of a file system. It has a setup method
    26  // which inflates its state to the actual host file system, and an assert
    27  // method which checks that the actual file system matches the described state.
    28  type filesystemState struct {
    29  	root  string
    30  	dirs  []fsPath
    31  	files []fsPath
    32  	links []fsLink
    33  }
    34  
    35  // assert makes sure that the fs state matches the state of the actual host
    36  // file system
    37  func (fs filesystemState) assert(t *testing.T) {
    38  	dirMap := make(map[string]bool)
    39  	fileMap := make(map[string]bool)
    40  	linkMap := make(map[string]bool)
    41  
    42  	for _, d := range fs.dirs {
    43  		dirMap[d.prepend(fs.root).String()] = true
    44  	}
    45  	for _, f := range fs.files {
    46  		fileMap[f.prepend(fs.root).String()] = true
    47  	}
    48  	for _, l := range fs.links {
    49  		linkMap[l.path.prepend(fs.root).String()] = true
    50  	}
    51  
    52  	err := filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error {
    53  		if err != nil {
    54  			t.Errorf("filepath.Walk path=%q  err=%q", path, err)
    55  			return err
    56  		}
    57  
    58  		if path == fs.root {
    59  			return nil
    60  		}
    61  
    62  		// Careful! Have to check whether the path is a symlink first because, on
    63  		// windows, a symlink to a directory will return 'true' for info.IsDir().
    64  		if (info.Mode() & os.ModeSymlink) != 0 {
    65  			if linkMap[path] {
    66  				delete(linkMap, path)
    67  			} else {
    68  				t.Errorf("unexpected symlink exists %q", path)
    69  			}
    70  			return nil
    71  		}
    72  
    73  		if info.IsDir() {
    74  			if dirMap[path] {
    75  				delete(dirMap, path)
    76  			} else {
    77  				t.Errorf("unexpected directory exists %q", path)
    78  			}
    79  			return nil
    80  		}
    81  
    82  		if fileMap[path] {
    83  			delete(fileMap, path)
    84  		} else {
    85  			t.Errorf("unexpected file exists %q", path)
    86  		}
    87  		return nil
    88  	})
    89  
    90  	if err != nil {
    91  		t.Errorf("filesystem.Walk err=%q", err)
    92  	}
    93  
    94  	for d := range dirMap {
    95  		t.Errorf("could not find expected directory %q", d)
    96  	}
    97  	for f := range fileMap {
    98  		t.Errorf("could not find expected file %q", f)
    99  	}
   100  	for l := range linkMap {
   101  		t.Errorf("could not find expected symlink %q", l)
   102  	}
   103  }
   104  
   105  // fsLink represents a symbolic link.
   106  type fsLink struct {
   107  	path fsPath
   108  	to   string
   109  }
   110  
   111  // setup inflates fs onto the actual host file system
   112  func (fs filesystemState) setup(t *testing.T) {
   113  	fs.setupDirs(t)
   114  	fs.setupFiles(t)
   115  	fs.setupLinks(t)
   116  }
   117  
   118  func (fs filesystemState) setupDirs(t *testing.T) {
   119  	for _, dir := range fs.dirs {
   120  		p := dir.prepend(fs.root)
   121  		if err := os.MkdirAll(p.String(), 0777); err != nil {
   122  			t.Fatalf("os.MkdirAll(%q, 0777) err=%q", p, err)
   123  		}
   124  	}
   125  }
   126  
   127  func (fs filesystemState) setupFiles(t *testing.T) {
   128  	for _, file := range fs.files {
   129  		p := file.prepend(fs.root)
   130  		f, err := os.Create(p.String())
   131  		if err != nil {
   132  			t.Fatalf("os.Create(%q) err=%q", p, err)
   133  		}
   134  		if err := f.Close(); err != nil {
   135  			t.Fatalf("file %q Close() err=%q", p, err)
   136  		}
   137  	}
   138  }
   139  
   140  func (fs filesystemState) setupLinks(t *testing.T) {
   141  	for _, link := range fs.links {
   142  		p := link.path.prepend(fs.root)
   143  
   144  		// On Windows, relative symlinks confuse filepath.Walk. This is golang/go
   145  		// issue 17540. So, we'll just sigh and do absolute links, assuming they are
   146  		// relative to the directory of link.path.
   147  		dir := filepath.Dir(p.String())
   148  		to := filepath.Join(dir, link.to)
   149  
   150  		if err := os.Symlink(to, p.String()); err != nil {
   151  			t.Fatalf("os.Symlink(%q, %q) err=%q", to, p, err)
   152  		}
   153  	}
   154  }