Help us shape the future of Go! Take the 2026 Go Developer Survey

treeguard

package
v0.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package treeguard fails a test binary that leaves a file behind in the directory it ran in.

`go test` runs a package's binary in that package's *source* directory, so a test that writes to a relative path writes into the checked-out tree. Nothing reports it: the write succeeds, the test passes, and the file sits there until a later `git add -A` commits it into a change that never meant to create it. That has happened twice in this repository with one file.

The guard is a before-and-after listing around the whole run. It cannot say which test wrote the file — the run is over by the time it looks — but naming the file is enough to find the writer, and turning a silent success into a failed package is the whole point: an unnoticed stray becomes a red build before it can reach anyone else's commit.

What it does *not* cover is a write outside the package directory. A test that needs a filesystem should take a directory from the framework, which takes it away again; this exists for the case where nobody remembered to.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run(m interface{ Run() int }) int

Run runs the package's tests and returns the status the binary should exit with. A package guards itself with

func TestMain(m *testing.M) { os.Exit(treeguard.Run(m)) }

and the status is m.Run's unless the run left something behind, in which case a passing package still fails.

The parameter is the one method *testing.M offers here rather than the type itself, so this package's own tests can hand it a run that leaves a file — which is the case that matters and the one a real *testing.M cannot be asked to perform.

func Temp

func Temp(m interface{ Run() int }) interface{ Run() int }

Temp gives a run a temporary directory of its own and fails it if anything is left there. A package guards itself with

func TestMain(m *testing.M) { os.Exit(treeguard.Temp(m).Run()) }

and composes it with the other wrappers the way childguard.Wrap composes.

Why this is not Run with a different directory

Run counts *files*, and says so: a directory a test makes and empties again has left nothing behind, and reporting it would make the guard cry wolf in a source tree where git does not record an empty directory anyway.

The leak this is for is an empty directory and nothing else. A process substitution makes one under the shell's TMPDIR to hold its named pipes; the pipes go as soon as the command that named them ends, and for a long time nothing removed what was left. 10,585 accumulated in /tmp in one working session and 4,188 more in the two days after they were swept by hand (#1284). Run, pointed at TMPDIR, would have reported none of them — which is the point worth writing down: the guard that was already here could not have caught this, so the answer was to teach it the case rather than to leave a second guard somewhere else that knows one thing this one does not.

So an entry of any kind counts here, and a directory is named rather than descended into: what is inside a stray is the writer's business, and the report wants one line per thing left behind.

What it covers

A whole run, not a test. It cannot say which test leaked — the run is over by the time it looks — but a package that starts shells is a small enough haystack, and turning a silent success into a failed package is the whole point. The suites that start shells are where a leak reaches a *binary*: interp's own tests each hand their Runner a TMPDIR the framework takes away again, so a leak there is invisible, and a leak in a shipped shell is permanent.

A run killed by a signal leaves the scratch directory behind, and a SIGKILLed one cannot do otherwise. That is the same hole every cleanup has and it is not worth pretending about.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL