...

Source file src/github.com/onsi/gomega/matchers/have_field_test.go

Documentation: github.com/onsi/gomega/matchers

     1  package matchers_test
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	. "github.com/onsi/ginkgo/v2"
     8  	. "github.com/onsi/gomega"
     9  )
    10  
    11  type Book struct {
    12  	Title   string
    13  	Author  person
    14  	Pages   int
    15  	Sequel  *Book
    16  	Prequel *Book
    17  }
    18  
    19  func (book Book) AuthorName() string {
    20  	return fmt.Sprintf("%s %s", book.Author.FirstName, book.Author.LastName)
    21  }
    22  
    23  func (book Book) AbbreviatedAuthor() person {
    24  	return person{
    25  		FirstName: book.Author.FirstName[0:3],
    26  		LastName:  book.Author.LastName[0:3],
    27  		DOB:       book.Author.DOB,
    28  	}
    29  }
    30  
    31  func (book Book) ReceiverTitle() string {
    32  	return book.Title
    33  }
    34  
    35  func (book *Book) PointerReceiverTitle() string {
    36  	return book.Title
    37  }
    38  
    39  func (book Book) NoReturn() {
    40  }
    41  
    42  func (book Book) TooManyReturn() (string, error) {
    43  	return "", nil
    44  }
    45  
    46  func (book Book) HasArg(arg string) string {
    47  	return arg
    48  }
    49  
    50  type person struct {
    51  	FirstName string
    52  	LastName  string
    53  	DOB       time.Time
    54  }
    55  
    56  var _ = Describe("HaveField", func() {
    57  	var book Book
    58  	BeforeEach(func() {
    59  		book = Book{
    60  			Title: "Les Miserables",
    61  			Author: person{
    62  				FirstName: "Victor",
    63  				LastName:  "Hugo",
    64  				DOB:       time.Date(1802, 2, 26, 0, 0, 0, 0, time.UTC),
    65  			},
    66  			Pages: 2783,
    67  			Sequel: &Book{
    68  				Title: "Les Miserables 2",
    69  			},
    70  		}
    71  	})
    72  
    73  	DescribeTable("traversing the struct works",
    74  		func(field string, expected interface{}) {
    75  			Ω(book).Should(HaveField(field, expected))
    76  		},
    77  		Entry("Top-level field with default submatcher", "Title", "Les Miserables"),
    78  		Entry("Top-level field with custom submatcher", "Title", ContainSubstring("Les Mis")),
    79  		Entry("Nested field", "Author.FirstName", "Victor"),
    80  		Entry("Top-level method", "AuthorName()", "Victor Hugo"),
    81  		Entry("Nested method", "Author.DOB.Year()", BeNumerically("<", 1900)),
    82  		Entry("Traversing past a method", "AbbreviatedAuthor().FirstName", Equal("Vic")),
    83  		Entry("Traversing a pointer", "Sequel.Title", "Les Miserables 2"),
    84  	)
    85  
    86  	DescribeTable("negation works",
    87  		func(field string, expected interface{}) {
    88  			Ω(book).ShouldNot(HaveField(field, expected))
    89  		},
    90  		Entry("Top-level field with default submatcher", "Title", "Les Mis"),
    91  		Entry("Top-level field with custom submatcher", "Title", ContainSubstring("Notre Dame")),
    92  		Entry("Nested field", "Author.FirstName", "Hugo"),
    93  		Entry("Top-level method", "AuthorName()", "Victor M. Hugo"),
    94  		Entry("Nested method", "Author.DOB.Year()", BeNumerically(">", 1900)),
    95  		Entry("Traversing a pointer", "Sequel.Title", "Les Mis 2"),
    96  	)
    97  
    98  	Describe("when field lookup fails", func() {
    99  		It("errors appropriately", func() {
   100  			success, err := HaveField("BookName", "Les Miserables").Match(book)
   101  			Ω(success).Should(BeFalse())
   102  			Ω(err.Error()).Should(ContainSubstring("HaveField could not find field named '%s' in struct:", "BookName"))
   103  
   104  			success, err = HaveField("BookName", "Les Miserables").Match(book)
   105  			Ω(success).Should(BeFalse())
   106  			Ω(err.Error()).Should(ContainSubstring("HaveField could not find field named '%s' in struct:", "BookName"))
   107  
   108  			success, err = HaveField("AuthorName", "Victor Hugo").Match(book)
   109  			Ω(success).Should(BeFalse())
   110  			Ω(err.Error()).Should(ContainSubstring("HaveField could not find field named '%s' in struct:", "AuthorName"))
   111  
   112  			success, err = HaveField("Title()", "Les Miserables").Match(book)
   113  			Ω(success).Should(BeFalse())
   114  			Ω(err.Error()).Should(ContainSubstring("HaveField could not find method named '%s' in struct of type matchers_test.Book.", "Title()"))
   115  
   116  			success, err = HaveField("NoReturn()", "Les Miserables").Match(book)
   117  			Ω(success).Should(BeFalse())
   118  			Ω(err.Error()).Should(ContainSubstring("HaveField found an invalid method named 'NoReturn()' in struct of type matchers_test.Book.\nMethods must take no arguments and return exactly one value."))
   119  
   120  			success, err = HaveField("TooManyReturn()", "Les Miserables").Match(book)
   121  			Ω(success).Should(BeFalse())
   122  			Ω(err.Error()).Should(ContainSubstring("HaveField found an invalid method named 'TooManyReturn()' in struct of type matchers_test.Book.\nMethods must take no arguments and return exactly one value."))
   123  
   124  			success, err = HaveField("HasArg()", "Les Miserables").Match(book)
   125  			Ω(success).Should(BeFalse())
   126  			Ω(err.Error()).Should(ContainSubstring("HaveField found an invalid method named 'HasArg()' in struct of type matchers_test.Book.\nMethods must take no arguments and return exactly one value."))
   127  
   128  			success, err = HaveField("Pages.Count", 2783).Match(book)
   129  			Ω(success).Should(BeFalse())
   130  			Ω(err.Error()).Should(Equal("HaveField encountered:\n    <int>: 2783\nWhich is not a struct."))
   131  
   132  			success, err = HaveField("Author.Abbreviation", "Vic").Match(book)
   133  			Ω(success).Should(BeFalse())
   134  			Ω(err.Error()).Should(ContainSubstring("HaveField could not find field named '%s' in struct:", "Abbreviation"))
   135  
   136  			success, err = HaveField("Prequel.Title", "Les Miserables 0").Match(book)
   137  			Ω(success).Should(BeFalse())
   138  			Ω(err.Error()).Should(ContainSubstring("HaveField encountered nil while dereferencing a pointer of type *matchers_test.Book."))
   139  		})
   140  	})
   141  
   142  	Describe("Failure Messages", func() {
   143  		It("renders the underlying matcher failure", func() {
   144  			matcher := HaveField("Title", "Les Mis")
   145  			success, err := matcher.Match(book)
   146  			Ω(success).Should(BeFalse())
   147  			Ω(err).ShouldNot(HaveOccurred())
   148  
   149  			msg := matcher.FailureMessage(book)
   150  			Ω(msg).Should(Equal("Value for field 'Title' failed to satisfy matcher.\nExpected\n    <string>: Les Miserables\nto equal\n    <string>: Les Mis"))
   151  
   152  			matcher = HaveField("Title", "Les Miserables")
   153  			success, err = matcher.Match(book)
   154  			Ω(success).Should(BeTrue())
   155  			Ω(err).ShouldNot(HaveOccurred())
   156  
   157  			msg = matcher.NegatedFailureMessage(book)
   158  			Ω(msg).Should(Equal("Value for field 'Title' satisfied matcher, but should not have.\nExpected\n    <string>: Les Miserables\nnot to equal\n    <string>: Les Miserables"))
   159  		})
   160  	})
   161  
   162  	Describe("receiver lookup", func() {
   163  		DescribeTable("(pointer) receiver lookup works",
   164  			func(field string, expected interface{}) {
   165  				Ω(&book).Should(HaveField(field, expected))
   166  			},
   167  			Entry("non-pointer receiver", "ReceiverTitle()", "Les Miserables"),
   168  			Entry("pointer receiver", "PointerReceiverTitle()", "Les Miserables"),
   169  		)
   170  
   171  		It("correctly fails", func() {
   172  			matcher := HaveField("ReceiverTitle()", "Les Miserables")
   173  			answer := struct{}{}
   174  			Ω(matcher.Match(answer)).Error().Should(MatchError(
   175  				"HaveField could not find method named 'ReceiverTitle()' in struct of type struct {}."))
   176  
   177  			matcher = HaveField("PointerReceiverTitle()", "Les Miserables")
   178  			Ω(matcher.Match(book)).Error().Should(MatchError(
   179  				"HaveField could not find method named 'PointerReceiverTitle()' in struct of type matchers_test.Book."))
   180  		})
   181  	})
   182  
   183  })
   184  

View as plain text