Skip to content

Commit

Permalink
testscript: add RequireUniqueNames parameter
Browse files Browse the repository at this point in the history
Co-authored-by: Roger Peppe <rogpeppe@gmail.com>
  • Loading branch information
2 people authored and mvdan committed Jan 18, 2023
1 parent f98815c commit 89b23b0
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 1 deletion.
12 changes: 12 additions & 0 deletions testscript/testdata/testscript_duplicate_name.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Check that RequireUniqueNames works;
# it should reject txtar archives with duplicate names as defined by the host system.

unquote scripts-normalized/testscript.txt

testscript scripts-normalized
! testscript -unique-names scripts-normalized
stdout '.* would overwrite .* \(because RequireUniqueNames is enabled\)'

-- scripts-normalized/testscript.txt --
>-- file --
>-- dir/../file --
28 changes: 27 additions & 1 deletion testscript/testscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"flag"
"fmt"
"go/build"
"io/fs"
"io/ioutil"
"os"
"os/exec"
Expand Down Expand Up @@ -174,6 +175,10 @@ type Params struct {
// executions explicit.
RequireExplicitExec bool

// RequireUniqueNames requires that names in the txtar archive are unique.
// By default, later entries silently overwrite earlier ones.
RequireUniqueNames bool

// ContinueOnError causes a testscript to try to continue in
// the face of errors. Once an error has occurred, the script
// will continue as if in verbose mode.
Expand Down Expand Up @@ -372,6 +377,22 @@ type backgroundCmd struct {
neg bool // if true, cmd should fail
}

func writeFile(name string, data []byte, perm fs.FileMode, excl bool) error {
oflags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
if excl {
oflags |= os.O_EXCL
}
f, err := os.OpenFile(name, oflags, perm)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Write(data); err != nil {
return fmt.Errorf("cannot write file contents: %v", err)
}
return nil
}

// setup sets up the test execution temporary directory and environment.
// It returns the comment section of the txtar archive.
func (ts *TestScript) setup() string {
Expand Down Expand Up @@ -433,7 +454,12 @@ func (ts *TestScript) setup() string {
name := ts.MkAbs(ts.expand(f.Name))
ts.scriptFiles[name] = f.Name
ts.Check(os.MkdirAll(filepath.Dir(name), 0o777))
ts.Check(ioutil.WriteFile(name, f.Data, 0o666))
switch err := writeFile(name, f.Data, 0o666, ts.params.RequireUniqueNames); {
case ts.params.RequireUniqueNames && errors.Is(err, fs.ErrExist):
ts.Check(fmt.Errorf("%s would overwrite %s (because RequireUniqueNames is enabled)", f.Name, name))
default:
ts.Check(err)
}
}
// Run any user-defined setup.
if ts.params.Setup != nil {
Expand Down
2 changes: 2 additions & 0 deletions testscript/testscript_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func TestScripts(t *testing.T) {
fset := flag.NewFlagSet("testscript", flag.ContinueOnError)
fUpdate := fset.Bool("update", false, "update scripts when cmp fails")
fExplicitExec := fset.Bool("explicit-exec", false, "require explicit use of exec for commands")
fUniqueNames := fset.Bool("unique-names", false, "require unique names in txtar archive")
fVerbose := fset.Bool("v", false, "be verbose with output")
fContinue := fset.Bool("continue", false, "continue on error")
if err := fset.Parse(args); err != nil {
Expand All @@ -229,6 +230,7 @@ func TestScripts(t *testing.T) {
Dir: ts.MkAbs(dir),
UpdateScripts: *fUpdate,
RequireExplicitExec: *fExplicitExec,
RequireUniqueNames: *fUniqueNames,
Cmds: map[string]func(ts *TestScript, neg bool, args []string){
"some-param-cmd": func(ts *TestScript, neg bool, args []string) {
},
Expand Down

0 comments on commit 89b23b0

Please sign in to comment.