321 lines
8.2 KiB
Go
321 lines
8.2 KiB
Go
![]() |
package httpexpect
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// String provides methods to inspect attached string value
|
||
|
// (Go representation of JSON string).
|
||
|
type String struct {
|
||
|
chain chain
|
||
|
value string
|
||
|
}
|
||
|
|
||
|
// NewString returns a new String given a reporter used to report failures
|
||
|
// and value to be inspected.
|
||
|
//
|
||
|
// reporter should not be nil.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
func NewString(reporter Reporter, value string) *String {
|
||
|
return &String{makeChain(reporter), value}
|
||
|
}
|
||
|
|
||
|
// Raw returns underlying value attached to String.
|
||
|
// This is the value originally passed to NewString.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// assert.Equal(t, "Hello", str.Raw())
|
||
|
func (s *String) Raw() string {
|
||
|
return s.value
|
||
|
}
|
||
|
|
||
|
// Path is similar to Value.Path.
|
||
|
func (s *String) Path(path string) *Value {
|
||
|
return getPath(&s.chain, s.value, path)
|
||
|
}
|
||
|
|
||
|
// Schema is similar to Value.Schema.
|
||
|
func (s *String) Schema(schema interface{}) *String {
|
||
|
checkSchema(&s.chain, s.value, schema)
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Length returns a new Number object that may be used to inspect string length.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.Length().Equal(5)
|
||
|
func (s *String) Length() *Number {
|
||
|
return &Number{s.chain, float64(len(s.value))}
|
||
|
}
|
||
|
|
||
|
// DateTime parses date/time from string an returns a new DateTime object.
|
||
|
//
|
||
|
// If layout is given, DateTime() uses time.Parse() with given layout.
|
||
|
// Otherwise, it uses http.ParseTime(). If pasing error occurred,
|
||
|
// DateTime reports failure and returns empty (but non-nil) object.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Tue, 15 Nov 1994 08:12:31 GMT")
|
||
|
// str.DateTime().Lt(time.Now())
|
||
|
//
|
||
|
// str := NewString(t, "15 Nov 94 08:12 GMT")
|
||
|
// str.DateTime(time.RFC822).Lt(time.Now())
|
||
|
func (s *String) DateTime(layout ...string) *DateTime {
|
||
|
if s.chain.failed() {
|
||
|
return &DateTime{s.chain, time.Unix(0, 0)}
|
||
|
}
|
||
|
var (
|
||
|
t time.Time
|
||
|
err error
|
||
|
)
|
||
|
if len(layout) != 0 {
|
||
|
t, err = time.Parse(layout[0], s.value)
|
||
|
} else {
|
||
|
t, err = http.ParseTime(s.value)
|
||
|
}
|
||
|
if err != nil {
|
||
|
s.chain.fail(err.Error())
|
||
|
return &DateTime{s.chain, time.Unix(0, 0)}
|
||
|
}
|
||
|
return &DateTime{s.chain, t}
|
||
|
}
|
||
|
|
||
|
// Empty succeeds if string is empty.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "")
|
||
|
// str.Empty()
|
||
|
func (s *String) Empty() *String {
|
||
|
return s.Equal("")
|
||
|
}
|
||
|
|
||
|
// NotEmpty succeeds if string is non-empty.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.NotEmpty()
|
||
|
func (s *String) NotEmpty() *String {
|
||
|
return s.NotEqual("")
|
||
|
}
|
||
|
|
||
|
// Equal succeeds if string is equal to given Go string.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.Equal("Hello")
|
||
|
func (s *String) Equal(value string) *String {
|
||
|
if !(s.value == value) {
|
||
|
s.chain.fail("\nexpected string equal to:\n %q\n\nbut got:\n %q",
|
||
|
value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// NotEqual succeeds if string is not equal to given Go string.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.NotEqual("Goodbye")
|
||
|
func (s *String) NotEqual(value string) *String {
|
||
|
if !(s.value != value) {
|
||
|
s.chain.fail("\nexpected string not equal to:\n %q", value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// EqualFold succeeds if string is equal to given Go string after applying Unicode
|
||
|
// case-folding (so it's a case-insensitive match).
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.EqualFold("hELLo")
|
||
|
func (s *String) EqualFold(value string) *String {
|
||
|
if !strings.EqualFold(s.value, value) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string equal to (case-insensitive):\n %q\n\nbut got:\n %q",
|
||
|
value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// NotEqualFold succeeds if string is not equal to given Go string after applying
|
||
|
// Unicode case-folding (so it's a case-insensitive match).
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.NotEqualFold("gOODBYe")
|
||
|
func (s *String) NotEqualFold(value string) *String {
|
||
|
if strings.EqualFold(s.value, value) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string not equal to (case-insensitive):\n %q\n\nbut got:\n %q",
|
||
|
value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Contains succeeds if string contains given Go string as a substring.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.Contains("ell")
|
||
|
func (s *String) Contains(value string) *String {
|
||
|
if !strings.Contains(s.value, value) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string containing substring:\n %q\n\nbut got:\n %q",
|
||
|
value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// NotContains succeeds if string doesn't contain Go string as a substring.
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.NotContains("bye")
|
||
|
func (s *String) NotContains(value string) *String {
|
||
|
if strings.Contains(s.value, value) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string not containing substring:\n %q\n\nbut got:\n %q",
|
||
|
value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// ContainsFold succeeds if string contains given Go string as a substring after
|
||
|
// applying Unicode case-folding (so it's a case-insensitive match).
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.ContainsFold("ELL")
|
||
|
func (s *String) ContainsFold(value string) *String {
|
||
|
if !strings.Contains(strings.ToLower(s.value), strings.ToLower(value)) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string containing substring (case-insensitive):\n %q"+
|
||
|
"\n\nbut got:\n %q", value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// NotContainsFold succeeds if string doesn't contain given Go string as a substring
|
||
|
// after applying Unicode case-folding (so it's a case-insensitive match).
|
||
|
//
|
||
|
// Example:
|
||
|
// str := NewString(t, "Hello")
|
||
|
// str.NotContainsFold("BYE")
|
||
|
func (s *String) NotContainsFold(value string) *String {
|
||
|
if strings.Contains(strings.ToLower(s.value), strings.ToLower(value)) {
|
||
|
s.chain.fail(
|
||
|
"\nexpected string not containing substring (case-insensitive):\n %q"+
|
||
|
"\n\nbut got:\n %q", value, s.value)
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Match matches the string with given regexp and returns a new Match object
|
||
|
// with found submatches.
|
||
|
//
|
||
|
// If regexp is invalid or string doesn't match regexp, Match fails and returns
|
||
|
// empty (but non-nil) object. regexp.Compile is used to construct regexp, and
|
||
|
// Regexp.FindStringSubmatch is used to construct matches.
|
||
|
//
|
||
|
// Example:
|
||
|
// s := NewString(t, "http://example.com/users/john")
|
||
|
// m := s.Match(`http://(?P<host>.+)/users/(?P<user>.+)`)
|
||
|
//
|
||
|
// m.NotEmpty()
|
||
|
// m.Length().Equal(3)
|
||
|
//
|
||
|
// m.Index(0).Equal("http://example.com/users/john")
|
||
|
// m.Index(1).Equal("example.com")
|
||
|
// m.Index(2).Equal("john")
|
||
|
//
|
||
|
// m.Name("host").Equal("example.com")
|
||
|
// m.Name("user").Equal("john")
|
||
|
func (s *String) Match(re string) *Match {
|
||
|
r, err := regexp.Compile(re)
|
||
|
if err != nil {
|
||
|
s.chain.fail(err.Error())
|
||
|
return makeMatch(s.chain, nil, nil)
|
||
|
}
|
||
|
|
||
|
m := r.FindStringSubmatch(s.value)
|
||
|
if m == nil {
|
||
|
s.chain.fail("\nexpected string matching regexp:\n `%s`\n\nbut got:\n %q",
|
||
|
re, s.value)
|
||
|
return makeMatch(s.chain, nil, nil)
|
||
|
}
|
||
|
|
||
|
return makeMatch(s.chain, m, r.SubexpNames())
|
||
|
}
|
||
|
|
||
|
// MatchAll find all matches in string for given regexp and returns a list
|
||
|
// of found matches.
|
||
|
//
|
||
|
// If regexp is invalid or string doesn't match regexp, MatchAll fails and
|
||
|
// returns empty (but non-nil) slice. regexp.Compile is used to construct
|
||
|
// regexp, and Regexp.FindAllStringSubmatch is used to find matches.
|
||
|
//
|
||
|
// Example:
|
||
|
// s := NewString(t,
|
||
|
// "http://example.com/users/john http://example.com/users/bob")
|
||
|
//
|
||
|
// m := s.MatchAll(`http://(?P<host>\S+)/users/(?P<user>\S+)`)
|
||
|
//
|
||
|
// m[0].Name("user").Equal("john")
|
||
|
// m[1].Name("user").Equal("bob")
|
||
|
func (s *String) MatchAll(re string) []Match {
|
||
|
r, err := regexp.Compile(re)
|
||
|
if err != nil {
|
||
|
s.chain.fail(err.Error())
|
||
|
return []Match{}
|
||
|
}
|
||
|
|
||
|
matches := r.FindAllStringSubmatch(s.value, -1)
|
||
|
if matches == nil {
|
||
|
s.chain.fail("\nexpected string matching regexp:\n `%s`\n\nbut got:\n %q",
|
||
|
re, s.value)
|
||
|
return []Match{}
|
||
|
}
|
||
|
|
||
|
ret := []Match{}
|
||
|
for _, m := range matches {
|
||
|
ret = append(ret, *makeMatch(
|
||
|
s.chain,
|
||
|
m,
|
||
|
r.SubexpNames()))
|
||
|
}
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
// NotMatch succeeds if the string doesn't match to given regexp.
|
||
|
//
|
||
|
// regexp.Compile is used to construct regexp, and Regexp.MatchString
|
||
|
// is used to perform match.
|
||
|
//
|
||
|
// Example:
|
||
|
// s := NewString(t, "a")
|
||
|
// s.NotMatch(`[^a]`)
|
||
|
func (s *String) NotMatch(re string) *String {
|
||
|
r, err := regexp.Compile(re)
|
||
|
if err != nil {
|
||
|
s.chain.fail(err.Error())
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
if r.MatchString(s.value) {
|
||
|
s.chain.fail("\nexpected string not matching regexp:\n `%s`\n\nbut got:\n %q",
|
||
|
re, s.value)
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
return s
|
||
|
}
|