1/*Package skip provides functions for skipping a test and printing the source code
2of the condition used to skip the test.
3*/
4package skip // import "gotest.tools/skip"
5
6import (
7	"fmt"
8	"path"
9	"reflect"
10	"runtime"
11	"strings"
12
13	"gotest.tools/internal/format"
14	"gotest.tools/internal/source"
15)
16
17type skipT interface {
18	Skip(args ...interface{})
19	Log(args ...interface{})
20}
21
22type helperT interface {
23	Helper()
24}
25
26// BoolOrCheckFunc can be a bool or func() bool, other types will panic
27type BoolOrCheckFunc interface{}
28
29// If the condition expression evaluates to true, or the condition function returns
30// true, skip the test.
31// The skip message will contain the source code of the expression.
32// Extra message text can be passed as a format string with args
33func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
34	if ht, ok := t.(helperT); ok {
35		ht.Helper()
36	}
37	switch check := condition.(type) {
38	case bool:
39		ifCondition(t, check, msgAndArgs...)
40	case func() bool:
41		if check() {
42			t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...))
43		}
44	default:
45		panic(fmt.Sprintf("invalid type for condition arg: %T", check))
46	}
47}
48
49func getFunctionName(function func() bool) string {
50	funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
51	return strings.SplitN(path.Base(funcPath), ".", 2)[1]
52}
53
54func ifCondition(t skipT, condition bool, msgAndArgs ...interface{}) {
55	if ht, ok := t.(helperT); ok {
56		ht.Helper()
57	}
58	if !condition {
59		return
60	}
61	const (
62		stackIndex = 2
63		argPos     = 1
64	)
65	source, err := source.FormattedCallExprArg(stackIndex, argPos)
66	if err != nil {
67		t.Log(err.Error())
68		t.Skip(format.Message(msgAndArgs...))
69	}
70	t.Skip(format.WithCustomMessage(source, msgAndArgs...))
71}
72