Test filesystem walks in memory¶
workspace never opens the real filesystem itself — it walks an
afero.Fs you hand it. In production that is
afero.NewOsFs(); in tests it is afero.NewMemMapFs(), so you can build an entire project
layout in memory and assert on the walk with no temp directories and no cleanup.
Build a layout and detect¶
func TestDetectsModuleRoot(t *testing.T) {
fs := afero.NewMemMapFs()
require.NoError(t, afero.WriteFile(fs, "/proj/go.mod", []byte("module x"), 0o644))
require.NoError(t, fs.MkdirAll("/proj/internal/pkg", 0o755))
ws, err := workspace.Detect(fs, "/proj/internal/pkg", workspace.DefaultMarkers)
require.NoError(t, err)
assert.Equal(t, "/proj", ws.Root)
assert.Equal(t, "go.mod", ws.Marker)
}
The marker is created two levels above the start directory; the walk climbs to it and reports the root and the marker that matched.
Assert the "not found" path¶
Because the memory filesystem contains only what you put there, the failure path is just as easy to exercise:
fs := afero.NewMemMapFs()
require.NoError(t, fs.MkdirAll("/nowhere/deep", 0o755))
_, err := workspace.Detect(fs, "/nowhere/deep", workspace.DefaultMarkers)
assert.ErrorIs(t, err, workspace.ErrNotFound)
Keep tests parallel-safe¶
An afero.NewMemMapFs() is independent per test, so detection tests can run with
t.Parallel() freely. DetectFromCWD reads the process working directory with
os.Getwd(), but the filesystem it queries is still the one you inject — a memory
filesystem seeded at that working directory keeps even the CWD variant hermetic:
cwd, _ := os.Getwd()
fs := afero.NewMemMapFs()
require.NoError(t, afero.WriteFile(fs, cwd+"/go.mod", []byte("module x"), 0o644))
ws, err := workspace.DetectFromCWD(fs, workspace.DefaultMarkers)
require.NoError(t, err)
assert.Equal(t, cwd, ws.Root)
Prefer Detect with an explicit start directory when you want a test that does not depend
on the working directory at all.