diff --git a/.github/workflows/fuzz.yaml b/.github/workflows/fuzz.yaml new file mode 100644 index 0000000..05c2a05 --- /dev/null +++ b/.github/workflows/fuzz.yaml @@ -0,0 +1,20 @@ +name: Fuzz Testing +on: + # Perform Fuzz testing on PRs and on a daily basis. Daily will continue to + # look for problems. Doing this on PRs will look for issues introduced in + # a change. + pull_request: + schedule: + - cron: '33 23 * * *' # Run at 11:33 every day +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: "1.20" + - name: Checkout code + uses: actions/checkout@v3 + - name: Fuzz + run: make fuzz diff --git a/Makefile b/Makefile index eac1917..0e7b5c7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ GOPATH=$(shell go env GOPATH) GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint -GOFUZZBUILD = $(GOPATH)/bin/go-fuzz-build -GOFUZZ = $(GOPATH)/bin/go-fuzz .PHONY: lint lint: $(GOLANGCI_LINT) @@ -19,19 +17,14 @@ test-cover: GO111MODULE=on go test -cover . .PHONY: fuzz -fuzz: $(GOFUZZBUILD) $(GOFUZZ) - @echo "==> Fuzz testing" - $(GOFUZZBUILD) - $(GOFUZZ) -workdir=_fuzz +fuzz: + @echo "==> Running Fuzz Tests" + go test -fuzz=FuzzNewVersion -fuzztime=15s . + go test -fuzz=FuzzStrictNewVersion -fuzztime=15s . + go test -fuzz=FuzzNewConstraint -fuzztime=15s . $(GOLANGCI_LINT): # Install golangci-lint. The configuration for it is in the .golangci.yml # file in the root of the repository echo ${GOPATH} curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1 - -$(GOFUZZBUILD): - cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz-build - -$(GOFUZZ): - cd / && go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-dep \ No newline at end of file diff --git a/constraints_test.go b/constraints_test.go index c725a95..c720797 100644 --- a/constraints_test.go +++ b/constraints_test.go @@ -776,3 +776,36 @@ func TestTextUnmarshalConstraints(t *testing.T) { } } } + +func FuzzNewConstraint(f *testing.F) { + testcases := []string{ + "v1.2.3", + " ", + "......", + "1", + "1.2.3-beta.1", + "1.2.3+foo", + "2.3.4-alpha.1+bar", + "lorem ipsum", + "*", + "!=1.2.3", + "^4.5", + "1.0.0 - 2", + "1.2.3.4.5.6", + ">= 1", + "~9.8.7", + "<= 12.13.14", + "987654321.123456789.654123789", + "1.x", + "2.3.x", + "9.2-beta.0", + } + + for _, tc := range testcases { + f.Add(tc) + } + + f.Fuzz(func(t *testing.T, a string) { + _, _ = NewConstraint(a) + }) +} diff --git a/fuzz.go b/fuzz.go deleted file mode 100644 index a242ad7..0000000 --- a/fuzz.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build gofuzz - -package semver - -func Fuzz(data []byte) int { - d := string(data) - - // Test NewVersion - _, _ = NewVersion(d) - - // Test StrictNewVersion - _, _ = StrictNewVersion(d) - - // Test NewConstraint - _, _ = NewConstraint(d) - - // The return value should be 0 normally, 1 if the priority in future tests - // should be increased, and -1 if future tests should skip passing in that - // data. We do not have a reason to change priority so 0 is always returned. - // There are example tests that do this. - return 0 -} diff --git a/version_test.go b/version_test.go index 767dc29..16156dd 100644 --- a/version_test.go +++ b/version_test.go @@ -681,3 +681,27 @@ func TestValidateMetadata(t *testing.T) { } } } + +func FuzzNewVersion(f *testing.F) { + testcases := []string{"v1.2.3", " ", "......", "1", "1.2.3-beta.1", "1.2.3+foo", "2.3.4-alpha.1+bar", "lorem ipsum"} + + for _, tc := range testcases { + f.Add(tc) + } + + f.Fuzz(func(t *testing.T, a string) { + _, _ = NewVersion(a) + }) +} + +func FuzzStrictNewVersion(f *testing.F) { + testcases := []string{"v1.2.3", " ", "......", "1", "1.2.3-beta.1", "1.2.3+foo", "2.3.4-alpha.1+bar", "lorem ipsum"} + + for _, tc := range testcases { + f.Add(tc) + } + + f.Fuzz(func(t *testing.T, a string) { + _, _ = StrictNewVersion(a) + }) +}