-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Output mutant statuses filter (#226)
* docs: add output-statuses flag #108 * feat: add mutant logger #108 * refactor: move mutant printing to logger #108 * ci: add statuses filter #108 * fix: deepsource issue --------- Co-authored-by: Davide Petilli <[email protected]>
- Loading branch information
1 parent
ba6851a
commit e7bdf6a
Showing
10 changed files
with
245 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
unleash: | ||
output-statuses: lctr | ||
threshold: | ||
efficacy: 80 | ||
mutant-coverage: 90 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package report | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/go-gremlins/gremlins/internal/configuration" | ||
"github.com/go-gremlins/gremlins/internal/log" | ||
"github.com/go-gremlins/gremlins/internal/mutator" | ||
) | ||
|
||
type Filter = map[mutator.Status]struct{} | ||
|
||
var ErrInvalidFilter = errors.New("invalid statuses filter, only 'lctkvsr' letters allowed") | ||
|
||
// MutantLogger prints mutant statuses based on filter and verbosity flags. | ||
type MutantLogger struct { | ||
Filter | ||
} | ||
|
||
func NewLogger() MutantLogger { | ||
outputStatuses := configuration.Get[string](configuration.UnleashOutputStatusesKey) | ||
f, err := ParseFilter(outputStatuses) | ||
if err != nil { | ||
log.Infof("output-statuses filter not applied: %s\n", err) | ||
} | ||
|
||
return MutantLogger{ | ||
Filter: f, | ||
} | ||
} | ||
|
||
func (l MutantLogger) Mutant(m mutator.Mutator) { | ||
if l.Filter == nil { | ||
Mutant(m) | ||
|
||
return | ||
} | ||
|
||
if _, ok := l.Filter[m.Status()]; ok { | ||
Mutant(m) | ||
} | ||
} | ||
|
||
func ParseFilter(s string) (Filter, error) { | ||
if s == "" { | ||
return nil, nil | ||
} | ||
|
||
result := Filter{} | ||
|
||
for _, r := range s { | ||
switch r { | ||
case 'l': | ||
result[mutator.Lived] = struct{}{} | ||
case 'c': | ||
result[mutator.NotCovered] = struct{}{} | ||
case 't': | ||
result[mutator.TimedOut] = struct{}{} | ||
case 'k': | ||
result[mutator.Killed] = struct{}{} | ||
case 'v': | ||
result[mutator.NotViable] = struct{}{} | ||
case 's': | ||
result[mutator.Skipped] = struct{}{} | ||
case 'r': | ||
result[mutator.Runnable] = struct{}{} | ||
default: | ||
return nil, ErrInvalidFilter | ||
} | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package report_test | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
|
||
"github.com/go-gremlins/gremlins/internal/configuration" | ||
"github.com/go-gremlins/gremlins/internal/log" | ||
"github.com/go-gremlins/gremlins/internal/mutator" | ||
"github.com/go-gremlins/gremlins/internal/report" | ||
) | ||
|
||
func Test_parseFilter(t *testing.T) { | ||
tests := []struct { | ||
filter string | ||
want report.Filter | ||
err error | ||
}{ | ||
{ | ||
filter: "lc", | ||
want: report.Filter{ | ||
mutator.Lived: struct{}{}, | ||
mutator.NotCovered: struct{}{}, | ||
}, | ||
}, | ||
{ | ||
filter: "tkvs", | ||
want: report.Filter{ | ||
mutator.TimedOut: struct{}{}, | ||
mutator.Killed: struct{}{}, | ||
mutator.NotViable: struct{}{}, | ||
mutator.Skipped: struct{}{}, | ||
}, | ||
}, | ||
{ | ||
filter: "r", | ||
want: report.Filter{ | ||
mutator.Runnable: struct{}{}, | ||
}, | ||
}, | ||
{ | ||
filter: "", | ||
}, | ||
{ | ||
filter: "lnc", | ||
want: nil, | ||
err: report.ErrInvalidFilter, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.filter, func(t *testing.T) { | ||
got, err := report.ParseFilter(tt.filter) | ||
if !errors.Is(err, tt.err) { | ||
t.Errorf("ParseFilter() error = %v, wantErr %v", err, tt.err) | ||
} | ||
|
||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("ParseFilter() got = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestLogger(t *testing.T) { | ||
out := &bytes.Buffer{} | ||
defer out.Reset() | ||
log.Init(out, &bytes.Buffer{}) | ||
defer log.Reset() | ||
|
||
m := stubMutant{status: mutator.NotCovered, mutantType: mutator.ConditionalsBoundary, position: fakePosition} | ||
|
||
configuration.Set(configuration.UnleashOutputStatusesKey, "lp") | ||
logger := report.NewLogger() // prints error | ||
|
||
logger.Mutant(m) // prints Not covered because no filter | ||
|
||
m.status = mutator.Killed | ||
|
||
configuration.Set(configuration.UnleashOutputStatusesKey, "") | ||
logger = report.NewLogger() | ||
|
||
logger.Mutant(m) // prints Killed because no filter | ||
|
||
configuration.Set(configuration.UnleashOutputStatusesKey, "l") | ||
logger = report.NewLogger() | ||
|
||
logger.Mutant(m) // Killed filtered | ||
|
||
m.status = mutator.Lived | ||
|
||
logger.Mutant(m) // prints Lived because no filter | ||
|
||
got := out.String() | ||
|
||
want := "output-statuses filter not applied: " + report.ErrInvalidFilter.Error() + "\n" + | ||
" NOT COVERED CONDITIONALS_BOUNDARY at aFolder/aFile.go:12:3\n" + | ||
" KILLED CONDITIONALS_BOUNDARY at aFolder/aFile.go:12:3\n" + | ||
" LIVED CONDITIONALS_BOUNDARY at aFolder/aFile.go:12:3\n" | ||
|
||
if !cmp.Equal(got, want) { | ||
t.Errorf(cmp.Diff(got, want)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters