Go

Explain io/fs and fs.FS. How do you walk a directory with filepath.WalkDir and test file-system code with testing/fstest.MapFS?

Question 542MediumGo 1.22 to 1.25

fs.FS (Go 1.16) is a minimal read-only interface: Open(name string) (fs.File, error). Optional interfaces add capabilities: ReadDirFS, ReadFileFS, StatFS, SubFS and GlobFS. The helpers fs.ReadFile, fs.WalkDir and similar use them when present. Implementations include os.DirFS, embed.FS, zip.Reader, os.Root.FS() and fstest.MapFS. Paths are always slash-separated, unrooted, with no .. (fs.ValidPath), even on Windows. filepath.WalkDir walks OS paths, and fs.WalkDir walks any fs.FS. Both are faster than the old filepath.Walk because they pass a DirEntry instead of calling Lstat on every file.

func countGo(fsys fs.FS) (int, error) {
	n := 0
	err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err // d may be nil when the root itself fails
		}
		if d.IsDir() && d.Name() == "vendor" {
			return fs.SkipDir // fs.SkipAll (Go 1.20) stops the whole walk
		}
		if !d.IsDir() && strings.HasSuffix(path, ".go") {
			n++
		}
		return nil
	})
	return n, err
}

// production: countGo(os.DirFS("/src"))

func TestCountGo(t *testing.T) {
	fsys := fstest.MapFS{
		"main.go":       {Data: []byte("package main")},
		"pkg/a.go":      {Data: []byte("package pkg")},
		"vendor/x/b.go": {}, // parent dirs are synthesized
		"README.md":     {},
	}
	n, err := countGo(fsys)
	if err != nil || n != 2 {
		t.Fatalf("got %d, %v; want 2", n, err)
	}
}

What the interviewer is looking for: depend on fs.FS instead of calling os directly, so the code can be tested without temp dirs. fstest.TestFS checks that your own FS implementation follows the contract. fs.FS is read-only, so writes still need os or your own interface.

More on More Standard Library Essentials

All 16 More Standard Library Essentials questions