Skip to content

Commit

Permalink
#2 Refactor to use slices of mutant types
Browse files Browse the repository at this point in the history
Signed-off-by: Davide Petilli <davide@petilli.me>
  • Loading branch information
k3rn31 committed Jun 25, 2022
1 parent 58a3249 commit 6b3c1ab
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 59 deletions.
27 changes: 18 additions & 9 deletions mutator/mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ import "go/token"

type MutantType int

const (
ConditionalBoundary MutantType = iota
)

func (mt MutantType) String() string {
switch mt {
case ConditionalBoundary:
Expand All @@ -33,9 +29,22 @@ func (mt MutantType) String() string {
}
}

var tokenMutantType = map[token.Token]MutantType{
token.GTR: ConditionalBoundary,
token.LSS: ConditionalBoundary,
token.GEQ: ConditionalBoundary,
token.LEQ: ConditionalBoundary,
const (
ConditionalBoundary MutantType = iota
)

var tokenMutantType = map[token.Token][]MutantType{
token.GTR: {ConditionalBoundary},
token.LSS: {ConditionalBoundary},
token.GEQ: {ConditionalBoundary},
token.LEQ: {ConditionalBoundary},
}

var mutations = map[MutantType]map[token.Token]token.Token{
ConditionalBoundary: {
token.GTR: token.GEQ,
token.LSS: token.LEQ,
token.GEQ: token.GTR,
token.LEQ: token.LSS,
},
}
48 changes: 32 additions & 16 deletions mutator/mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ const (
)

type Mutant struct {
MutantType MutantType
Token token.Token
Position token.Position
MutantType MutantType
Status MutationStatus
Token token.Token
Mutation token.Token
}

type Mutator struct {
Expand All @@ -47,35 +48,50 @@ func New(p coverage.Profile) *Mutator {
return &Mutator{covProfile: p}
}

func (m Mutator) RunWithFileName(fileName string) []Mutant {
func (mu Mutator) RunWithFileName(fileName string) []Mutant {
var result []Mutant
set := token.NewFileSet()
file, _ := parser.ParseFile(set, fileName, nil, parser.ParseComments)
ast.Inspect(file, func(node ast.Node) bool {
switch node := node.(type) {
case *ast.BinaryExpr:
r, ok := inspectBinaryExpr(set, node)
r, ok := mu.inspectBinaryExpr(set, node)
if !ok {
return false
}
if m.covProfile.IsCovered(r.Position) {
r.Status = Runnable
}
result = append(result, r)
result = append(result, r...)
}
return true
})
return result
}

func inspectBinaryExpr(set *token.FileSet, be *ast.BinaryExpr) (Mutant, bool) {
mt, ok := tokenMutantType[be.Op]
func (mu Mutator) inspectBinaryExpr(set *token.FileSet, be *ast.BinaryExpr) ([]Mutant, bool) {
var result []Mutant
mutantTypes, ok := tokenMutantType[be.Op]
if !ok {
return Mutant{}, false
return nil, false
}
return Mutant{
MutantType: mt,
Token: be.Op,
Position: set.Position(be.OpPos),
}, true
for _, mt := range mutantTypes {
pos := set.Position(be.OpPos)
mutant := Mutant{
MutantType: mt,
Token: be.Op,
Mutation: mutations[mt][be.Op],
Status: mutationStatus(mu, pos),
Position: pos,
}
result = append(result, mutant)
}

return result, true
}

func mutationStatus(mu Mutator, pos token.Position) MutationStatus {
var status MutationStatus
if mu.covProfile.IsCovered(pos) {
status = Runnable
}

return status
}
76 changes: 42 additions & 34 deletions mutator/mutator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,50 +34,55 @@ func notCoveredPosition(filename string) coverage.Profile {

func TestMutations(t *testing.T) {
testCases := []struct {
name string
fileName string
mutantType mutator.MutantType
tokenType token.Token
covProfile coverage.Profile
mutStatus mutator.MutationStatus
name string
fileName string
mutantType mutator.MutantType
token token.Token
tokenMutation token.Token
covProfile coverage.Profile
mutStatus mutator.MutationStatus
}{
{
name: "it recognizes CONDITIONAL_BOUNDARY with GTR",
fileName: "testdata/fixtures/conditional_boundary_gtr_go",
mutantType: mutator.ConditionalBoundary,
tokenType: token.GTR,
covProfile: coveredPosition("testdata/fixtures/conditional_boundary_gtr_go"),
mutStatus: mutator.Runnable,
name: "it recognizes CONDITIONAL_BOUNDARY with GTR",
fileName: "testdata/fixtures/conditional_boundary_gtr_go",
mutantType: mutator.ConditionalBoundary,
token: token.GTR,
tokenMutation: token.GEQ,
covProfile: coveredPosition("testdata/fixtures/conditional_boundary_gtr_go"),
mutStatus: mutator.Runnable,
},
{
name: "it recognizes CONDITIONAL_BOUNDARY with LSS",
fileName: "testdata/fixtures/conditional_boundary_lss_go",
mutantType: mutator.ConditionalBoundary,
tokenType: token.LSS,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_lss_go"),
mutStatus: mutator.NotCovered,
name: "it recognizes CONDITIONAL_BOUNDARY with LSS",
fileName: "testdata/fixtures/conditional_boundary_lss_go",
mutantType: mutator.ConditionalBoundary,
token: token.LSS,
tokenMutation: token.LEQ,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_lss_go"),
mutStatus: mutator.NotCovered,
},
{
name: "it recognizes CONDITIONAL_BOUNDARY with LEQ",
fileName: "testdata/fixtures/conditional_boundary_leq_go",
mutantType: mutator.ConditionalBoundary,
tokenType: token.LEQ,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_leq_go"),
mutStatus: mutator.NotCovered,
name: "it recognizes CONDITIONAL_BOUNDARY with LEQ",
fileName: "testdata/fixtures/conditional_boundary_leq_go",
mutantType: mutator.ConditionalBoundary,
token: token.LEQ,
tokenMutation: token.LSS,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_leq_go"),
mutStatus: mutator.NotCovered,
},
{
name: "it recognizes CONDITIONAL_BOUNDARY with GEQ",
fileName: "testdata/fixtures/conditional_boundary_geq_go",
mutantType: mutator.ConditionalBoundary,
tokenType: token.GEQ,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_geq_go"),
mutStatus: mutator.NotCovered,
name: "it recognizes CONDITIONAL_BOUNDARY with GEQ",
fileName: "testdata/fixtures/conditional_boundary_geq_go",
mutantType: mutator.ConditionalBoundary,
token: token.GEQ,
tokenMutation: token.GTR,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_geq_go"),
mutStatus: mutator.NotCovered,
},
{
name: "it skips illegal CONDITIONAL_BOUNDARY",
fileName: "testdata/fixtures/conditional_boundary_illegal_go",
mutantType: mutator.ConditionalBoundary,
tokenType: token.ILLEGAL,
token: token.ILLEGAL,
covProfile: notCoveredPosition("testdata/fixtures/conditional_boundary_illegal_go"),
},
}
Expand All @@ -88,7 +93,7 @@ func TestMutations(t *testing.T) {
mut := mutator.New(tc.covProfile)
got := mut.RunWithFileName(tc.fileName)

if tc.tokenType == token.ILLEGAL {
if tc.token == token.ILLEGAL {
if len(got) != 0 {
t.Errorf("expected no mutator found")
}
Expand All @@ -97,8 +102,11 @@ func TestMutations(t *testing.T) {
if !cmp.Equal(got[0].MutantType, mutator.ConditionalBoundary) {
t.Errorf(cmp.Diff(got[0].MutantType, mutator.ConditionalBoundary))
}
if !cmp.Equal(got[0].Token, tc.tokenType) {
t.Errorf(cmp.Diff(got[0].Token, tc.tokenType))
if !cmp.Equal(got[0].Token, tc.token) {
t.Errorf(cmp.Diff(got[0].Token, tc.token))
}
if !cmp.Equal(got[0].Mutation, tc.tokenMutation) {
t.Errorf(cmp.Diff(got[0].Mutation, tc.tokenMutation))
}
if !cmp.Equal(got[0].Status, tc.mutStatus) {
t.Errorf(cmp.Diff(got[0].Status, tc.mutStatus))
Expand Down

0 comments on commit 6b3c1ab

Please # to comment.