match.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package httpexpect
  2. import (
  3. "reflect"
  4. )
  5. // Match provides methods to inspect attached regexp match results.
  6. type Match struct {
  7. chain chain
  8. submatches []string
  9. names map[string]int
  10. }
  11. // NewMatch returns a new Match object given a reporter used to report
  12. // failures and submatches to be inspected.
  13. //
  14. // reporter should not be nil. submatches and names may be nil.
  15. //
  16. // Example:
  17. // s := "http://example.com/users/john"
  18. // r := regexp.MustCompile(`http://(?P<host>.+)/users/(?P<user>.+)`)
  19. // m := NewMatch(reporter, r.FindStringSubmatch(s), r.SubexpNames())
  20. //
  21. // m.NotEmpty()
  22. // m.Length().Equal(3)
  23. //
  24. // m.Index(0).Equal("http://example.com/users/john")
  25. // m.Index(1).Equal("example.com")
  26. // m.Index(2).Equal("john")
  27. //
  28. // m.Name("host").Equal("example.com")
  29. // m.Name("user").Equal("john")
  30. func NewMatch(reporter Reporter, submatches []string, names []string) *Match {
  31. return makeMatch(makeChain(reporter), submatches, names)
  32. }
  33. func makeMatch(chain chain, submatches []string, names []string) *Match {
  34. if submatches == nil {
  35. submatches = []string{}
  36. }
  37. namemap := map[string]int{}
  38. for n, name := range names {
  39. if name != "" {
  40. namemap[name] = n
  41. }
  42. }
  43. return &Match{chain, submatches, namemap}
  44. }
  45. // Raw returns underlying submatches attached to Match.
  46. // This is the value originally passed to NewMatch.
  47. //
  48. // Example:
  49. // m := NewMatch(t, submatches, names)
  50. // assert.Equal(t, submatches, m.Raw())
  51. func (m *Match) Raw() []string {
  52. return m.submatches
  53. }
  54. // Length returns a new Number object that may be used to inspect
  55. // number of submatches.
  56. //
  57. // Example:
  58. // m := NewMatch(t, submatches, names)
  59. // m.Length().Equal(len(submatches))
  60. func (m *Match) Length() *Number {
  61. return &Number{m.chain, float64(len(m.submatches))}
  62. }
  63. // Index returns a new String object that may be used to inspect submatch
  64. // with given index.
  65. //
  66. // Note that submatch with index 0 contains the whole match. If index is out
  67. // of bounds, Index reports failure and returns empty (but non-nil) value.
  68. //
  69. // Example:
  70. // s := "http://example.com/users/john"
  71. //
  72. // r := regexp.MustCompile(`http://(.+)/users/(.+)`)
  73. // m := NewMatch(t, r.FindStringSubmatch(s), nil)
  74. //
  75. // m.Index(0).Equal("http://example.com/users/john")
  76. // m.Index(1).Equal("example.com")
  77. // m.Index(2).Equal("john")
  78. func (m *Match) Index(index int) *String {
  79. if index < 0 || index >= len(m.submatches) {
  80. m.chain.fail(
  81. "\nsubmatch index out of bounds:\n index %d\n\n bounds [%d; %d)",
  82. index,
  83. 0,
  84. len(m.submatches))
  85. return &String{m.chain, ""}
  86. }
  87. return &String{m.chain, m.submatches[index]}
  88. }
  89. // Name returns a new String object that may be used to inspect submatch
  90. // with given name.
  91. //
  92. // If there is no submatch with given name, Name reports failure and returns
  93. // empty (but non-nil) value.
  94. //
  95. // Example:
  96. // s := "http://example.com/users/john"
  97. //
  98. // r := regexp.MustCompile(`http://(?P<host>.+)/users/(?P<user>.+)`)
  99. // m := NewMatch(t, r.FindStringSubmatch(s), r.SubexpNames())
  100. //
  101. // m.Name("host").Equal("example.com")
  102. // m.Name("user").Equal("john")
  103. func (m *Match) Name(name string) *String {
  104. index, ok := m.names[name]
  105. if !ok {
  106. m.chain.fail(
  107. "\nsubmatch name not found:\n %q\n\navailable names:\n%s",
  108. name,
  109. dumpValue(m.names))
  110. return &String{m.chain, ""}
  111. }
  112. return m.Index(index)
  113. }
  114. // Empty succeeds if submatches array is empty.
  115. //
  116. // Example:
  117. // m := NewMatch(t, submatches, names)
  118. // m.Empty()
  119. func (m *Match) Empty() *Match {
  120. if len(m.submatches) != 0 {
  121. m.chain.fail("\nexpected zero submatches, but got:\n %s",
  122. dumpValue(m.submatches))
  123. }
  124. return m
  125. }
  126. // NotEmpty succeeds if submatches array is non-empty.
  127. //
  128. // Example:
  129. // m := NewMatch(t, submatches, names)
  130. // m.NotEmpty()
  131. func (m *Match) NotEmpty() *Match {
  132. if len(m.submatches) == 0 {
  133. m.chain.fail("expected non-zero submatches")
  134. }
  135. return m
  136. }
  137. // Values succeeds if submatches array, starting from index 1, is equal to
  138. // given array.
  139. //
  140. // Note that submatch with index 0 contains the whole match and is not
  141. // included into this check.
  142. //
  143. // Example:
  144. // s := "http://example.com/users/john"
  145. // r := regexp.MustCompile(`http://(.+)/users/(.+)`)
  146. // m := NewMatch(t, r.FindStringSubmatch(s), nil)
  147. // m.Values("example.com", "john")
  148. func (m *Match) Values(values ...string) *Match {
  149. if values == nil {
  150. values = []string{}
  151. }
  152. if !reflect.DeepEqual(values, m.getValues()) {
  153. m.chain.fail("\nexpected submatches equal to:\n%s\n\nbut got:\n%s",
  154. dumpValue(values),
  155. dumpValue(m.getValues()))
  156. }
  157. return m
  158. }
  159. // NotValues succeeds if submatches array, starting from index 1, is not
  160. // equal to given array.
  161. //
  162. // Note that submatch with index 0 contains the whole match and is not
  163. // included into this check.
  164. //
  165. // Example:
  166. // s := "http://example.com/users/john"
  167. // r := regexp.MustCompile(`http://(.+)/users/(.+)`)
  168. // m := NewMatch(t, r.FindStringSubmatch(s), nil)
  169. // m.NotValues("example.com", "bob")
  170. func (m *Match) NotValues(values ...string) *Match {
  171. if values == nil {
  172. values = []string{}
  173. }
  174. if reflect.DeepEqual(values, m.getValues()) {
  175. m.chain.fail("\nexpected submatches not equal to:\n%s",
  176. dumpValue(values))
  177. }
  178. return m
  179. }
  180. func (m *Match) getValues() []string {
  181. if len(m.submatches) > 1 {
  182. return m.submatches[1:]
  183. }
  184. return []string{}
  185. }