Repository: gavv/httpexpect
Pull request #238 (2023-01-26 14:11:59)

Decode method
Continuation pr for #192 

gavv: Thanks for PR
coveralls: 
[![Coverage Status](https://coveralls.io/builds/56318379/badge)](https://coveralls.io/builds/56318379)

Coverage: 94.829% (-0.02%) from 94.847% when pulling **ce014cb73ec335f6a97548ccd21bbb8b9a5b0398 on Rohith-Raju:DecodeMethod** into **eb535fe85f25570429c24f5633672db35cfa5a63 on gavv:master**.

gavv: > [![Coverage Status](https://camo.githubusercontent.com/45fe3a0937de295d9707cd486e994496bf686238a389792d3f9a448dcba48f37/68747470733a2f2f636f766572616c6c732e696f2f6275696c64732f35363331383734322f6261646765)](https://coveralls.io/builds/56318742)
> 
> Coverage: 94.829% (-0.02%) from 94.847% when pulling **[9d224c6](https://github.com/gavv/httpexpect/commit/9d224c6b84c5178a413840409a23c669027c173c) on Rohith-Raju:DecodeMethod** into **[eb535fe](https://github.com/gavv/httpexpect/commit/eb535fe85f25570429c24f5633672db35cfa5a63) on gavv:master**.

Please take a look at the uncovered branch.
github-actions[bot]: :umbrella: The latest upstream change (presumably [these](https://github.com/gavv/httpexpect/compare/f5da5fedb219...329d937d8624)) made this pull request unmergeable. Please resolve the merge conflicts.
Rohith-Raju: oops, vscode linter went crazy. let me fix that
gavv: Thanks for update. I've pushed a few minor fixes.

Patch:
diff --git a/README.md b/README.md
index e23ce50..0c69efb 100644
--- a/README.md
+++ b/README.md
@@ -220,6 +220,27 @@ for _, private := range repos.Path("$..private").Array().Iter() {
 }
 ```
 
+##### JSON decoding
+
+```go
+type User struct {
+	Name   string `json:"name"`
+	Age    int    `json:"age"`
+	Gender string `json:"gender"`
+}
+
+var user User
+e.GET("/user").
+	Expect().
+	Status(http.StatusOK).
+	JSON().
+	Decode(&user)
+	
+if user.Name != "octocat" {
+	t.Fail()
+}
+```
+
 ##### Forms
 
 ```go
diff --git a/array.go b/array.go
index 1e9147b..0fb2301 100644
--- a/array.go
+++ b/array.go
@@ -73,8 +73,8 @@ func (a *Array) Raw() []interface{} {
 // Decode unmarshals the underlying value attached to the Array to a target variable.
 // target should be one of these:
 //
-// - pointer to an empty interface
-// - pointer to a slice of any type
+//   - pointer to an empty interface
+//   - pointer to a slice of any type
 //
 // Example:
 //
diff --git a/boolean.go b/boolean.go
index 74b74fa..f502f81 100644
--- a/boolean.go
+++ b/boolean.go
@@ -52,8 +52,8 @@ func (b *Boolean) Raw() bool {
 // Decode unmarshals the underlying value attached to the Boolean to a target variable.
 // target should be one of these:
 //
-// - pointer to an empty interface
-// - pointer to a boolean
+//   - pointer to an empty interface
+//   - pointer to a boolean
 //
 // Example:
 //
diff --git a/number.go b/number.go
index fe5ac31..71703b4 100644
--- a/number.go
+++ b/number.go
@@ -53,8 +53,8 @@ func (n *Number) Raw() float64 {
 // Decode unmarshals the underlying value attached to the Number to a target variable.
 // target should be one of these:
 //
-// - pointer to an empty interface
-// - pointer to any integer or floating type
+//   - pointer to an empty interface
+//   - pointer to any integer or floating type
 //
 // Example:
 //
diff --git a/object.go b/object.go
index aebcb50..b51c76c 100644
--- a/object.go
+++ b/object.go
@@ -74,9 +74,9 @@ func (o *Object) Raw() map[string]interface{} {
 // Decode unmarshals the underlying value attached to the Object to a target variable
 // target should be one of this:
 //
-// - pointer to an empty interface
-// - pointer to a map
-// - pointer to a struct
+//   - pointer to an empty interface
+//   - pointer to a map
+//   - pointer to a struct
 //
 // Example:
 //
@@ -84,7 +84,7 @@ func (o *Object) Raw() map[string]interface{} {
 //		Foo int                    `json:"foo"`
 //		Bar []interface{}          `json:"bar"`
 //		Baz map[string]interface{} `json:"baz"`
-//		Bat struct{ a int }        `json:"bat"`
+//		Bat struct{ A int }        `json:"bat"`
 //	}
 //
 //	m := map[string]interface{}{
@@ -93,7 +93,7 @@ func (o *Object) Raw() map[string]interface{} {
 //		"baz": map[string]interface{}{
 //			"a": "b",
 //		},
-//		"bat": struct{ a int }{0},
+//		"bat": struct{ A int }{123},
 //	}
 //
 //	value := NewObject(t, value)
@@ -102,7 +102,7 @@ func (o *Object) Raw() map[string]interface{} {
 //	value.Decode(&target)
 //
 //	assert.Equal(t, S{123,[]interface{}{"123", 234.0},
-//		map[string]interface{}{"a": "b"}, struct{ a int }{0},
+//		map[string]interface{}{"a": "b"}, struct{ A int }{123},
 //	}, target)
 func (o *Object) Decode(target interface{}) *Object {
 	opChain := o.chain.enter("Decode()")
diff --git a/string.go b/string.go
index c0e7513..ff6258b 100644
--- a/string.go
+++ b/string.go
@@ -59,8 +59,8 @@ func (s *String) Raw() string {
 // Decode unmarshals the underlying value attached to the String to a target variable.
 // target should be one of these:
 //
-// - pointer to an empty interface
-// - pointer to a string
+//   - pointer to an empty interface
+//   - pointer to a string
 //
 // Example:
 //
diff --git a/value.go b/value.go
index 592ab4c..fe9be15 100644
--- a/value.go
+++ b/value.go
@@ -75,6 +75,41 @@ func (v *Value) Raw() interface{} {
 	return v.value
 }
 
+// Decode unmarshals the underlying value attached to the Object to a target variable
+// target should be pointer to any type.
+//
+// Example:
+//
+//	type S struct {
+//		Foo int             `json:"foo"`
+//		Bar []interface{}   `json:"bar"`
+//		Baz struct{ A int } `json:"baz"`
+//	}
+//
+//	m := map[string]interface{}{
+//		"foo": 123,
+//		"bar": []interface{}{"123", 456.0},
+//		"baz": struct{ A int }{123},
+//	}
+//
+//	value = NewValue(reporter,m)
+//
+//	var target S
+//	value.Decode(&target)
+//
+//	assert.Equal(t, S{123, []interface{}{"123", 456.0}, struct{ A int }{123}, target})
+func (v *Value) Decode(target interface{}) *Value {
+	opChain := v.chain.enter("Decode()")
+	defer opChain.leave()
+
+	if opChain.failed() {
+		return v
+	}
+
+	canonDecode(opChain, v.value, target)
+	return v
+}
+
 // Alias returns a new Value object with alias.
 // When a test of Value object with alias is failed,
 // an assertion is displayed as a chain starting from the alias.


Test patch:
diff --git a/object_test.go b/object_test.go
index c27d288..391ad3a 100644
--- a/object_test.go
+++ b/object_test.go
@@ -162,7 +162,7 @@ func TestObject_Decode(t *testing.T) {
 			Foo int                    `json:"foo"`
 			Bar []interface{}          `json:"bar"`
 			Baz map[string]interface{} `json:"baz"`
-			Bat struct{ a int }        `json:"bat"`
+			Bat struct{ A int }        `json:"bat"`
 		}
 
 		m := map[string]interface{}{
@@ -171,13 +171,16 @@ func TestObject_Decode(t *testing.T) {
 			"baz": map[string]interface{}{
 				"a": "b",
 			},
-			"bat": struct{ a int }{0},
+			"bat": struct{ A int }{123},
 		}
 
 		value := NewObject(reporter, m)
 
-		actualStruct := S{123, []interface{}{"123", 234.0},
-			map[string]interface{}{"a": "b"}, struct{ a int }{0},
+		actualStruct := S{
+			Foo: 123,
+			Bar: []interface{}{"123", 234.0},
+			Baz: map[string]interface{}{"a": "b"},
+			Bat: struct{ A int }{123},
 		}
 
 		var target S
diff --git a/value_test.go b/value_test.go
index 286d448..a44c05e 100644
--- a/value_test.go
+++ b/value_test.go
@@ -22,6 +22,9 @@ func TestValue_Failed(t *testing.T) {
 
 	assert.NotNil(t, value.Path("/"))
 
+	var target interface{}
+	value.Decode(target)
+
 	assert.NotNil(t, value.Object())
 	assert.NotNil(t, value.Array())
 	assert.NotNil(t, value.String())
@@ -68,6 +71,70 @@ func TestValue_Constructors(t *testing.T) {
 	})
 }
 
+func TestValue_Decode(t *testing.T) {
+	t.Run("Decode into empty interface", func(t *testing.T) {
+		reporter := newMockReporter(t)
+
+		value := NewValue(reporter, 123.0)
+
+		var target interface{}
+		value.Decode(&target)
+
+		value.chain.assertNotFailed(t)
+		assert.Equal(t, 123.0, target)
+	})
+
+	t.Run("Decode into struct", func(t *testing.T) {
+		reporter := newMockReporter(t)
+
+		type S struct {
+			Foo int             `json:"foo"`
+			Bar []interface{}   `json:"bar"`
+			Baz struct{ A int } `json:"baz"`
+		}
+
+		m := map[string]interface{}{
+			"foo": 123,
+			"bar": []interface{}{"123", 456.0},
+			"baz": struct{ A int }{123},
+		}
+
+		value := NewValue(reporter, m)
+
+		actualStruct := S{
+			123,
+			[]interface{}{"123", 456.0},
+			struct{ A int }{123},
+		}
+
+		var target S
+		value.Decode(&target)
+
+		value.chain.assertNotFailed(t)
+		assert.Equal(t, target, actualStruct)
+	})
+
+	t.Run("Target is nil", func(t *testing.T) {
+		reporter := newMockReporter(t)
+
+		value := NewValue(reporter, 123)
+
+		value.Decode(nil)
+
+		value.chain.failed()
+	})
+
+	t.Run("Target is unmarshable", func(t *testing.T) {
+		reporter := newMockReporter(t)
+
+		value := NewValue(reporter, 123)
+
+		value.Decode(123)
+
+		value.chain.failed()
+	})
+}
+
 func TestValue_Alias(t *testing.T) {
 	reporter := newMockReporter(t)