Skip to content

Commit

Permalink
skip: deprecate skip.If and replace it with assert.SkipIf
Browse files Browse the repository at this point in the history
Instead of a very small page it should be fine to move this one exported function to
the assert package.
  • Loading branch information
dnephin committed Apr 16, 2022
1 parent dbe78a8 commit d2fbfd7
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 70 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ module paths pin to version `v2.3.0`.
execute binaries and test the output
* [poll](http://pkg.go.dev/gotest.tools/v3/poll) -
test asynchronous code by polling until a desired state is reached
* [skip](http://pkg.go.dev/gotest.tools/v3/skip) -
skip a test and print the source code of the condition used to skip the test

## Related

Expand Down
8 changes: 7 additions & 1 deletion assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ import (
"gotest.tools/v3/internal/assert"
)

// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
// BoolOrComparison can be a bool, cmp.Comparison, or error. See Assert for
// details about how this type is used.
type BoolOrComparison interface{}

// TestingT is the subset of testing.T used by the assert package.
Expand Down Expand Up @@ -120,6 +121,11 @@ type helperT interface {
// A nil value is considered success, and a non-nil error is a failure.
// The return value of error.Error is used as the failure message.
//
//
// Extra details can be added to the failure message using msgAndArgs. msgAndArgs
// may be either a single string, or a format string and args that will be
// passed to fmt.Sprintf.
//
// Assert uses t.FailNow to fail the test. Like t.FailNow, Assert must be called
// from the goroutine running the test function, not from other
// goroutines created during the test. Use Check from other goroutines.
Expand Down
104 changes: 104 additions & 0 deletions assert/skip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package assert

import (
"fmt"
"path"
"reflect"
"runtime"
"strings"

"gotest.tools/v3/internal/format"
"gotest.tools/v3/internal/source"
)

// SkipT is the interface accepted by SkipIf to skip tests. It is implemented by
// testing.T, and testing.B.
type SkipT interface {
Skip(args ...interface{})
Log(args ...interface{})
}

// SkipResult may be returned by a function used with SkipIf to provide a
// detailed message to use as part of the skip message.
type SkipResult interface {
Skip() bool
Message() string
}

// BoolOrCheckFunc can be a bool, func() bool, or func() SkipResult. Other
// types will panic. See SkipIf for details about how this type is used.
type BoolOrCheckFunc interface{}

// SkipIf skips the test if the condition evaluates to true. If the condition
// evaluates to false then SkipIf does nothing. SkipIf is a convenient way of
// skipping tests and using the literal source of the condition as the text of
// the skip message.
//
// For example, this usage would produce the following skip message:
//
// assert.SkipIf(t, runtime.GOOS == "windows", "not supported")
// // filename.go:11: runtime.GOOS == "windows": not supported
//
// The condition argument may be one of the following:
//
// bool
// The test will be skipped if the value is true. The literal source of the
// expression passed to SkipIf will be used as the skip message.
//
// func() bool
// The test will be skipped if the function returns true. The name of the
// function will be used as the skip message.
//
// func() SkipResult
// The test will be skipped if SkipResult.Skip return true. Both the name
// of the function and the return value of SkipResult.Message will be used
// as the skip message.
//
// Extra details can be added to the skip message using msgAndArgs. msgAndArgs
// may be either a single string, or a format string and args that will be
// passed to fmt.Sprintf.
func SkipIf(t SkipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
switch check := condition.(type) {
case bool:
ifCondition(t, check, msgAndArgs...)
case func() bool:
if check() {
t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...))
}
case func() SkipResult:
result := check()
if result.Skip() {
msg := getFunctionName(check) + ": " + result.Message()
t.Skip(format.WithCustomMessage(msg, msgAndArgs...))
}
default:
panic(fmt.Sprintf("invalid type for condition arg: %T", check))
}
}

func getFunctionName(function interface{}) string {
funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
return strings.SplitN(path.Base(funcPath), ".", 2)[1]
}

func ifCondition(t SkipT, condition bool, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
if !condition {
return
}
const (
stackIndex = 2
argPos = 1
)
source, err := source.FormattedCallExprArg(stackIndex, argPos)
if err != nil {
t.Log(err.Error())
t.Skip(format.Message(msgAndArgs...))
}
t.Skip(format.WithCustomMessage(source, msgAndArgs...))
}
39 changes: 39 additions & 0 deletions assert/skip_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package assert_test

import (
"gotest.tools/v3/assert"
)

var apiVersion = ""

type env struct{}

func (e env) hasFeature(_ string) bool { return false }

var testEnv = env{}

func MissingFeature() bool { return false }

func ExampleSkipIf() {
assert.SkipIf(t, MissingFeature)
// --- SKIP: TestName (0.00s)
// skip.go:18: MissingFeature

assert.SkipIf(t, MissingFeature, "coming soon")
// --- SKIP: TestName (0.00s)
// skip.go:22: MissingFeature: coming soon
}

func ExampleSkipIf_withExpression() {
assert.SkipIf(t, apiVersion < version("v1.24"))
// --- SKIP: TestName (0.00s)
// skip.go:28: apiVersion < version("v1.24")

assert.SkipIf(t, !testEnv.hasFeature("build"), "coming soon")
// --- SKIP: TestName (0.00s)
// skip.go:32: !textenv.hasFeature("build"): coming soon
}

func version(v string) string {
return v
}
135 changes: 135 additions & 0 deletions assert/skip_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package assert

import (
"bytes"
"fmt"
"testing"

"gotest.tools/v3/assert/cmp"
)

type fakeSkipT struct {
reason string
logs []string
}

func (f *fakeSkipT) Skip(args ...interface{}) {
buf := new(bytes.Buffer)
for _, arg := range args {
buf.WriteString(fmt.Sprintf("%s", arg))
}
f.reason = buf.String()
}

func (f *fakeSkipT) Log(args ...interface{}) {
f.logs = append(f.logs, fmt.Sprintf("%s", args[0]))
}

func (f *fakeSkipT) Helper() {}

func version(v string) string {
return v
}

func TestSkipIFCondition(t *testing.T) {
skipT := &fakeSkipT{}
apiVersion := "v1.4"
SkipIf(skipT, apiVersion < version("v1.6"))

Equal(t, `apiVersion < version("v1.6")`, skipT.reason)
Assert(t, cmp.Len(skipT.logs, 0))
}

func TestSkipIfConditionWithMessage(t *testing.T) {
skipT := &fakeSkipT{}
apiVersion := "v1.4"
SkipIf(skipT, apiVersion < "v1.6", "see notes")

Equal(t, `apiVersion < "v1.6": see notes`, skipT.reason)
Assert(t, cmp.Len(skipT.logs, 0))
}

func TestSkipIfConditionMultiline(t *testing.T) {
skipT := &fakeSkipT{}
apiVersion := "v1.4"
SkipIf(
skipT,
apiVersion < "v1.6")

Equal(t, `apiVersion < "v1.6"`, skipT.reason)
Assert(t, cmp.Len(skipT.logs, 0))
}

func TestSkipIfConditionMultilineWithMessage(t *testing.T) {
skipT := &fakeSkipT{}
apiVersion := "v1.4"
SkipIf(
skipT,
apiVersion < "v1.6",
"see notes")

Equal(t, `apiVersion < "v1.6": see notes`, skipT.reason)
Assert(t, cmp.Len(skipT.logs, 0))
}

func TestSkipIfConditionNoSkip(t *testing.T) {
skipT := &fakeSkipT{}
SkipIf(skipT, false)

Equal(t, "", skipT.reason)
Assert(t, cmp.Len(skipT.logs, 0))
}

func SkipBecauseISaidSo() bool {
return true
}

func TestSkipIf(t *testing.T) {
skipT := &fakeSkipT{}
SkipIf(skipT, SkipBecauseISaidSo)

Equal(t, "SkipBecauseISaidSo", skipT.reason)
}

func TestSkipIfWithMessage(t *testing.T) {
skipT := &fakeSkipT{}
SkipIf(skipT, SkipBecauseISaidSo, "see notes")

Equal(t, "SkipBecauseISaidSo: see notes", skipT.reason)
}

func TestSkipIf_InvalidCondition(t *testing.T) {
skipT := &fakeSkipT{}
Assert(t, cmp.Panics(func() {
SkipIf(skipT, "just a string")
}))
}

func TestSkipIfWithSkipResultFunc(t *testing.T) {
t.Run("no extra message", func(t *testing.T) {
skipT := &fakeSkipT{}
SkipIf(skipT, alwaysSkipWithMessage)

Equal(t, "alwaysSkipWithMessage: skip because I said so!", skipT.reason)
})
t.Run("with extra message", func(t *testing.T) {
skipT := &fakeSkipT{}
SkipIf(skipT, alwaysSkipWithMessage, "also %v", 4)

Equal(t, "alwaysSkipWithMessage: skip because I said so!: also 4", skipT.reason)
})
}

func alwaysSkipWithMessage() SkipResult {
return skipResult{}
}

type skipResult struct{}

func (s skipResult) Skip() bool {
return true
}

func (s skipResult) Message() string {
return "skip because I said so!"
}
11 changes: 5 additions & 6 deletions env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
"gotest.tools/v3/internal/source"
"gotest.tools/v3/skip"
)

