mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
add rm-gocheck.go script and eg templates
The following "rm-gocheck:"-prefixed commits were generated by go run rm-gocheck.go --commit Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
931edfe5e9
commit
8f64611c83
4 changed files with 579 additions and 0 deletions
472
rm-gocheck.go
Normal file
472
rm-gocheck.go
Normal file
|
@ -0,0 +1,472 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
shouldCommit = flag.Bool("commit", false, "if set, each step will result in a commit")
|
||||
filter = flag.String("filter", "", "only run on files matching filter")
|
||||
titlePrefix = flag.String("prefix", "rm-gocheck: ", "commit title prefix")
|
||||
allFiles []string
|
||||
fileToCmp = map[string]string{}
|
||||
cmps = map[string][]string{}
|
||||
)
|
||||
|
||||
type action func(*step) string
|
||||
|
||||
type step struct {
|
||||
files []string
|
||||
pkgs map[string]string
|
||||
|
||||
title string
|
||||
pattern string
|
||||
action action
|
||||
comment string
|
||||
}
|
||||
|
||||
func mustSh(format string, args ...interface{}) (output []string) {
|
||||
var err error
|
||||
output, err = sh(format, args...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sh(format string, args ...interface{}) (output []string, err error) {
|
||||
cmdargs := fmt.Sprintf(format, args...)
|
||||
out, err := exec.Command("sh", "-c", cmdargs).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cmd=%s\nout=%s\n", cmdargs, out)
|
||||
}
|
||||
l := strings.Split(string(out), "\n")
|
||||
// remove last element if empty
|
||||
if len(l[len(l)-1]) == 0 {
|
||||
l = l[:len(l)-1]
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func listToArgs(l []string) string {
|
||||
s := fmt.Sprintf("%q", l)
|
||||
s = s[1 : len(s)-1]
|
||||
return s
|
||||
}
|
||||
|
||||
func Replace(subst string) action {
|
||||
return func(s *step) string {
|
||||
return fmt.Sprintf("sed -E -i 's#%s#%s#g' \\\n-- %s", s.pattern, subst, listToArgs(s.files))
|
||||
}
|
||||
}
|
||||
|
||||
func CmpReplace(subst string) action {
|
||||
return func(s *step) string {
|
||||
var allCmdArgs, filesNeedingCmpImport []string
|
||||
for _, file := range s.files {
|
||||
cmp, ok := fileToCmp[file]
|
||||
if !ok {
|
||||
cmp = "cmp"
|
||||
l := mustSh(`grep -m 1 -F '"gotest.tools/assert/cmp"' %s | awk '{print $1}'`, file)
|
||||
if len(l) > 0 {
|
||||
cmp = l[0]
|
||||
} else {
|
||||
filesNeedingCmpImport = append(filesNeedingCmpImport, file)
|
||||
}
|
||||
fileToCmp[file] = cmp
|
||||
cmps[cmp] = append(cmps[cmp], file)
|
||||
}
|
||||
}
|
||||
|
||||
if len(filesNeedingCmpImport) > 0 {
|
||||
linesep := " \\\n"
|
||||
importCmd := fmt.Sprintf(`sed -E -i '0,/^import "github\.com/ s/^(import "github\.com.*)/\1\nimport "gotest.tools\/assert\/cmp")/'%s-- %s`, linesep, listToArgs(filesNeedingCmpImport))
|
||||
allCmdArgs = append(allCmdArgs, importCmd)
|
||||
importCmd = fmt.Sprintf(`sed -E -i '0,/^\t+"github\.com/ s/(^\t+"github\.com.*)/\1\n"gotest.tools\/assert\/cmp"/'%s-- %s`, linesep, listToArgs(filesNeedingCmpImport))
|
||||
allCmdArgs = append(allCmdArgs, importCmd)
|
||||
}
|
||||
|
||||
for cmp, files := range cmps {
|
||||
cmdargs := fmt.Sprintf("sed -E -i 's#%s#%s#g' \\\n-- %s", s.pattern, strings.ReplaceAll(subst, "${cmp}", cmp), listToArgs(files))
|
||||
allCmdArgs = append(allCmdArgs, cmdargs)
|
||||
}
|
||||
return strings.Join(allCmdArgs, " \\\n&& \\\n")
|
||||
}
|
||||
}
|
||||
|
||||
func redress(pattern string, files ...string) error {
|
||||
rgx, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return errors.New("no files provided")
|
||||
}
|
||||
fn := func(file string) error {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
tmpName := file + ".tmp"
|
||||
fixed, err := os.Create(tmpName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fixed.Close()
|
||||
|
||||
const (
|
||||
searching = iota
|
||||
found
|
||||
line_done
|
||||
)
|
||||
state := searching
|
||||
s := bufio.NewScanner(f)
|
||||
for s.Scan() {
|
||||
b := s.Bytes()
|
||||
if state != found {
|
||||
bb := bytes.TrimRight(b, " \t")
|
||||
if state == line_done && len(bb) == 0 {
|
||||
continue
|
||||
}
|
||||
state = searching
|
||||
if !rgx.Match(b) {
|
||||
fixed.Write(b)
|
||||
fixed.Write([]byte{'\n'})
|
||||
} else {
|
||||
fixed.Write(bb)
|
||||
fixed.Write([]byte{' '})
|
||||
state = found
|
||||
}
|
||||
continue
|
||||
}
|
||||
b = bytes.TrimRight(b, " \t")
|
||||
fixed.Write(b)
|
||||
if len(b) > 0 {
|
||||
switch b[len(b)-1] {
|
||||
case ',', '(':
|
||||
fixed.Write([]byte{' '})
|
||||
continue
|
||||
case ')':
|
||||
fixed.Write([]byte{'\n'})
|
||||
state = line_done
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fixed.Close()
|
||||
f.Close()
|
||||
src, err := ioutil.ReadFile(tmpName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src, err = format.Source(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
os.Remove(tmpName)
|
||||
return ioutil.WriteFile(file, src, 0644)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(files))
|
||||
for _, file := range files {
|
||||
go func(file string) {
|
||||
defer wg.Done()
|
||||
if err := fn(file); err != nil {
|
||||
panic(fmt.Sprintf("redress %s: %v", file, err))
|
||||
}
|
||||
}(file)
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func Redress(s *step) string {
|
||||
return fmt.Sprintf("go run rm-gocheck.go redress '%s' \\\n %s", s.pattern, listToArgs(s.files))
|
||||
}
|
||||
|
||||
func Format(s *step) string {
|
||||
pkgs := make([]string, 0, len(s.pkgs))
|
||||
for dir := range s.pkgs {
|
||||
pkgs = append(pkgs, "./"+dir)
|
||||
}
|
||||
files := listToArgs(pkgs)
|
||||
return fmt.Sprintf("goimports -w \\\n-- %s \\\n&& \\\n gofmt -w -s \\\n-- %s", files, files)
|
||||
}
|
||||
|
||||
func CommentInterface(s *step) string {
|
||||
cmds := make([]string, 0, len(s.pkgs))
|
||||
for dir := range s.pkgs {
|
||||
cmd := fmt.Sprintf(`while :; do \
|
||||
out=$(go test -c ./%s 2>&1 | grep 'cannot use nil as type string in return argument') || break
|
||||
echo "$out" | while read line; do
|
||||
file=$(echo "$line" | cut -d: -f1)
|
||||
n=$(echo "$line" | cut -d: -f2)
|
||||
sed -E -i "${n}"'s#\b(return .*, )nil#\1""#g' "$file"
|
||||
done
|
||||
done`, dir)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
return strings.Join(cmds, " \\\n&& \\\n")
|
||||
}
|
||||
|
||||
func Eg(template string, prehook action, helperTypes string) action {
|
||||
return func(s *step) string {
|
||||
cmds := make([]string, 0, 3+4*len(s.pkgs))
|
||||
|
||||
if prehook != nil {
|
||||
cmds = append(cmds, prehook(s))
|
||||
}
|
||||
|
||||
cmdstr := fmt.Sprintf(`go get -d golang.org/x/tools/cmd/eg && dir=$(go env GOPATH)/src/golang.org/x/tools && git -C "$dir" fetch https://github.com/tiborvass/tools handle-variadic && git -C "$dir" checkout 61a94b82347c29b3289e83190aa3dda74d47abbb && go install golang.org/x/tools/cmd/eg`)
|
||||
cmds = append(cmds, cmdstr)
|
||||
|
||||
for dir, pkg := range s.pkgs {
|
||||
cmds = append(cmds, fmt.Sprintf(`/bin/echo -e 'package %s\n%s' > ./%s/eg_helper.go`, pkg, helperTypes, dir))
|
||||
cmds = append(cmds, fmt.Sprintf(`goimports -w ./%s`, dir))
|
||||
cmds = append(cmds, fmt.Sprintf(`eg -w -t %s -- ./%s`, template, dir))
|
||||
cmds = append(cmds, fmt.Sprintf(`rm -f ./%s/eg_helper.go`, dir))
|
||||
}
|
||||
cmds = append(cmds, fmt.Sprintf("go run rm-gocheck.go redress '%s' \\\n %s", `\bassert\.Assert\b.*(\(|,)\s*$`, listToArgs(s.files)))
|
||||
return strings.Join(cmds, " \\\n&& \\\n")
|
||||
}
|
||||
}
|
||||
|
||||
func do(steps []step) {
|
||||
fileArgs := listToArgs(allFiles)
|
||||
for _, s := range steps {
|
||||
fmt.Print(s.title, "... ")
|
||||
s.files, _ = sh(`git grep --name-only -E '%s' -- %s`, s.pattern, fileArgs)
|
||||
if len(s.files) == 0 {
|
||||
fmt.Println("no files match")
|
||||
continue
|
||||
}
|
||||
s.pkgs = map[string]string{}
|
||||
pkg := ""
|
||||
if len(s.files) > 0 {
|
||||
x := mustSh(`grep -m1 '^package ' -- %s | cut -d' ' -f2`, s.files[0])
|
||||
pkg = x[0]
|
||||
}
|
||||
for _, file := range s.files {
|
||||
s.pkgs[filepath.Dir(file)] = pkg
|
||||
}
|
||||
cmdstr := s.action(&s)
|
||||
mustSh(cmdstr)
|
||||
if *shouldCommit {
|
||||
if len(s.comment) > 0 {
|
||||
s.comment = "\n\n" + s.comment
|
||||
}
|
||||
msg := fmt.Sprintf("%s%s\n\n%s%s", *titlePrefix, s.title, cmdstr, s.comment)
|
||||
sh(`git add %s`, listToArgs(s.files))
|
||||
cmd := exec.Command("git", "commit", "-s", "-F-")
|
||||
cmd.Stdin = strings.NewReader(msg)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
panic(string(out))
|
||||
}
|
||||
fmt.Println("committed")
|
||||
} else {
|
||||
fmt.Println("done")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) > 0 {
|
||||
switch cmd := args[0]; cmd {
|
||||
case "redress":
|
||||
if len(args) < 3 {
|
||||
panic(fmt.Sprintf("usage: %s [flags] redress <pattern> <files...>", os.Args[0]))
|
||||
}
|
||||
if err := redress(args[1], args[2:]...); err != nil {
|
||||
panic(fmt.Sprintf("redress: %v", err))
|
||||
}
|
||||
return
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown command %s", cmd))
|
||||
}
|
||||
}
|
||||
|
||||
allFiles, _ = sh(`git grep --name-only '"github.com/go-check/check"' :**.go | grep -vE '^(vendor/|integration-cli/checker|rm-gocheck\.go|template\..*\.go)' | grep -E '%s'`, *filter)
|
||||
if len(allFiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
do([]step{
|
||||
{
|
||||
title: "normalize c.Check to c.Assert",
|
||||
pattern: `\bc\.Check\(`,
|
||||
action: Replace(`c.Assert(`),
|
||||
},
|
||||
{
|
||||
title: "redress multiline c.Assert calls",
|
||||
pattern: `\bc\.Assert\b.*(,|\()\s*$`,
|
||||
action: Redress,
|
||||
},
|
||||
{
|
||||
title: "c.Assert(...) -> assert.Assert(c, ...)",
|
||||
pattern: `\bc\.Assert\(`,
|
||||
action: Replace(`assert.Assert(c, `),
|
||||
},
|
||||
{
|
||||
title: "check.C -> testing.B for BenchmarkXXX",
|
||||
pattern: `( Benchmark[^\(]+\([^ ]+ \*)check\.C\b`,
|
||||
action: Replace(`\1testing.B`),
|
||||
},
|
||||
{
|
||||
title: "check.C -> testing.T",
|
||||
pattern: `\bcheck\.C\b`,
|
||||
action: Replace(`testing.T`),
|
||||
},
|
||||
{
|
||||
title: "ErrorMatches -> assert.ErrorContains",
|
||||
pattern: `\bassert\.Assert\(c, (.*), check\.ErrorMatches,`,
|
||||
action: Replace(`assert.ErrorContains(c, \1,`),
|
||||
},
|
||||
{
|
||||
title: "normalize to use checker",
|
||||
pattern: `\bcheck\.(Equals|DeepEquals|HasLen|IsNil|Matches|Not|NotNil)\b`,
|
||||
action: Replace(`checker.\1`),
|
||||
},
|
||||
{
|
||||
title: "Not(IsNil) -> != nil",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Not\(checker\.IsNil\)`,
|
||||
action: Replace(`assert.Assert(c, \1 != nil`),
|
||||
},
|
||||
{
|
||||
title: "Not(Equals) -> a != b",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Not\(checker\.Equals\), (.*)`,
|
||||
action: Replace(`assert.Assert(c, \1 != \2`),
|
||||
},
|
||||
{
|
||||
title: "Not(Matches) -> !cmp.Regexp",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Not\(checker\.Matches\), (.*)\)`,
|
||||
action: CmpReplace(`assert.Assert(c, !${cmp}.Regexp("^"+\2+"$", \1)().Success())`),
|
||||
},
|
||||
{
|
||||
title: "Equals -> assert.Equal",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Equals, (.*)`,
|
||||
action: Replace(`assert.Equal(c, \1, \2`),
|
||||
},
|
||||
{
|
||||
title: "DeepEquals -> assert.DeepEqual",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.DeepEquals, (.*)`,
|
||||
action: Replace(`assert.DeepEqual(c, \1, \2`),
|
||||
},
|
||||
{
|
||||
title: "HasLen -> assert.Equal + len()",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.HasLen, (.*)`,
|
||||
action: Replace(`assert.Equal(c, len(\1), \2`),
|
||||
},
|
||||
{
|
||||
title: "IsNil",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.IsNil\b`,
|
||||
action: Replace(`assert.Assert(c, \1 == nil`),
|
||||
},
|
||||
{
|
||||
title: "NotNil",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.NotNil\b`,
|
||||
action: Replace(`assert.Assert(c, \1 != nil`),
|
||||
},
|
||||
{
|
||||
title: "False",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.False\b`,
|
||||
action: Replace(`assert.Assert(c, !\1`),
|
||||
},
|
||||
{
|
||||
title: "True",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.True`,
|
||||
action: Replace(`assert.Assert(c, \1`),
|
||||
},
|
||||
{
|
||||
title: "redress check.Suite calls",
|
||||
pattern: `[^/]\bcheck\.Suite\(.*\{\s*$`,
|
||||
action: Redress,
|
||||
},
|
||||
{
|
||||
title: "comment out check.Suite calls",
|
||||
pattern: `^([^*])+?((var .*)?check\.Suite\(.*\))`,
|
||||
action: Replace(`\1/*\2*/`),
|
||||
},
|
||||
{
|
||||
title: "comment out check.TestingT",
|
||||
pattern: `([^*])(check\.TestingT\([^\)]+\))`,
|
||||
action: Replace(`\1/*\2*/`),
|
||||
},
|
||||
{
|
||||
title: "run goimports to compile successfully",
|
||||
action: Format,
|
||||
},
|
||||
{
|
||||
title: "Matches -> cmp.Regexp",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Matches, (.*)\)$`,
|
||||
action: Eg("template.matches.go",
|
||||
CmpReplace(`assert.Assert(c, eg_matches(${cmp}.Regexp, \1, \2))`),
|
||||
`var eg_matches func(func(cmp.RegexOrPattern, string) cmp.Comparison, interface{}, string, ...interface{}) bool`),
|
||||
},
|
||||
{
|
||||
title: "Not(Contains) -> !strings.Contains",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Not\(checker\.Contains\), (.*)\)$`,
|
||||
action: Eg("template.not_contains.go",
|
||||
Replace(`assert.Assert(c, !eg_contains(\1, \2))`),
|
||||
`var eg_contains func(arg1, arg2 string, extra ...interface{}) bool`),
|
||||
},
|
||||
{
|
||||
title: "Contains -> strings.Contains",
|
||||
pattern: `\bassert\.Assert\(c, (.*), checker\.Contains, (.*)\)$`,
|
||||
action: Eg("template.contains.go",
|
||||
Replace(`assert.Assert(c, eg_contains(\1, \2))`),
|
||||
`var eg_contains func(arg1, arg2 string, extra ...interface{}) bool`),
|
||||
},
|
||||
{
|
||||
title: "convert check.Commentf to string - with multiple args",
|
||||
pattern: `\bcheck.Commentf\(([^,]+),(.*)\)`,
|
||||
action: Replace(`fmt.Sprintf(\1,\2)`),
|
||||
},
|
||||
{
|
||||
title: "convert check.Commentf to string - with just one string",
|
||||
pattern: `\bcheck.Commentf\(("[^"]+")\)`,
|
||||
action: Replace(`\1`),
|
||||
},
|
||||
{
|
||||
title: "convert check.Commentf to string - other",
|
||||
pattern: `\bcheck.Commentf\(([^\)]+)\)`,
|
||||
action: Replace(`\1`),
|
||||
},
|
||||
{
|
||||
title: "check.CommentInterface -> string",
|
||||
pattern: `(\*testing\.T\b.*)check\.CommentInterface\b`,
|
||||
action: Replace(`\1string`),
|
||||
},
|
||||
{
|
||||
title: "goimports",
|
||||
action: Format,
|
||||
},
|
||||
{
|
||||
title: "fix compile errors from converting check.CommentInterface to string",
|
||||
action: CommentInterface,
|
||||
},
|
||||
})
|
||||
}
|
35
template.contains.go
Normal file
35
template.contains.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
type fn func(arg1, arg2 string, extra ...interface{}) bool
|
||||
type assertfn func(t assert.TestingT, comparison assert.BoolOrComparison, msgAndArgs ...interface{})
|
||||
|
||||
func before(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_contains fn,
|
||||
arg1 string,
|
||||
arg2 string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, eg_contains(arg1, arg2, extra...))
|
||||
}
|
||||
|
||||
func after(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_contains fn,
|
||||
arg1 string,
|
||||
arg2 string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, strings.Contains(arg1, arg2), extra...)
|
||||
}
|
37
template.matches.go
Normal file
37
template.matches.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
type fn func(re func(cmp.RegexOrPattern, string) cmp.Comparison, r interface{}, v string, extra ...interface{}) bool
|
||||
type assertfn func(t assert.TestingT, comparison assert.BoolOrComparison, msgAndArgs ...interface{})
|
||||
|
||||
func before(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_matches fn,
|
||||
re func(cmp.RegexOrPattern, string) cmp.Comparison,
|
||||
r string,
|
||||
v string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, eg_matches(re, v, r, extra...))
|
||||
}
|
||||
|
||||
func after(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_matches fn,
|
||||
re func(cmp.RegexOrPattern, string) cmp.Comparison,
|
||||
r string,
|
||||
v string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, re("^"+r+"$", v), extra...)
|
||||
}
|
35
template.not_contains.go
Normal file
35
template.not_contains.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
type fn func(arg1, arg2 string, extra ...interface{}) bool
|
||||
type assertfn func(t assert.TestingT, comparison assert.BoolOrComparison, msgAndArgs ...interface{})
|
||||
|
||||
func before(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_contains fn,
|
||||
arg1 string,
|
||||
arg2 string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, !eg_contains(arg1, arg2, extra...))
|
||||
}
|
||||
|
||||
func after(
|
||||
t *testing.T,
|
||||
a assertfn,
|
||||
eg_contains fn,
|
||||
arg1 string,
|
||||
arg2 string,
|
||||
extra ...interface{}) {
|
||||
|
||||
a(t, !strings.Contains(arg1, arg2), extra...)
|
||||
}
|
Loading…
Reference in a new issue