testmark-go

testexec: will now create tmpdirs and files for you if you have an 'fs' entry tree.

commit 80687ba163dfc22ef8b05f2df86ac94fa3cfcd9a · parent 14b6f0f554 · browse this tree
Eric Myhre, 2021-09-30 23:51:15 UTC

diff --git a/testexec/testexec.go b/testexec/testexec.go
index 976753a..88bbd04 100644
--- a/testexec/testexec.go
+++ b/testexec/testexec.go
@@ -11,6 +11,9 @@ package testexec
 import (
 	"bytes"
 	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
 	"strconv"
 	"strings"
 	"testing"
@@ -105,6 +108,12 @@ func (tcfg *Tester) init() {
 // and nothing about their stdout nor stderr will be checked.
 // (If you want to mandate that their output is empty, you must create a blank data block to say so explicitly.)
 //
+// Additionally, the commands can be run within a temp directory, with some files pre-populated,
+// by use of data hunks under the "fs/" name.  So, "fs/foo.bar" will result in a file named "foo.bar" in the temp directory.
+// The temp directory is applied by using `os.Chdir`, and so is not safe for use with concurrent tests.
+// There are no special faculties for making empty directories, symlinks, setting file properties, etc;
+// if you need to do anything fancy, a setup script may be a good direction to pursue.
+//
 // If you wish to run some commands, and gather and test (or ignore!) their output as one block,
 // then run additional commands in a subtest, you can use another special path name
 // in the testmark.DirEnt for that: `then-(.*)`.
@@ -166,6 +175,29 @@ func (tcfg Tester) test(t *testing.T, data testmark.DirEnt, allowExec, allowScri
 		t.Skipf("nothing to do if requested to regenerate test fixtures but have nowhere to put data")
 	}
 
+	// Create a tempdir, and fill it with any files.
+	if fsEnt, exists := data.Children["fs"]; exists {
+		// Create and get into a tempdir.
+		dir, err := ioutil.TempDir("", "testmarkexec")
+		if err != nil {
+			t.Errorf("test aborted: could not create tempdir: %s", err)
+		}
+		defer os.RemoveAll(dir)
+		retreat, err := os.Getwd()
+		if err != nil {
+			t.Errorf("test aborted: could not find cwd: %s", err)
+		}
+		defer os.Chdir(retreat)
+		if err := os.Chdir(dir); err != nil {
+			t.Errorf("test aborted: could not chdir to tempdir: %s", err)
+		}
+
+		// Create files.
+		if err := createFiles(fsEnt, "."); err != nil {
+			t.Errorf("test aborted: could not populate files to tempdir: %s", err)
+		}
+	}
+
 	// Prepare output buffers.
 	var stdout, stderr io.Writer
 	if _, exists := data.Children["output"]; exists {
@@ -271,3 +303,21 @@ func (tcfg Tester) doScript(t *testing.T, hunk *testmark.Hunk, stdout, stderr io
 	}
 	return
 }
+
+// createFiles makes files and directories matching testmark hunks.
+// It creates them relative to the os cwd plus prefix -- use with care.
+func createFiles(dir *testmark.DirEnt, prefix string) error {
+	if dir.Hunk != nil {
+		return ioutil.WriteFile(prefix, dir.Hunk.Body, 0644)
+	} else {
+		if err := os.MkdirAll(prefix, 0755); err != nil {
+			return err
+		}
+	}
+	for _, ent := range dir.Children {
+		if err := createFiles(ent, filepath.Join(prefix, ent.Name)); err != nil {
+			return err
+		}
+	}
+	return nil
+}