func TestPatchFromUnset(t *testing.T) {
Expand All @@ -23,7 +22,7 @@ func TestPatchFromUnset(t *testing.T) {
}

func TestPatch(t *testing.T) {
skip.If(t, os.Getenv("PATH") == "")
assert.SkipIf(t, os.Getenv("PATH") == "")
oldVal := os.Getenv("PATH")

key, value := "PATH", "NEWVALUE"
Expand All @@ -35,7 +34,7 @@ func TestPatch(t *testing.T) {
}

func TestPatch_IntegrationWithCleanup(t *testing.T) {
skip.If(t, source.GoVersionLessThan(1, 14))
assert.SkipIf(t, source.GoVersionLessThan(1, 14))

key := "totally_unique_env_var_key"
t.Run("cleanup in subtest", func(t *testing.T) {
Expand Down Expand Up @@ -67,7 +66,7 @@ func TestPatchAll(t *testing.T) {
}

func TestPatchAllWindows(t *testing.T) {
skip.If(t, runtime.GOOS != "windows")
assert.SkipIf(t, runtime.GOOS != "windows")
oldEnv := os.Environ()
newEnv := map[string]string{
"FIRST": "STARS",
Expand All @@ -92,7 +91,7 @@ func sorted(source []string) []string {
}

func TestPatchAll_IntegrationWithCleanup(t *testing.T) {
skip.If(t, source.GoVersionLessThan(1, 14))
assert.SkipIf(t, source.GoVersionLessThan(1, 14))

key := "totally_unique_env_var_key"
t.Run("cleanup in subtest", func(t *testing.T) {
Expand Down Expand Up @@ -145,7 +144,7 @@ func TestChangeWorkingDir(t *testing.T) {
}

func TestChangeWorkingDir_IntegrationWithCleanup(t *testing.T) {
skip.If(t, source.GoVersionLessThan(1, 14))
assert.SkipIf(t, source.GoVersionLessThan(1, 14))

tmpDir := fs.NewDir(t, t.Name())
defer tmpDir.Remove()
Expand Down
5 changes: 2 additions & 3 deletions fs/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"gotest.tools/v3/assert"
"gotest.tools/v3/fs"
"gotest.tools/v3/internal/source"
"gotest.tools/v3/skip"
)

func TestNewDirWithOpsAndManifestEqual(t *testing.T) {
Expand Down Expand Up @@ -67,7 +66,7 @@ func TestNewFile(t *testing.T) {
}

func TestNewFile_IntegrationWithCleanup(t *testing.T) {
skip.If(t, source.GoVersionLessThan(1, 14))
assert.SkipIf(t, source.GoVersionLessThan(1, 14))
var tmpFile *fs.File
t.Run("cleanup in subtest", func(t *testing.T) {
tmpFile = fs.NewFile(t, t.Name())
Expand All @@ -82,7 +81,7 @@ func TestNewFile_IntegrationWithCleanup(t *testing.T) {
}

func TestNewDir_IntegrationWithCleanup(t *testing.T) {
skip.If(t, source.GoVersionLessThan(1, 14))
assert.SkipIf(t, source.GoVersionLessThan(1, 14))
var tmpFile *fs.Dir
t.Run("cleanup in subtest", func(t *testing.T) {
tmpFile = fs.NewDir(t, t.Name())
Expand Down
Loading

0 comments on commit d2fbfd7

Please sign in to comment.