Repository: gavv/httpexpect (go)

Issue:
Implement String.IsAscii
Implement new assertion `String.IsAscii`, which succeeds if all string characters are ASCII.

Also add counterpart `String.NotIsAscii`.

Failure message for `IsAscii` should contains character that does not belong to ASCII.

Assertions should have documentation comment with example and be covered by unit tests.

See also #153.

Pull request description:
Implement String.IsAscii
close #154 

Patch:
diff --git a/array.go b/array.go
index aec188b..5c9a431 100644
--- a/array.go
+++ b/array.go
@@ -193,10 +193,13 @@ func (a *Array) Last() *Value {
 //	strings := []interface{}{"foo", "bar"}
 //	array := NewArray(t, strings)
 //
-//	for n, val := range array.Iter() {
-//	    val.String().Equal(strings[n])
+//	for index, value := range array.Iter() {
+//	    value.String().Equal(strings[index])
 //	}
 func (a *Array) Iter() []Value {
+	a.chain.enter("Iter()")
+	defer a.chain.leave()
+
 	if a.chain.failed() {
 		return []Value{}
 	}
@@ -204,7 +207,7 @@ func (a *Array) Iter() []Value {
 	ret := []Value{}
 	for n := range a.value {
 		valueChain := a.chain.clone()
-		valueChain.enter("Iter[%d]", n)
+		valueChain.replace("Iter[%d]", n)
 
 		ret = append(ret, *newValue(valueChain, a.value[n]))
 	}
diff --git a/string.go b/string.go
index fd6f401..f2f2406 100644
--- a/string.go
+++ b/string.go
@@ -8,6 +8,7 @@ import (
 	"strconv"
 	"strings"
 	"time"
+	"unicode"
 )
 
 // String provides methods to inspect attached string value
@@ -747,6 +748,76 @@ func (s *String) MatchAll(re string) []Match {
 	return ret
 }
 
+// IsASCII succeeds if all string characters are ASCII
+//
+// Example:
+//
+//	str := NewString(t, "Hello")
+//	str.IsASCII()
+func (s *String) IsASCII() *String {
+	s.chain.enter("IsASCII()")
+	defer s.chain.leave()
+
+	if s.chain.failed() {
+		return s
+	}
+
+	isASCII := true
+	for _, c := range s.value {
+		if c > unicode.MaxASCII {
+			isASCII = false
+			break
+		}
+	}
+
+	if !isASCII {
+		s.chain.fail(AssertionFailure{
+			Type:   AssertValid,
+			Actual: &AssertionValue{s.value},
+			Errors: []error{
+				errors.New("expected: all string characters are ascii"),
+			},
+		})
+	}
+
+	return s
+}
+
+// NotIsASCII succeeds if at least one string character is not ASCII
+//
+// Example:
+//
+//	str := NewString(t, "こんにちは")
+//	str.NotIsASCII()
+func (s *String) NotIsASCII() *String {
+	s.chain.enter("NotIsASCII()")
+	defer s.chain.leave()
+
+	if s.chain.failed() {
+		return s
+	}
+
+	isASCII := true
+	for _, c := range s.value {
+		if c > unicode.MaxASCII {
+			isASCII = false
+			break
+		}
+	}
+
+	if isASCII {
+		s.chain.fail(AssertionFailure{
+			Type:   AssertValid,
+			Actual: &AssertionValue{s.value},
+			Errors: []error{
+				errors.New("expected: at least one string character is not ascii"),
+			},
+		})
+	}
+
+	return s
+}
+
 // AsNumber parses float from string and returns a new Number instance
 // with result.
 //


Test patch:
diff --git a/binder_test.go b/binder_test.go
index 9f79e05..afe57c9 100644
--- a/binder_test.go
+++ b/binder_test.go
@@ -138,7 +138,7 @@ func TestBinderTLS(t *testing.T) {
 	assert.Nil(t, err)
 	assert.NotNil(t, resp)
 	assert.NotNil(t, resp.Request.TLS)
-	assert.Equal(t, tlsState, resp.Request.TLS)
+	assert.Same(t, tlsState, resp.Request.TLS)
 }
 
 func TestBinderChunked(t *testing.T) {
diff --git a/expect_test.go b/expect_test.go
index a1a2f77..951625f 100644
--- a/expect_test.go
+++ b/expect_test.go
@@ -76,9 +76,9 @@ func TestExpectBuilders(t *testing.T) {
 	assert.Equal(t, 2, len(reqs1))
 	assert.Equal(t, 1, len(reqs2))
 
-	assert.Equal(t, r1, reqs1[0])
-	assert.Equal(t, r2, reqs1[1])
-	assert.Equal(t, r1, reqs2[0])
+	assert.Same(t, r1, reqs1[0])
+	assert.Same(t, r2, reqs1[1])
+	assert.Same(t, r2, reqs2[0])
 }
 
 func TestExpectBuildersCopying(t *testing.T) {
@@ -175,9 +175,9 @@ func TestExpectMatchers(t *testing.T) {
 	assert.Equal(t, 2, len(resps1))
 	assert.Equal(t, 1, len(resps2))
 
-	assert.Equal(t, resp1, resps1[0])
-	assert.Equal(t, resp2, resps1[1])
-	assert.Equal(t, resp2, resps2[0])
+	assert.Same(t, resp1, resps1[0])
+	assert.Same(t, resp2, resps1[1])
+	assert.Same(t, resp2, resps2[0])
 }
 
 func TestExpectMatchersCopying(t *testing.T) {
diff --git a/request_test.go b/request_test.go
index c805f9c..f5691eb 100644
--- a/request_test.go
+++ b/request_test.go
@@ -151,7 +151,7 @@ func TestRequestMatchers(t *testing.T) {
 	resp := req.Expect()
 
 	assert.Equal(t, 1, len(resps))
-	assert.Equal(t, resp, resps[0])
+	assert.Same(t, resp, resps[0])
 }
 
 func TestRequestTransformers(t *testing.T) {
@@ -657,7 +657,7 @@ func TestRequestHeaders(t *testing.T) {
 	assert.Equal(t, "url", client.req.URL.String())
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestCookies(t *testing.T) {
@@ -693,7 +693,7 @@ func TestRequestCookies(t *testing.T) {
 	assert.Equal(t, "url", client.req.URL.String())
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBasicAuth(t *testing.T) {
@@ -740,7 +740,7 @@ func TestRequestWithHost(t *testing.T) {
 	assert.Equal(t, "example.com", client1.req.Host)
 	assert.Equal(t, "url", client1.req.URL.String())
 
-	assert.Equal(t, &client1.resp, resp.Raw())
+	assert.Same(t, &client1.resp, resp.Raw())
 
 	factory2 := DefaultRequestFactory{}
 	client2 := &mockClient{}
@@ -809,7 +809,7 @@ func TestRequestBodyChunked(t *testing.T) {
 	assert.Equal(t, make(http.Header), client.req.Header)
 	assert.Equal(t, "body", string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyChunkedNil(t *testing.T) {
@@ -897,7 +897,7 @@ func TestRequestBodyBytes(t *testing.T) {
 	assert.Equal(t, make(http.Header), client.req.Header)
 	assert.Equal(t, "body", string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyBytesNil(t *testing.T) {
@@ -958,7 +958,7 @@ func TestRequestBodyText(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, "some text", string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyForm(t *testing.T) {
@@ -998,7 +998,7 @@ func TestRequestBodyForm(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, `a=1&b=2`, string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyField(t *testing.T) {
@@ -1036,7 +1036,7 @@ func TestRequestBodyField(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, `a=1&b=2`, string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyFormStruct(t *testing.T) {
@@ -1074,7 +1074,7 @@ func TestRequestBodyFormStruct(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, `a=1&b=2`, string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyFormCombined(t *testing.T) {
@@ -1112,7 +1112,7 @@ func TestRequestBodyFormCombined(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, `a=1&b=2&c=3`, string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestBodyMultipart(t *testing.T) {
@@ -1273,7 +1273,7 @@ func TestRequestBodyJSON(t *testing.T) {
 	assert.Equal(t, http.Header(expectedHeaders), client.req.Header)
 	assert.Equal(t, `{"key":"value"}`, string(resp.content))
 
-	assert.Equal(t, &client.resp, resp.Raw())
+	assert.Same(t, &client.resp, resp.Raw())
 }
 
 func TestRequestContentLength(t *testing.T) {
@@ -1723,8 +1723,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -1766,8 +1766,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -1817,8 +1817,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -1867,8 +1867,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -1911,8 +1911,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -1952,8 +1952,8 @@ func TestRequestRedirect(t *testing.T) {
 			// Should set CheckRedirect
 			httpClient, _ := req.config.Client.(*http.Client)
 			assert.NotNil(t, httpClient.CheckRedirect)
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-			assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+			assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 			assert.Equal(t,
 				errors.New("stopped after 1 redirects"),
 				httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -2000,8 +2000,8 @@ func TestRequestRedirect(t *testing.T) {
 				// Should set CheckRedirect
 				httpClient, _ := req.config.Client.(*http.Client)
 				assert.NotNil(t, httpClient.CheckRedirect)
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 				assert.Equal(t,
 					errors.New("stopped after 1 redirects"),
 					httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -2057,8 +2057,8 @@ func TestRequestRedirect(t *testing.T) {
 				// Should set CheckRedirect
 				httpClient, _ := req.config.Client.(*http.Client)
 				assert.NotNil(t, httpClient.CheckRedirect)
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 				assert.Equal(t,
 					errors.New("stopped after 1 redirects"),
 					httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
@@ -2115,8 +2115,8 @@ func TestRequestRedirect(t *testing.T) {
 				// Should set CheckRedirect
 				httpClient, _ := req.config.Client.(*http.Client)
 				assert.NotNil(t, httpClient.CheckRedirect)
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, nil))
-				assert.Equal(t, nil, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, nil))
+				assert.Nil(t, httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 1)))
 				assert.Equal(t,
 					errors.New("stopped after 1 redirects"),
 					httpClient.CheckRedirect(req.httpReq, make([]*http.Request, 2)),
diff --git a/response_test.go b/response_test.go
index 06f1e66..6c73519 100644
--- a/response_test.go
+++ b/response_test.go
@@ -214,7 +214,7 @@ func TestResponseHeaders(t *testing.T) {
 	resp.chain.assertOK(t)
 	resp.chain.reset()
 
-	assert.Equal(t, httpResp, resp.Raw())
+	assert.Same(t, httpResp, resp.Raw())
 
 	resp.Status(http.StatusOK)
 	resp.chain.assertOK(t)
@@ -1011,7 +1011,7 @@ func TestResponseJSONPCharsetBad(t *testing.T) {
 	resp.chain.assertFailed(t)
 	resp.chain.reset()
 
-	assert.Equal(t, nil, resp.JSONP("foo").Raw())
+	assert.Nil(t, resp.JSONP("foo").Raw())
 }
 
 func TestResponseContentOpts(t *testing.T) {
diff --git a/string_test.go b/string_test.go
index b122ba1..29f5b40 100644
--- a/string_test.go
+++ b/string_test.go
@@ -42,6 +42,8 @@ func TestStringFailed(t *testing.T) {
 	value.Match("")
 	value.NotMatch("")
 	value.MatchAll("")
+	value.IsASCII()
+	value.NotIsASCII()
 }
 
 func TestStringGetters(t *testing.T) {
@@ -300,6 +302,64 @@ func TestStringMatchInvalid(t *testing.T) {
 	value.chain.reset()
 }
 
+func TestStringIsAscii(t *testing.T) {
+	reporter := newMockReporter(t)
+
+	value1 := NewString(reporter, "Ascii")
+	value1.IsASCII()
+	value1.chain.assertOK(t)
+	value1.chain.reset()
+
+	value2 := NewString(reporter, "Ascii is アスキー")
+	value2.IsASCII()
+	value2.chain.assertFailed(t)
+	value2.chain.reset()
+
+	value3 := NewString(reporter, "アスキー")
+	value3.IsASCII()
+	value3.chain.assertFailed(t)
+	value3.chain.reset()
+
+	value4 := NewString(reporter, string(rune(127)))
+	value4.IsASCII()
+	value4.chain.assertOK(t)
+	value4.chain.reset()
+
+	value5 := NewString(reporter, string(rune(128)))
+	value5.IsASCII()
+	value5.chain.assertFailed(t)
+	value5.chain.reset()
+}
+
+func TestStringIsNotAscii(t *testing.T) {
+	reporter := newMockReporter(t)
+
+	value1 := NewString(reporter, "Ascii")
+	value1.NotIsASCII()
+	value1.chain.assertFailed(t)
+	value1.chain.reset()
+
+	value2 := NewString(reporter, "Ascii is アスキー")
+	value2.NotIsASCII()
+	value2.chain.assertOK(t)
+	value2.chain.reset()
+
+	value3 := NewString(reporter, "アスキー")
+	value3.NotIsASCII()
+	value3.chain.assertOK(t)
+	value3.chain.reset()
+
+	value4 := NewString(reporter, string(rune(127)))
+	value4.NotIsASCII()
+	value4.chain.assertFailed(t)
+	value4.chain.reset()
+
+	value5 := NewString(reporter, string(rune(128)))
+	value5.NotIsASCII()
+	value5.chain.assertOK(t)
+	value5.chain.reset()
+}
+
 func TestStringAsNumber(t *testing.T) {
 	reporter := newMockReporter(t)