Skip to content

Commit 89b23b0

Browse files
twpaynerogpeppe
authored andcommitted
testscript: add RequireUniqueNames parameter
Co-authored-by: Roger Peppe <[email protected]>
1 parent f98815c commit 89b23b0

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Check that RequireUniqueNames works;
2+
# it should reject txtar archives with duplicate names as defined by the host system.
3+
4+
unquote scripts-normalized/testscript.txt
5+
6+
testscript scripts-normalized
7+
! testscript -unique-names scripts-normalized
8+
stdout '.* would overwrite .* \(because RequireUniqueNames is enabled\)'
9+
10+
-- scripts-normalized/testscript.txt --
11+
>-- file --
12+
>-- dir/../file --

testscript/testscript.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"flag"
1515
"fmt"
1616
"go/build"
17+
"io/fs"
1718
"io/ioutil"
1819
"os"
1920
"os/exec"
@@ -174,6 +175,10 @@ type Params struct {
174175
// executions explicit.
175176
RequireExplicitExec bool
176177

178+
// RequireUniqueNames requires that names in the txtar archive are unique.
179+
// By default, later entries silently overwrite earlier ones.
180+
RequireUniqueNames bool
181+
177182
// ContinueOnError causes a testscript to try to continue in
178183
// the face of errors. Once an error has occurred, the script
179184
// will continue as if in verbose mode.
@@ -372,6 +377,22 @@ type backgroundCmd struct {
372377
neg bool // if true, cmd should fail
373378
}
374379

380+
func writeFile(name string, data []byte, perm fs.FileMode, excl bool) error {
381+
oflags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC
382+
if excl {
383+
oflags |= os.O_EXCL
384+
}
385+
f, err := os.OpenFile(name, oflags, perm)
386+
if err != nil {
387+
return err
388+
}
389+
defer f.Close()
390+
if _, err := f.Write(data); err != nil {
391+
return fmt.Errorf("cannot write file contents: %v", err)
392+
}
393+
return nil
394+
}
395+
375396
// setup sets up the test execution temporary directory and environment.
376397
// It returns the comment section of the txtar archive.
377398
func (ts *TestScript) setup() string {
@@ -433,7 +454,12 @@ func (ts *TestScript) setup() string {
433454
name := ts.MkAbs(ts.expand(f.Name))
434455
ts.scriptFiles[name] = f.Name
435456
ts.Check(os.MkdirAll(filepath.Dir(name), 0o777))
436-
ts.Check(ioutil.WriteFile(name, f.Data, 0o666))
457+
switch err := writeFile(name, f.Data, 0o666, ts.params.RequireUniqueNames); {
458+
case ts.params.RequireUniqueNames && errors.Is(err, fs.ErrExist):
459+
ts.Check(fmt.Errorf("%s would overwrite %s (because RequireUniqueNames is enabled)", f.Name, name))
460+
default:
461+
ts.Check(err)
462+
}
437463
}
438464
// Run any user-defined setup.
439465
if ts.params.Setup != nil {

testscript/testscript_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ func TestScripts(t *testing.T) {
213213
fset := flag.NewFlagSet("testscript", flag.ContinueOnError)
214214
fUpdate := fset.Bool("update", false, "update scripts when cmp fails")
215215
fExplicitExec := fset.Bool("explicit-exec", false, "require explicit use of exec for commands")
216+
fUniqueNames := fset.Bool("unique-names", false, "require unique names in txtar archive")
216217
fVerbose := fset.Bool("v", false, "be verbose with output")
217218
fContinue := fset.Bool("continue", false, "continue on error")
218219
if err := fset.Parse(args); err != nil {
@@ -229,6 +230,7 @@ func TestScripts(t *testing.T) {
229230
Dir: ts.MkAbs(dir),
230231
UpdateScripts: *fUpdate,
231232
RequireExplicitExec: *fExplicitExec,
233+
RequireUniqueNames: *fUniqueNames,
232234
Cmds: map[string]func(ts *TestScript, neg bool, args []string){
233235
"some-param-cmd": func(ts *TestScript, neg bool, args []string) {
234236
},

0 commit comments

Comments
 (0)