diff --git a/testscript/doc.go b/testscript/doc.go index f47a7d98..8ad2272b 100644 --- a/testscript/doc.go +++ b/testscript/doc.go @@ -121,6 +121,33 @@ A condition can be negated: [!short] means to run the rest of the line when testing.Short() is false. Additional conditions can be added by passing a function to Params.Condition. +The function will only be called when all built-in conditions have been checked for. + +An example: + Condition: func(cond string) (bool, error) { + // Assume condition name and args are separated by colon (":") + args := strings.Split(cond, ":") + name := args[0] + switch name { + case "exists": + if len(args) < 2 { + return false, fmt.Errorf("syntax: [exists:file_name]") + } + _, err := os.Stat(args[1]) + return !errors.Is(err, fs.ErrNotExist), nil + case "long": + return os.Getenv("TEST_LONG") != "", nil + default: + return false, fmt.Errorf("unrecognized condition %s", name) + } + }, + +With the conditions so defined, you can use them as follows: + env file_name=/path/to/filename + [exists:$file_name] exec echo 'file was found' + env loops=1 + [long] env loops=3 + exec do_something $loops The predefined commands are: diff --git a/testscript/testdata/custom_conditions.txt b/testscript/testdata/custom_conditions.txt new file mode 100644 index 00000000..8c1018f3 --- /dev/null +++ b/testscript/testdata/custom_conditions.txt @@ -0,0 +1,67 @@ +[!exec:echo] skip + +env upper_word=ABCD +env lower_word=abcd + +[always_true] exec echo 'this is true' +stdout 'this is true' + +exec echo '' + +[!always_true] exec echo 'this is true' +! stdout . + +exec echo '' + +[always_false] exec echo 'this is false' +! stdout . + +exec echo '' + +[!always_false] exec echo 'this is false' +stdout 'this is false' + +exec echo '' + +[is_upper:ABCD] exec echo 'it is upper' +stdout 'it is upper' + +exec echo '' + +[is_upper:$upper_word] exec echo 'it is again upper' +stdout 'it is again upper' + +exec echo '' + +[is_upper:abcd] exec echo 'it is upper' +! stdout . + +exec echo '' + +[is_upper:$lower_word] exec echo 'it is lower' +! stdout . + +exec echo '' + +[!is_upper:ABCD] exec echo 'it is upper' +! stdout . + +exec echo '' + +[is_lower:abcd] exec echo 'it is lower' +stdout 'it is lower' + +exec echo '' + +[is_lower:$lower_word] exec echo 'it is again lower' +stdout 'it is again lower' + +exec echo '' + +[is_lower:ABCD] exec echo 'it is lower' +! stdout . + +exec echo '' + +[!is_lower:$lower_word] exec echo 'it is lower' +! stdout . diff --git a/testscript/testdata/custom_conditions_errors.txt b/testscript/testdata/custom_conditions_errors.txt new file mode 100644 index 00000000..65301bde --- /dev/null +++ b/testscript/testdata/custom_conditions_errors.txt @@ -0,0 +1,72 @@ +env GOPATH=$WORK +env GOCACHE=$WORK/.cache + +[!exec:echo] skip +cd cond_errors +exec go mod tidy +! exec go test -run TestConditionErrors/is_upper-no-parameter +stdout 'FAIL' +stdout 'syntax: \[is_upper:word\]' + +! exec go test -run TestConditionErrors/is_lower-no-parameter +stdout 'FAIL' +stdout 'syntax: \[is_lower:word\]' + +! exec go test -run TestConditionErrors/unrecognized +stdout 'FAIL' +stdout 'unrecognized condition something' + +-- cond_errors/main_test.go -- +package condition_errors + +import ( + "fmt" + "strings" + "testing" + + "github.com/rogpeppe/go-internal/testscript" +) + +func TestConditionErrors(t *testing.T) { + testscript.Run(t, testscript.Params{ + Dir: "testdata", + Condition: func(cond string) (bool, error) { + // Assume condition name and args are separated by colon (":") + args := strings.Split(cond, ":") + name := args[0] + switch name { + case "is_upper": + if len(args) < 2 { + return false, fmt.Errorf("syntax: [is_upper:word]") + } + return strings.ToUpper(args[1]) == args[1], nil + case "is_lower": + if len(args) < 2 { + return false, fmt.Errorf("syntax: [is_lower:word]") + } + return strings.ToLower(args[1]) == args[1], nil + case "always_true": + return true, nil + case "always_false": + return false, nil + default: + return false, fmt.Errorf("unrecognized condition %s", name) + } + }, + }) +} +-- cond_errors/go.mod -- +module condition_errors + +go 1.18 + +require ( + github.com/rogpeppe/go-internal v1.9.0 +) + +-- cond_errors/testdata/is_upper-no-parameter.txt -- +[is_upper] exec echo '' +-- cond_errors/testdata/is_lower-no-parameter.txt -- +[is_lower] exec echo '' +-- cond_errors/testdata/unrecognized.txt -- +[something] exec echo '' diff --git a/testscript/testscript_test.go b/testscript/testscript_test.go index 5bf42cde..f9e4d597 100644 --- a/testscript/testscript_test.go +++ b/testscript/testscript_test.go @@ -254,6 +254,29 @@ func TestScripts(t *testing.T) { }, "echoandexit": echoandexit, }, + Condition: func(cond string) (bool, error) { + // Assume condition name and args are separated by colon (":") + args := strings.Split(cond, ":") + name := args[0] + switch name { + case "is_upper": + if len(args) < 2 { + return false, fmt.Errorf("syntax: [is_upper:word]") + } + return strings.ToUpper(args[1]) == args[1], nil + case "is_lower": + if len(args) < 2 { + return false, fmt.Errorf("syntax: [is_lower:word]") + } + return strings.ToLower(args[1]) == args[1], nil + case "always_true": + return true, nil + case "always_false": + return false, nil + default: + return false, fmt.Errorf("unrecognized condition %s", name) + } + }, Setup: func(env *Env) error { infos, err := ioutil.ReadDir(env.WorkDir) if err != nil {