Skip to content

Commit

Permalink
Merge branch 'feature/#7' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
k3rn31 committed Jun 25, 2022
2 parents 41fdb98 + 0fb341a commit 898fab0
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ all: lint test build

build:
mkdir -p ${BIN}
${GO_BUILD} -o ${BIN}/${BINARY_NAME} cmd/gremlins/main.go
${GO_BUILD} -tags exec -o ${BIN}/${BINARY_NAME} cmd/gremlins/main.go

test:
${GO_TEST} ./...
Expand Down
30 changes: 30 additions & 0 deletions cmd/gremlins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//go:build exec

/*
* Copyright 2022 The Gremlins Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cmd

import (
"github.com/spf13/cobra"
)

var GremlinsCmd = &cobra.Command{
Use: "gremlins",
Short: `Gremlins is a mutation testing tool for Go projects, made with love by k3rn31
and friends.
`,
}
14 changes: 13 additions & 1 deletion cmd/gremlins/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build exec

/*
* Copyright 2022 The Gremlins Authors
*
Expand All @@ -16,6 +18,16 @@

package main

func main() {
import (
"fmt"
"github.com/k3rn31/gremlins/cmd"
"os"
)

func main() {
cmd.GremlinsCmd.AddCommand(cmd.UnleashCmd)
if err := cmd.GremlinsCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
60 changes: 60 additions & 0 deletions cmd/unleash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build exec

/*
* Copyright 2022 The Gremlins Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cmd

import (
"fmt"
"github.com/k3rn31/gremlins/coverage"
"github.com/k3rn31/gremlins/mutator"
"github.com/spf13/cobra"
"io/ioutil"
"os"
)

var UnleashCmd = &cobra.Command{
Use: "unleash [path of the Go module]",
Aliases: []string{"run", "r"},
Args: cobra.MaximumNArgs(1),
Short: "Executes the mutation testing process",
Long: `Unleashes the gremlins and performs mutation testing on a Go module.`,
Run: func(cmd *cobra.Command, args []string) {
path := "."
if len(args) > 0 {
path = args[0]
}
tmpdir, _ := ioutil.TempDir(os.TempDir(), "unleash-")
cov, err := coverage.New(tmpdir, path)
if err != nil {
fmt.Printf("directory %s does not contain main module\n", path)
os.Exit(1)
}
pro, err := cov.Run()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
mut := mutator.New(os.DirFS(path), pro)
rec := mut.Run()

// Temporary report
for _, r := range rec {
fmt.Printf("found possible mutant at %s - %s\n", r.Position, r.Status)
}
},
}
29 changes: 18 additions & 11 deletions coverage/coverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
type Coverage struct {
cmdContext execContext
workDir string
path string
fileName string
mod string
}
Expand All @@ -40,31 +41,37 @@ type execContext = func(name string, args ...string) *exec.Cmd

// New instantiates a Coverage element using exec.Command as execContext,
// actually running the command on the OS.
func New(workdir string) *Coverage {
return NewWithCmdAndPackage(exec.Command, getMod(), workdir)
func New(workdir, path string) (*Coverage, error) {
if strings.HasSuffix(path, "/") {
path = path[:len(path)-1]
}
mod, err := getMod(path)
if err != nil {
return nil, err
}
return NewWithCmdAndPackage(exec.Command, mod, workdir, path), nil
}

func getMod() string {
file, err := os.Open("go.mod")
func getMod(path string) (string, error) {
file, err := os.Open(path + "/go.mod")
if err != nil {
fmt.Printf("not in a go module root folder: %v\n", err)
os.Exit(-1)
return "", err
}
r := bufio.NewReader(file)
line, _, err := r.ReadLine()
if err != nil {
fmt.Printf("not in a go module root folder %v\n\n", err)
os.Exit(-1)
return "", err
}
packageName := bytes.TrimPrefix(line, []byte("module "))
return string(packageName)
return string(packageName), nil
}

// NewWithCmdAndPackage instantiates a Coverage element given a custom execContext.
func NewWithCmdAndPackage(cmdContext execContext, mod, workdir string) *Coverage {
func NewWithCmdAndPackage(cmdContext execContext, mod, workdir, path string) *Coverage {
return &Coverage{
cmdContext: cmdContext,
workDir: workdir,
path: path + "/...",
fileName: "coverage",
mod: mod,
}
Expand Down Expand Up @@ -102,7 +109,7 @@ func (c Coverage) filePath() string {
}

func (c Coverage) execute() error {
cmd := c.cmdContext("go", "test", "-cover", "-coverprofile", c.filePath(), "./...")
cmd := c.cmdContext("go", "test", "-cover", "-coverprofile", c.filePath(), c.path)
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions coverage/coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestCoverageRun(t *testing.T) {
wantFilename := "coverage"
wantFilePath := wantWorkdir + "/" + wantFilename
holder := &commandHolder{}
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(holder), "example.com", wantWorkdir)
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(holder), "example.com", wantWorkdir, ".")

_, _ = cov.Run()

Expand All @@ -51,7 +51,7 @@ func TestCoverageRun(t *testing.T) {

func TestCoverageRunFails(t *testing.T) {
t.Parallel()
cov := coverage.NewWithCmdAndPackage(fakeExecCommandFailure, "example.com", "workdir")
cov := coverage.NewWithCmdAndPackage(fakeExecCommandFailure, "example.com", "workdir", "./...")
_, err := cov.Run()
if err == nil {
t.Error("expected run to report an error")
Expand All @@ -60,7 +60,7 @@ func TestCoverageRunFails(t *testing.T) {

func TestCoverageParsesOutput(t *testing.T) {
t.Parallel()
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(nil), "example.com", "testdata/valid")
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(nil), "example.com", "testdata/valid", "./...")
want := coverage.Profile{
"path/file1.go": {
{
Expand Down Expand Up @@ -98,7 +98,7 @@ func TestCoverageParsesOutput(t *testing.T) {

func TestParseOutputFail(t *testing.T) {
t.Parallel()
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(nil), "example.com", "testdata/invalid")
cov := coverage.NewWithCmdAndPackage(fakeExecCommandSuccess(nil), "example.com", "testdata/invalid", "./...")

_, err := cov.Run()
if err == nil {
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ go 1.18

require (
github.com/google/go-cmp v0.5.8 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/spf13/cobra v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/tools v0.1.11 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

0 comments on commit 898fab0

Please sign in to comment.