From 09805176fae0434ab3aa734f161871991abc6163 Mon Sep 17 00:00:00 2001 From: Markus Zimmermann Date: Thu, 23 Jun 2016 10:18:44 +0200 Subject: [PATCH 1/2] Fix, linters did not display their problems --- scripts/lint.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/lint.sh b/scripts/lint.sh index a2594b3..28ebd53 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -5,18 +5,18 @@ if [ -z ${ROOT_DIR+x} ]; then echo "ROOT_DIR is not set"; exit 1; fi echo "gofmt:" OUT=$(gofmt -l $ROOT_DIR) -if [ $($OUT | wc -l) -ne 0 ]; then echo $OUT; PROBLEM=1; fi +if [ $(echo -n "$OUT" | wc -l) -ne 0 ]; then echo -n "$OUT"; PROBLEM=1; fi echo "errcheck:" OUT=$(errcheck $PKG/...) -if [ $($OUT | wc -l) -ne 0 ]; then echo $OUT; PROBLEM=1; fi +if [ $(echo -n "$OUT" | wc -l) -ne 0 ]; then echo -n "$OUT"; PROBLEM=1; fi echo "go vet:" OUT=$(go tool vet -all=true -v=true $ROOT_DIR 2>&1 | grep --invert-match -P "(Checking file|\%p of wrong type|can't check non-constant format|not compatible with reflect.StructTag.Get)") -if [ $($OUT | wc -l) -ne 0 ]; then echo $OUT; PROBLEM=1; fi +if [ $(echo -n "$OUT" | wc -l) -ne 0 ]; then echo -n "$OUT"; PROBLEM=1; fi echo "golint:" OUT=$(golint $PKG/... | grep --invert-match -P "(_string.go:)") -if [ $($OUT | wc -l) -ne 0 ]; then echo $OUT; PROBLEM=1; fi +if [ $(echo -n "$OUT" | wc -l) -ne 0 ]; then echo -n "$OUT"; PROBLEM=1; fi if [ -n "$PROBLEM" ]; then exit 1; fi From 1a3ed256c6e3ca0e12fbcced491f778d360374ba Mon Sep 17 00:00:00 2001 From: Markus Zimmermann Date: Thu, 23 Jun 2016 11:18:14 +0200 Subject: [PATCH 2/2] Extend the noop substitution to branch mutators This work started in PR #20 --- astutil/create.go | 36 ++++++++++++++++++++++++ astutil/query.go | 33 ++++++++++++++++++++++ cmd/go-mutesting/main_test.go | 2 +- mutator/branch/mutatecase.go | 5 +++- mutator/branch/mutateelse.go | 5 ++-- mutator/branch/mutateif.go | 5 +++- mutator/statement/remove.go | 45 ++---------------------------- testdata/branch/mutatecase.go.0.go | 2 +- testdata/branch/mutatecase.go.1.go | 2 +- testdata/branch/mutatecase.go.2.go | 2 +- testdata/branch/mutateelse.go.0.go | 2 +- testdata/branch/mutateif.go.0.go | 2 +- testdata/branch/mutateif.go.1.go | 2 +- 13 files changed, 88 insertions(+), 55 deletions(-) create mode 100644 astutil/create.go create mode 100644 astutil/query.go diff --git a/astutil/create.go b/astutil/create.go new file mode 100644 index 0000000..23b0775 --- /dev/null +++ b/astutil/create.go @@ -0,0 +1,36 @@ +package astutil + +import ( + "go/ast" + "go/token" +) + +// CreateNoopOfStatement creates a syntactically safe noop statement out of a given statement. +func CreateNoopOfStatement(stmt ast.Stmt) ast.Stmt { + return CreateNoopOfStatements([]ast.Stmt{stmt}) +} + +// CreateNoopOfStatement creates a syntactically safe noop statement out of a given statement. +func CreateNoopOfStatements(stmts []ast.Stmt) ast.Stmt { + var ids []ast.Expr + for _, stmt := range stmts { + ids = append(ids, IdentifiersInStatement(stmt)...) + } + + if len(ids) == 0 { + return &ast.EmptyStmt{ + Semicolon: token.NoPos, + } + } + + lhs := make([]ast.Expr, len(ids)) + for i := range ids { + lhs[i] = ast.NewIdent("_") + } + + return &ast.AssignStmt{ + Lhs: lhs, + Rhs: ids, + Tok: token.ASSIGN, + } +} diff --git a/astutil/query.go b/astutil/query.go new file mode 100644 index 0000000..8f64bf5 --- /dev/null +++ b/astutil/query.go @@ -0,0 +1,33 @@ +package astutil + +import ( + "go/ast" +) + +// IdentifiersInStatement returns all identifiers with their found in a statement. +func IdentifiersInStatement(stmt ast.Stmt) []ast.Expr { + w := &identifierWalker{} + + ast.Walk(w, stmt) + + return w.identifiers +} + +type identifierWalker struct { + identifiers []ast.Expr +} + +func (w *identifierWalker) Visit(node ast.Node) ast.Visitor { + switch n := node.(type) { + case *ast.Ident: + w.identifiers = append(w.identifiers, n) + + return nil + case *ast.SelectorExpr: + w.identifiers = append(w.identifiers, n) + + return nil + } + + return w +} diff --git a/cmd/go-mutesting/main_test.go b/cmd/go-mutesting/main_test.go index 7d086c4..c3233b8 100644 --- a/cmd/go-mutesting/main_test.go +++ b/cmd/go-mutesting/main_test.go @@ -44,5 +44,5 @@ func TestMain(t *testing.T) { out := <-bufChannel assert.Equal(t, returnOk, exitCode) - assert.Contains(t, out, "The mutation score is 0.578947 (11 passed, 8 failed, 2 skipped, total is 21)") + assert.Contains(t, out, "The mutation score is 0.583333 (7 passed, 5 failed, 1 skipped, total is 13)") } diff --git a/mutator/branch/mutatecase.go b/mutator/branch/mutatecase.go index 03fe776..a01f31c 100644 --- a/mutator/branch/mutatecase.go +++ b/mutator/branch/mutatecase.go @@ -3,6 +3,7 @@ package branch import ( "go/ast" + "github.com/zimmski/go-mutesting/astutil" "github.com/zimmski/go-mutesting/mutator" ) @@ -47,7 +48,9 @@ func (m *MutatorCase) Mutate(node ast.Node, changed chan bool) { } old := n.Body - n.Body = make([]ast.Stmt, 0) + n.Body = []ast.Stmt{ + astutil.CreateNoopOfStatements(n.Body), + } changed <- true <-changed diff --git a/mutator/branch/mutateelse.go b/mutator/branch/mutateelse.go index 038e26f..f87d427 100644 --- a/mutator/branch/mutateelse.go +++ b/mutator/branch/mutateelse.go @@ -3,6 +3,7 @@ package branch import ( "go/ast" + "github.com/zimmski/go-mutesting/astutil" "github.com/zimmski/go-mutesting/mutator" ) @@ -56,9 +57,7 @@ func (m *MutatorElse) Mutate(node ast.Node, changed chan bool) { } old := n.Else - n.Else = &ast.EmptyStmt{ - Semicolon: n.Else.Pos(), - } + n.Else = astutil.CreateNoopOfStatement(old) changed <- true <-changed diff --git a/mutator/branch/mutateif.go b/mutator/branch/mutateif.go index 50cfc28..01a2dd2 100644 --- a/mutator/branch/mutateif.go +++ b/mutator/branch/mutateif.go @@ -3,6 +3,7 @@ package branch import ( "go/ast" + "github.com/zimmski/go-mutesting/astutil" "github.com/zimmski/go-mutesting/mutator" ) @@ -47,7 +48,9 @@ func (m *MutatorIf) Mutate(node ast.Node, changed chan bool) { } old := n.Body.List - n.Body.List = make([]ast.Stmt, 0) + n.Body.List = []ast.Stmt{ + astutil.CreateNoopOfStatement(n.Body), + } changed <- true <-changed diff --git a/mutator/statement/remove.go b/mutator/statement/remove.go index ce679ca..7dd45aa 100644 --- a/mutator/statement/remove.go +++ b/mutator/statement/remove.go @@ -4,6 +4,7 @@ import ( "go/ast" "go/token" + "github.com/zimmski/go-mutesting/astutil" "github.com/zimmski/go-mutesting/mutator" ) @@ -85,7 +86,7 @@ func (m *MutatorRemoveStatement) Mutate(node ast.Node, changed chan bool) { for i, ni := range l { if m.checkStatement(ni) { old := l[i] - l[i] = createNoop(old) + l[i] = astutil.CreateNoopOfStatement(old) changed <- true <-changed @@ -98,48 +99,6 @@ func (m *MutatorRemoveStatement) Mutate(node ast.Node, changed chan bool) { } } -func createNoop(old ast.Stmt) ast.Stmt { - v := &idCollector{} - ast.Walk(v, old) - return v.generateStatement(old) -} - -type idCollector struct { - Ids []ast.Expr -} - -func (i *idCollector) Visit(node ast.Node) ast.Visitor { - switch v := node.(type) { - case *ast.Ident: - i.Ids = append(i.Ids, v) - return nil - case *ast.SelectorExpr: - i.Ids = append(i.Ids, v) - return nil - } - return i -} - -func (i *idCollector) generateStatement(old ast.Stmt) ast.Stmt { - if len(i.Ids) == 0 { - return &ast.EmptyStmt{ - Semicolon: old.Pos(), - } - } - - lhs := make([]ast.Expr, len(i.Ids)) - for i := range i.Ids { - lhs[i] = ast.NewIdent("_") - } - - return &ast.AssignStmt{ - Lhs: lhs, - Rhs: i.Ids, - Tok: token.ASSIGN, - TokPos: old.Pos(), - } -} - // String implements the String method of the Stringer interface func (m MutatorRemoveStatement) String() string { return "statement/remove" diff --git a/testdata/branch/mutatecase.go.0.go b/testdata/branch/mutatecase.go.0.go index 5ba84cd..a757ce0 100644 --- a/testdata/branch/mutatecase.go.0.go +++ b/testdata/branch/mutatecase.go.0.go @@ -12,7 +12,7 @@ func main() { for i != 4 { switch { case i == 1: - + _, _ = fmt.Println, i case i == 2: fmt.Println(i * 2) default: diff --git a/testdata/branch/mutatecase.go.1.go b/testdata/branch/mutatecase.go.1.go index 632074e..8f6316a 100644 --- a/testdata/branch/mutatecase.go.1.go +++ b/testdata/branch/mutatecase.go.1.go @@ -14,7 +14,7 @@ func main() { case i == 1: fmt.Println(i) case i == 2: - + _, _ = fmt.Println, i default: fmt.Println(i * 3) } diff --git a/testdata/branch/mutatecase.go.2.go b/testdata/branch/mutatecase.go.2.go index 5223de3..3bed4b3 100644 --- a/testdata/branch/mutatecase.go.2.go +++ b/testdata/branch/mutatecase.go.2.go @@ -16,7 +16,7 @@ func main() { case i == 2: fmt.Println(i * 2) default: - + _, _ = fmt.Println, i } i++ diff --git a/testdata/branch/mutateelse.go.0.go b/testdata/branch/mutateelse.go.0.go index 6c359c7..ee3c223 100644 --- a/testdata/branch/mutateelse.go.0.go +++ b/testdata/branch/mutateelse.go.0.go @@ -15,7 +15,7 @@ func main() { } else if i == 2 { fmt.Println(i * 2) } else { - + _, _ = fmt.Println, i } i++ diff --git a/testdata/branch/mutateif.go.0.go b/testdata/branch/mutateif.go.0.go index ffeea61..fb45fb7 100644 --- a/testdata/branch/mutateif.go.0.go +++ b/testdata/branch/mutateif.go.0.go @@ -11,7 +11,7 @@ func main() { for i != 4 { if i == 1 { - + _, _ = fmt.Println, i } else if i == 2 { fmt.Println(i * 2) } else { diff --git a/testdata/branch/mutateif.go.1.go b/testdata/branch/mutateif.go.1.go index b5476a9..694cf07 100644 --- a/testdata/branch/mutateif.go.1.go +++ b/testdata/branch/mutateif.go.1.go @@ -13,7 +13,7 @@ func main() { if i == 1 { fmt.Println(i) } else if i == 2 { - + _, _ = fmt.Println, i } else { fmt.Println(i * 3) }