| // Copyright 2017 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package gps | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"os" | 
 | 	"path/filepath" | 
 | 	"reflect" | 
 | 	"testing" | 
 |  | 
 | 	"github.com/golang/dep/internal/test" | 
 | ) | 
 |  | 
 | // This file contains utilities for running tests around file system state. | 
 |  | 
 | type fsTestCase struct { | 
 | 	before, after filesystemState | 
 | } | 
 |  | 
 | // assert makes sure that the tc.after state matches the state of the actual host | 
 | // file system at tc.after.root. | 
 | func (tc fsTestCase) assert(t *testing.T) { | 
 | 	dirMap := make(map[string]bool) | 
 | 	fileMap := make(map[string]bool) | 
 | 	linkMap := make(map[string]bool) | 
 |  | 
 | 	for _, d := range tc.after.dirs { | 
 | 		dirMap[filepath.Join(tc.after.root, d)] = true | 
 | 	} | 
 | 	for _, f := range tc.after.files { | 
 | 		fileMap[filepath.Join(tc.after.root, f)] = true | 
 | 	} | 
 | 	for _, l := range tc.after.links { | 
 | 		linkMap[filepath.Join(tc.after.root, l.path)] = true | 
 | 	} | 
 |  | 
 | 	err := filepath.Walk(tc.after.root, func(path string, info os.FileInfo, err error) error { | 
 | 		if err != nil { | 
 | 			t.Errorf("filepath.Walk path=%q  err=%q", path, err) | 
 | 			return err | 
 | 		} | 
 |  | 
 | 		if path == tc.after.root { | 
 | 			return nil | 
 | 		} | 
 |  | 
 | 		// Careful! Have to check whether the path is a symlink first because, on | 
 | 		// windows, a symlink to a directory will return 'true' for info.IsDir(). | 
 | 		if (info.Mode() & os.ModeSymlink) != 0 { | 
 | 			if linkMap[path] { | 
 | 				delete(linkMap, path) | 
 | 			} else { | 
 | 				t.Errorf("unexpected symlink exists %q", path) | 
 | 			} | 
 | 			return nil | 
 | 		} | 
 |  | 
 | 		if info.IsDir() { | 
 | 			if dirMap[path] { | 
 | 				delete(dirMap, path) | 
 | 			} else { | 
 | 				t.Errorf("unexpected directory exists %q", path) | 
 | 			} | 
 | 			return nil | 
 | 		} | 
 |  | 
 | 		if fileMap[path] { | 
 | 			delete(fileMap, path) | 
 | 		} else { | 
 | 			t.Errorf("unexpected file exists %q", path) | 
 | 		} | 
 | 		return nil | 
 | 	}) | 
 |  | 
 | 	if err != nil { | 
 | 		t.Errorf("filesystem.Walk err=%q", err) | 
 | 	} | 
 |  | 
 | 	for d := range dirMap { | 
 | 		t.Errorf("could not find expected directory %q", d) | 
 | 	} | 
 | 	for f := range fileMap { | 
 | 		t.Errorf("could not find expected file %q", f) | 
 | 	} | 
 | 	for l := range linkMap { | 
 | 		t.Errorf("could not find expected symlink %q", l) | 
 | 	} | 
 | } | 
 |  | 
 | // setup inflates fs onto the actual host file system at tc.before.root. | 
 | // It doesn't delete existing files and should be used on empty roots only. | 
 | func (tc fsTestCase) setup(t *testing.T) { | 
 | 	if err := tc.before.setup(); err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | } | 
 |  | 
 | func TestDeriveFilesystemState(t *testing.T) { | 
 | 	testcases := []struct { | 
 | 		name string | 
 | 		fs   fsTestCase | 
 | 	}{ | 
 | 		{ | 
 | 			name: "simple-case", | 
 | 			fs: fsTestCase{ | 
 | 				before: filesystemState{ | 
 | 					dirs: []string{ | 
 | 						"simple-dir", | 
 | 					}, | 
 | 					files: []string{ | 
 | 						"simple-file", | 
 | 					}, | 
 | 				}, | 
 | 				after: filesystemState{ | 
 | 					dirs: []string{ | 
 | 						"simple-dir", | 
 | 					}, | 
 | 					files: []string{ | 
 | 						"simple-file", | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "simple-symlink-case", | 
 | 			fs: fsTestCase{ | 
 | 				before: filesystemState{ | 
 | 					dirs: []string{ | 
 | 						"simple-dir", | 
 | 					}, | 
 | 					files: []string{ | 
 | 						"simple-file", | 
 | 					}, | 
 | 					links: []fsLink{ | 
 | 						{ | 
 | 							path:   "link", | 
 | 							to:     "nonexisting", | 
 | 							broken: true, | 
 | 						}, | 
 | 					}, | 
 | 				}, | 
 | 				after: filesystemState{ | 
 | 					dirs: []string{ | 
 | 						"simple-dir", | 
 | 					}, | 
 | 					files: []string{ | 
 | 						"simple-file", | 
 | 					}, | 
 | 					links: []fsLink{ | 
 | 						{ | 
 | 							path:   "link", | 
 | 							to:     "", | 
 | 							broken: true, | 
 | 						}, | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 		{ | 
 | 			name: "complex-symlink-case", | 
 | 			fs: fsTestCase{ | 
 | 				before: filesystemState{ | 
 | 					links: []fsLink{ | 
 | 						{ | 
 | 							path:     "link1", | 
 | 							to:       "link2", | 
 | 							circular: true, | 
 | 						}, | 
 | 						{ | 
 | 							path:     "link2", | 
 | 							to:       "link1", | 
 | 							circular: true, | 
 | 						}, | 
 | 					}, | 
 | 				}, | 
 | 				after: filesystemState{ | 
 | 					links: []fsLink{ | 
 | 						{ | 
 | 							path:     "link1", | 
 | 							to:       "", | 
 | 							circular: true, | 
 | 						}, | 
 | 						{ | 
 | 							path:     "link2", | 
 | 							to:       "", | 
 | 							circular: true, | 
 | 						}, | 
 | 					}, | 
 | 				}, | 
 | 			}, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, tc := range testcases { | 
 | 		h := test.NewHelper(t) | 
 |  | 
 | 		h.TempDir(tc.name) | 
 |  | 
 | 		tc.fs.before.root = h.Path(tc.name) | 
 | 		tc.fs.after.root = h.Path(tc.name) | 
 |  | 
 | 		tc.fs.setup(t) | 
 |  | 
 | 		state, err := deriveFilesystemState(h.Path(tc.name)) | 
 | 		if err != nil { | 
 | 			t.Fatal(err) | 
 | 		} | 
 |  | 
 | 		if !reflect.DeepEqual(tc.fs.after, state) { | 
 | 			fmt.Println(tc.fs.after) | 
 | 			fmt.Println(state) | 
 | 			t.Fatal("filesystem state mismatch") | 
 | 		} | 
 |  | 
 | 		h.Cleanup() | 
 | 	} | 
 | } |