Skip to content

Commit

Permalink
Merge branch 'master' into contains-bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
nickajacks1 authored Jun 8, 2024
2 parents f301cfc + 1b4fca7 commit c723164
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ jobs:
uses: actions/checkout@v4

- name: Create GitHub release from tag
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
23 changes: 20 additions & 3 deletions assert/assertion_format.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 40 additions & 6 deletions assert/assertion_forward.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 47 additions & 6 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import (

"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
"gopkg.in/yaml.v3"

// Wrapper around gopkg.in/yaml.v3
"github.com/stretchr/testify/assert/yaml"
)

//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
Expand Down Expand Up @@ -576,8 +578,8 @@ func truncatingFormat(data interface{}) string {
return value
}

// EqualValues asserts that two objects are equal or convertible to the same types
// and equal.
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
Expand Down Expand Up @@ -1184,6 +1186,39 @@ func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) stri
return msg.String()
}

// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
//
// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isEmpty(listA) && isEmpty(listB) {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}

if !isList(t, listA, msgAndArgs...) {
return Fail(t, "listA is not a list type", msgAndArgs...)
}
if !isList(t, listB, msgAndArgs...) {
return Fail(t, "listB is not a list type", msgAndArgs...)
}

extraA, extraB := diffLists(listA, listB)
if len(extraA) == 0 && len(extraB) == 0 {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}

return true
}

// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
Expand Down Expand Up @@ -1625,15 +1660,21 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in

// matchRegexp return true if a specified regexp matches a string.
func matchRegexp(rx interface{}, str interface{}) bool {

var r *regexp.Regexp
if rr, ok := rx.(*regexp.Regexp); ok {
r = rr
} else {
r = regexp.MustCompile(fmt.Sprint(rx))
}

return (r.FindStringIndex(fmt.Sprint(str)) != nil)
switch v := str.(type) {
case []byte:
return r.Match(v)
case string:
return r.MatchString(v)
default:
return r.MatchString(fmt.Sprint(v))
}

}

Expand Down Expand Up @@ -1965,7 +2006,7 @@ func (*CollectT) Copy(TestingT) {
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
Expand Down
51 changes: 51 additions & 0 deletions assert/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,52 @@ func TestDiffLists(t *testing.T) {
}
}

func TestNotElementsMatch(t *testing.T) {
mockT := new(testing.T)

cases := []struct {
expected interface{}
actual interface{}
result bool
}{
// not mathing
{[]int{1}, []int{}, true},
{[]int{}, []int{2}, true},
{[]int{1}, []int{2}, true},
{[]int{1}, []int{1, 1}, true},
{[]int{1, 2}, []int{3, 4}, true},
{[]int{3, 4}, []int{1, 2}, true},
{[]int{1, 1, 2, 3}, []int{1, 2, 3}, true},
{[]string{"hello"}, []string{"world"}, true},
{[]string{"hello", "hello"}, []string{"world", "world"}, true},
{[3]string{"hello", "hello", "hello"}, [3]string{"world", "world", "world"}, true},

// matching
{nil, nil, false},
{[]int{}, nil, false},
{[]int{}, []int{}, false},
{[]int{1}, []int{1}, false},
{[]int{1, 1}, []int{1, 1}, false},
{[]int{1, 2}, []int{2, 1}, false},
{[2]int{1, 2}, [2]int{2, 1}, false},
{[]int{1, 1, 2}, []int{1, 2, 1}, false},
{[]string{"hello", "world"}, []string{"world", "hello"}, false},
{[]string{"hello", "hello"}, []string{"hello", "hello"}, false},
{[]string{"hello", "hello", "world"}, []string{"hello", "world", "hello"}, false},
{[3]string{"hello", "hello", "world"}, [3]string{"hello", "world", "hello"}, false},
}

for _, c := range cases {
t.Run(fmt.Sprintf("NotElementsMatch(%#v, %#v)", c.expected, c.actual), func(t *testing.T) {
res := NotElementsMatch(mockT, c.actual, c.expected)

if res != c.result {
t.Errorf("NotElementsMatch(%#v, %#v) should return %v", c.actual, c.expected, c.result)
}
})
}
}

func TestCondition(t *testing.T) {
mockT := new(testing.T)

Expand Down Expand Up @@ -1986,13 +2032,16 @@ func TestRegexp(t *testing.T) {
}{
{"^start", "start of the line"},
{"end$", "in the end"},
{"end$", "in the end"},
{"[0-9]{3}[.-]?[0-9]{2}[.-]?[0-9]{2}", "My phone number is 650.12.34"},
}

for _, tc := range cases {
True(t, Regexp(mockT, tc.rx, tc.str))
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
True(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str)))
False(t, NotRegexp(mockT, tc.rx, tc.str))
False(t, NotRegexp(mockT, tc.rx, []byte(tc.str)))
False(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
}

Expand All @@ -2007,7 +2056,9 @@ func TestRegexp(t *testing.T) {
for _, tc := range cases {
False(t, Regexp(mockT, tc.rx, tc.str), "Expected \"%s\" to not match \"%s\"", tc.rx, tc.str)
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), tc.str))
False(t, Regexp(mockT, regexp.MustCompile(tc.rx), []byte(tc.str)))
True(t, NotRegexp(mockT, tc.rx, tc.str))
True(t, NotRegexp(mockT, tc.rx, []byte(tc.str)))
True(t, NotRegexp(mockT, regexp.MustCompile(tc.rx), tc.str))
}
}
Expand Down
25 changes: 25 additions & 0 deletions assert/yaml/yaml_custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
// +build testify_yaml_custom,!testify_yaml_fail,!testify_yaml_default

// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
//
// This implementation is selected with the testify_yaml_custom build tag.
//
// go test -tags testify_yaml_custom
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3].
//
// In your test package:
//
// import assertYaml "github.com/stretchr/testify/assert/yaml"
//
// func init() {
// assertYaml.Unmarshall = func (in []byte, out interface{}) error {
// // ...
// return nil
// }
// }
package yaml

var Unmarshal func(in []byte, out interface{}) error
37 changes: 37 additions & 0 deletions assert/yaml/yaml_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//go:build !testify_yaml_fail && !testify_yaml_custom
// +build !testify_yaml_fail,!testify_yaml_custom

// Package yaml is just an indirection to handle YAML deserialization.
//
// This package is just an indirection that allows the builder to override the
// indirection with an alternative implementation of this package that uses
// another implemantation of YAML deserialization. This allows to not either not
// use YAML deserialization at all, or to use another implementation than
// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
//
// Alternative implementations are selected using build tags:
//
// - testify_yaml_fail: [Unmarshal] always fails with an error
// - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
// before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
// [github.com/stretchr/testify/assert.YAMLEqf].
//
// Usage:
//
// go test -tags testify_yaml_fail
//
// You can check with "go list" which implementation is linked:
//
// go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
//
// [PR #1120]: https://github.com/stretchr/testify/pull/1120
package yaml

import goyaml "gopkg.in/yaml.v3"

// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
func Unmarshal(in []byte, out interface{}) error {
return goyaml.Unmarshal(in, out)
}
18 changes: 18 additions & 0 deletions assert/yaml/yaml_fail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
// +build testify_yaml_fail,!testify_yaml_custom,!testify_yaml_default

// Package yaml is an implementation of YAML functions that always fail.
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3]:
//
// go test -tags testify_yaml_fail
package yaml

import "errors"

var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")

func Unmarshal([]byte, interface{}) error {
return errNotImplemented
}
Loading

0 comments on commit c723164

Please sign in to comment.