Skip to content

Commit

Permalink
add benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
nieomylnieja committed Oct 13, 2024
1 parent ead6d15 commit 450130c
Show file tree
Hide file tree
Showing 18 changed files with 1,604 additions and 843 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ test:
$(call _print_step,Running unit tests)
go test -race -cover ./... ./docs/validator-comparison/...

.PHONY: test/benchmark
## Run benchmark tests.
test/benchmark:
$(call _print_step,Running benchmark tests)
go test -bench=. -benchmem ./...

.PHONY: test/coverage
## Produce test coverage report and inspect it in browser.
test/coverage:
Expand Down
33 changes: 25 additions & 8 deletions internal/assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,25 @@ func NoError(t *testing.T, err error) bool {
}

// EqualError fails the test if the expected error is not equal to the actual error message.
func EqualError(t *testing.T, expected error, actual string) bool {
func EqualError(t *testing.T, err error, expected string) bool {
t.Helper()
if !Error(t, expected) {
if !Error(t, err) {
return false
}
if expected.Error() != actual {
return fail(t, "Expected error message: %q, actual: %q", expected.Error(), actual)
if err.Error() != expected {
return fail(t, "Expected error message: %q, actual: %q", expected, err.Error())
}
return true
}

// ErrorContains fails the test if the expected error does not contain the provided string.
func ErrorContains(t *testing.T, expected error, contains string) bool {
func ErrorContains(t *testing.T, err error, contains string) bool {
t.Helper()
if !Error(t, expected) {
if !Error(t, err) {
return false
}
if !strings.Contains(expected.Error(), contains) {
return fail(t, "Expected error message to contain %q, actual %q", contains, expected.Error())
if !strings.Contains(err.Error(), contains) {
return fail(t, "Expected error message to contain %q, actual %q", contains, err.Error())
}
return true
}
Expand Down Expand Up @@ -140,6 +140,23 @@ func ElementsMatch[T comparable](t *testing.T, expected, actual []T) bool {
return true
}

// Panic checks that the function panics with the expected message.
func Panic(t *testing.T, f func(), expected string) (result bool) {
t.Helper()

defer func() {
r := recover()
if r == nil {
result = fail(t, "Function did not panic")
return
}
result = Equal(t, expected, r)
}()

f()
return false
}

func areEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
Expand Down
12 changes: 6 additions & 6 deletions pkg/rules/comparable.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/nobl9/govy/pkg/govy"
)

// EQ ensures the property's value is equal to the compared value.
// EQ ensures the property's in is equal to the compared in.
func EQ[T comparable](compared T) govy.Rule[T] {
msg := fmt.Sprintf(comparisonFmt, cmpEqualTo, compared)
return govy.NewRule(func(v T) error {
Expand All @@ -22,7 +22,7 @@ func EQ[T comparable](compared T) govy.Rule[T] {
WithDescription(msg)
}

// NEQ ensures the property's value is not equal to the compared value.
// NEQ ensures the property's in is not equal to the compared in.
func NEQ[T comparable](compared T) govy.Rule[T] {
msg := fmt.Sprintf(comparisonFmt, cmpNotEqualTo, compared)
return govy.NewRule(func(v T) error {
Expand All @@ -35,25 +35,25 @@ func NEQ[T comparable](compared T) govy.Rule[T] {
WithDescription(msg)
}

// GT ensures the property's value is greater than the compared value.
// GT ensures the property's in is greater than the compared in.
func GT[T constraints.Ordered](compared T) govy.Rule[T] {
return orderedComparisonRule(cmpGreaterThan, compared).
WithErrorCode(ErrorCodeGreaterThan)
}

// GTE ensures the property's value is greater than or equal to the compared value.
// GTE ensures the property's in is greater than or equal to the compared in.
func GTE[T constraints.Ordered](compared T) govy.Rule[T] {
return orderedComparisonRule(cmpGreaterThanOrEqual, compared).
WithErrorCode(ErrorCodeGreaterThanOrEqualTo)
}

// LT ensures the property's value is less than the compared value.
// LT ensures the property's in is less than the compared in.
func LT[T constraints.Ordered](compared T) govy.Rule[T] {
return orderedComparisonRule(cmpLessThan, compared).
WithErrorCode(ErrorCodeLessThan)
}

// LTE ensures the property's value is less than or equal to the compared value.
// LTE ensures the property's in is less than or equal to the compared in.
func LTE[T constraints.Ordered](compared T) govy.Rule[T] {
return orderedComparisonRule(cmpLessThanOrEqual, compared).
WithErrorCode(ErrorCodeLessThanOrEqualTo)
Expand Down
215 changes: 156 additions & 59 deletions pkg/rules/comparable_test.go
Original file line number Diff line number Diff line change
@@ -1,96 +1,193 @@
package rules

import (
"fmt"
"testing"

"github.com/nobl9/govy/internal/assert"

"github.com/nobl9/govy/pkg/govy"
)

var eqTestCases = []*struct {
value any
input any
expectedError string
}{
{value: 1, input: 1},
{value: 1.1, input: 1.3, expectedError: "should be equal to '1.1'"},
}

func TestEQ(t *testing.T) {
t.Run("passes", func(t *testing.T) {
err := EQ(1.1).Validate(1.1)
assert.NoError(t, err)
})
t.Run("fails", func(t *testing.T) {
err := EQ(1.1).Validate(1.3)
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, "should be equal to '1.1'")
assert.True(t, govy.HasErrorCode(err, ErrorCodeEqualTo))
})
for _, tc := range eqTestCases {
err := EQ(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeEqualTo))
} else {
assert.NoError(t, err)
}
}
}

func BenchmarkEQ(b *testing.B) {
for range b.N {
for _, tc := range eqTestCases {
_ = EQ(tc.value).Validate(tc.input)
}
}
}

var neqTestCases = []*struct {
value any
input any
expectedError string
}{
{value: 1.1, input: 1.3},
{value: 1.1, input: 1.1, expectedError: "should be not equal to '1.1'"},
}

func TestNEQ(t *testing.T) {
t.Run("passes", func(t *testing.T) {
err := NEQ(1.1).Validate(1.3)
assert.NoError(t, err)
})
t.Run("fails", func(t *testing.T) {
err := NEQ(1.1).Validate(1.1)
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, "should be not equal to '1.1'")
assert.True(t, govy.HasErrorCode(err, ErrorCodeNotEqualTo))
})
for _, tc := range neqTestCases {
err := NEQ(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeNotEqualTo))
} else {
assert.NoError(t, err)
}
}
}

func BenchmarkNEQ(b *testing.B) {
for range b.N {
for _, tc := range neqTestCases {
_ = NEQ(tc.value).Validate(tc.input)
}
}
}

var gtTestCases = []*struct {
value int
input int
expectedError string
}{
{value: 1, input: 2},
{value: 1, input: 1, expectedError: "should be greater than '1'"},
{value: 4, input: 2, expectedError: "should be greater than '4'"},
}

func TestGT(t *testing.T) {
t.Run("passes", func(t *testing.T) {
err := GT(1).Validate(2)
assert.NoError(t, err)
})
t.Run("fails", func(t *testing.T) {
for n, v := range map[int]int{1: 1, 4: 2} {
err := GT(n).Validate(v)
for _, tc := range gtTestCases {
err := GT(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, fmt.Sprintf("should be greater than '%v'", n))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeGreaterThan))
} else {
assert.NoError(t, err)
}
}
}

func BenchmarkGT(b *testing.B) {
for range b.N {
for _, tc := range gtTestCases {
_ = GT(tc.value).Validate(tc.input)
}
})
}
}

var gteTestCases = []*struct {
value int
input int
expectedError string
}{
{value: 1, input: 1},
{value: 2, input: 4},
{value: 4, input: 2, expectedError: "should be greater than or equal to '4'"},
}

func TestGTE(t *testing.T) {
t.Run("passes", func(t *testing.T) {
for n, v := range map[int]int{1: 1, 2: 4} {
err := GTE(n).Validate(v)
for _, tc := range gteTestCases {
err := GTE(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeGreaterThanOrEqualTo))
} else {
assert.NoError(t, err)
}
})
t.Run("fails", func(t *testing.T) {
err := GTE(4).Validate(2)
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, "should be greater than or equal to '4'")
assert.True(t, govy.HasErrorCode(err, ErrorCodeGreaterThanOrEqualTo))
})
}
}

func BenchmarkGTE(b *testing.B) {
for range b.N {
for _, tc := range gteTestCases {
_ = GTE(tc.value).Validate(tc.input)
}
}
}

var ltTestCases = []*struct {
value int
input int
expectedError string
}{
{value: 4, input: 2},
{value: 1, input: 1, expectedError: "should be less than '1'"},
{value: 2, input: 4, expectedError: "should be less than '2'"},
}

func TestLT(t *testing.T) {
t.Run("passes", func(t *testing.T) {
err := LT(4).Validate(2)
assert.NoError(t, err)
})
t.Run("fails", func(t *testing.T) {
for n, v := range map[int]int{1: 1, 2: 4} {
err := LT(n).Validate(v)
for _, tc := range ltTestCases {
err := LT(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, fmt.Sprintf("should be less than '%v'", n))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeLessThan))
} else {
assert.NoError(t, err)
}
})
}
}

