-
-
Notifications
You must be signed in to change notification settings - Fork 281
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- implements new HaveExistingField matcher, fixing #548. - modifies existing extractField helper from HaveField for reuse with HaveExistingField - adds new unit tests for HaveExistingField matcher - updates documentation
- Loading branch information
Showing
5 changed files
with
168 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
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,36 @@ | ||
package matchers | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/onsi/gomega/format" | ||
) | ||
|
||
type HaveExistingFieldMatcher struct { | ||
Field string | ||
} | ||
|
||
func (matcher *HaveExistingFieldMatcher) Match(actual interface{}) (success bool, err error) { | ||
// we don't care about the field's actual value, just about any error in | ||
// trying to find the field (or method). | ||
_, err = extractField(actual, matcher.Field, "HaveExistingField") | ||
if err == nil { | ||
return true, nil | ||
} | ||
var mferr missingFieldError | ||
if errors.As(err, &mferr) { | ||
// missing field errors aren't errors in this context, but instead | ||
// unsuccessful matches. | ||
return false, nil | ||
} | ||
return false, err | ||
} | ||
|
||
func (matcher *HaveExistingFieldMatcher) FailureMessage(actual interface{}) (message string) { | ||
return fmt.Sprintf("Expected\n%s\nto have field '%s'", format.Object(actual, 1), matcher.Field) | ||
} | ||
|
||
func (matcher *HaveExistingFieldMatcher) NegatedFailureMessage(actual interface{}) (message string) { | ||
return fmt.Sprintf("Expected\n%s\nnot to have field '%s'", format.Object(actual, 1), matcher.Field) | ||
} |
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,84 @@ | ||
package matchers_test | ||
|
||
import ( | ||
"time" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("HaveExistingField", func() { | ||
|
||
var book Book | ||
BeforeEach(func() { | ||
book = Book{ | ||
Title: "Les Miserables", | ||
Author: person{ | ||
FirstName: "Victor", | ||
LastName: "Hugo", | ||
DOB: time.Date(1802, 2, 26, 0, 0, 0, 0, time.UTC), | ||
}, | ||
Pages: 2783, | ||
Sequel: &Book{ | ||
Title: "Les Miserables 2", | ||
}, | ||
} | ||
}) | ||
|
||
DescribeTable("traversing the struct works", | ||
func(field string) { | ||
Ω(book).Should(HaveExistingField(field)) | ||
}, | ||
Entry("Top-level field", "Title"), | ||
Entry("Nested field", "Author.FirstName"), | ||
Entry("Top-level method", "AuthorName()"), | ||
Entry("Nested method", "Author.DOB.Year()"), | ||
Entry("Traversing past a method", "AbbreviatedAuthor().FirstName"), | ||
Entry("Traversing a pointer", "Sequel.Title"), | ||
) | ||
|
||
DescribeTable("negation works", | ||
func(field string) { | ||
Ω(book).ShouldNot(HaveExistingField(field)) | ||
}, | ||
Entry("Top-level field", "Class"), | ||
Entry("Nested field", "Author.Class"), | ||
Entry("Top-level method", "ClassName()"), | ||
Entry("Nested method", "Author.DOB.BOT()"), | ||
Entry("Traversing past a method", "AbbreviatedAuthor().LastButOneName"), | ||
Entry("Traversing a pointer", "Sequel.Titles"), | ||
) | ||
|
||
It("errors appropriately", func() { | ||
success, err := HaveExistingField("Pages.Count").Match(book) | ||
Ω(success).Should(BeFalse()) | ||
Ω(err.Error()).Should(Equal("HaveExistingField encountered:\n <int>: 2783\nWhich is not a struct.")) | ||
|
||
success, err = HaveExistingField("Prequel.Title").Match(book) | ||
Ω(success).Should(BeFalse()) | ||
Ω(err.Error()).Should(ContainSubstring("HaveExistingField encountered nil while dereferencing a pointer of type *matchers_test.Book.")) | ||
|
||
success, err = HaveExistingField("HasArg()").Match(book) | ||
Ω(success).Should(BeFalse()) | ||
Ω(err.Error()).Should(ContainSubstring("HaveExistingField found an invalid method named 'HasArg()' in struct of type matchers_test.Book.\nMethods must take no arguments and return exactly one value.")) | ||
}) | ||
|
||
It("renders failure messages", func() { | ||
matcher := HaveExistingField("Turtle") | ||
success, err := matcher.Match(book) | ||
Ω(success).Should(BeFalse()) | ||
Ω(err).ShouldNot(HaveOccurred()) | ||
|
||
msg := matcher.FailureMessage(book) | ||
Ω(msg).Should(MatchRegexp(`(?s)Expected\n\s+<matchers_test\.Book>: .*\nto have field 'Turtle'`)) | ||
|
||
matcher = HaveExistingField("Title") | ||
success, err = matcher.Match(book) | ||
Ω(success).Should(BeTrue()) | ||
Ω(err).ShouldNot(HaveOccurred()) | ||
|
||
msg = matcher.NegatedFailureMessage(book) | ||
Ω(msg).Should(MatchRegexp(`(?s)Expected\n\s+<matchers_test\.Book>: .*\nnot to have field 'Title'`)) | ||
}) | ||
|
||
}) |
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