func BenchmarkLT(b *testing.B) {
for range b.N {
for _, tc := range ltTestCases {
_ = LT(tc.value).Validate(tc.input)
}
}
}

var lteTestCases = []*struct {
value int
input int
expectedError string
}{
{value: 1, input: 1},
{value: 4, input: 2},
{value: 2, input: 4, expectedError: "should be less than or equal to '2'"},
}

func TestLTE(t *testing.T) {
t.Run("passes", func(t *testing.T) {
for n, v := range map[int]int{1: 1, 4: 2} {
err := LTE(n).Validate(v)
for _, tc := range lteTestCases {
err := LTE(tc.value).Validate(tc.input)
if tc.expectedError != "" {
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, tc.expectedError)
assert.True(t, govy.HasErrorCode(err, ErrorCodeLessThanOrEqualTo))
} else {
assert.NoError(t, err)
}
})
t.Run("fails", func(t *testing.T) {
err := LTE(2).Validate(4)
assert.Require(t, assert.Error(t, err))
assert.EqualError(t, err, "should be less than or equal to '2'")
assert.True(t, govy.HasErrorCode(err, ErrorCodeLessThanOrEqualTo))
})
}
}

func BenchmarkLTE(b *testing.B) {
for range b.N {
for _, tc := range lteTestCases {
_ = LTE(tc.value).Validate(tc.input)
}
}
}
Loading

0 comments on commit 450130c

Please sign in to comment.