Skip to content

Commit

Permalink
Add Testee.Query to access map easily
Browse files Browse the repository at this point in the history
  • Loading branch information
otiai10 committed Jun 24, 2023
1 parent 59f270f commit 823aebc
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 0 deletions.
10 changes: 10 additions & 0 deletions all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,13 @@ func TestRequire(t *testing.T) {
// })
// mint.Expect(t, ok).ToBe(false)
}

func TestTestee_Query(t *testing.T) {
v := map[string]any{
"foo": map[string]any{"name": "otiai10", "age": 30},
"bar": []any{100, "helllo"},
}
mint.Expect(t, "foo").Query("foo").ToBe("foo")
mint.Expect(t, "foo").Query("bar").Not().ToBe("bar")
mint.Expect(t, v).Query("foo.name").ToBe("otiai10")
}
31 changes: 31 additions & 0 deletions mquery/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
mquery
===

```go
import mquery

var m = map[string]any{
"foo": "bar",
"hoge": map[string]any{
"name": "otiai10",
},
"fuga": map[int]map[string]any{
0: {"greet": "Hello"},
1: {"greet": "こんにちは"},
},
"langs": []string{"Go", "JavaScript", "English"},
"baz": nil,
"required": false,
}

func main() {
fmt.Println(
Query(m, "foo"), // "bar"
Query(m, "hoge.name"), // "otiai10"
Query(m, "fuga.0.greet"), // "Hello"
Query(m, "langs.2"), // "English"
Query(m, "required"), // false
Query(m, "baz.biz"), // nil
)
}
```
26 changes: 26 additions & 0 deletions mquery/all_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mquery

import (
"testing"
)

var m = map[string]any{
"foo": "bar",
"hoge": map[string]any{
"name": "otiai10",
},
"fuga": map[int]map[string]any{
0: {"greet": "Hello"},
1: {"greet": "こんにちは"},
},
"langs": []string{"Go", "JavaScript", "English"},
"baz": nil,
"required": false,
}

func TestQuery(t *testing.T) {
// Expect(t, Query(m, "foo")).ToBe("bar")
// Expect(t, Query(m, "hoge.name")).ToBe("otiai10")
// Expect(t, Query(m, "fuga.1.greet")).ToBe("こんにちは")
// Expect(t, Query(m, "langs.0")).ToBe("Go")
}
24 changes: 24 additions & 0 deletions mquery/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package mquery

var a = map[string]any{
"foo": "bar",
"hoge": map[string]any{
"name": "otiai10",
},
"fuga": map[int]map[string]any{
0: {"greet": "Hello"},
1: {"greet": "こんにちは"},
},
"langs": []string{"Go", "JavaScript", "English"},
"baz": nil,
"required": false,
}

func ExampleQuery() {
// Query(m, "foo") => "bar"
// Query(m, "hoge.name") => "otiai10"
// Query(m, "fuga.1.greet") => "こんにちは"
// Query(m, "langs.0") => "Go"
// Query(m, "baz") => nil
// Query(m, "required") => false
}
62 changes: 62 additions & 0 deletions mquery/mquery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package mquery

import (
"fmt"
"reflect"
"strconv"
"strings"
)

func Query(m any, q string) any {
return query(m, strings.Split(q, "."))
}

func query(m any, qs []string) any {
t := reflect.TypeOf(m)
switch t.Kind() {
case reflect.Map:
return queryMap(m, t, qs)
case reflect.Slice:
return querySlice(m, t, qs)
default:
return m
}
}

func queryMap(m any, t reflect.Type, qs []string) any {
if len(qs) == 0 {
return m
}
switch t.Key().Kind() {
case reflect.String:
next := reflect.ValueOf(m).MapIndex(reflect.ValueOf(qs[0])).Interface()
return query(next, qs[1:])
case reflect.Int:
i, err := strconv.Atoi(qs[0])
if err != nil {
return fmt.Errorf("cannot access map with keyword: %s: %v", qs[0], err)
}
next := reflect.ValueOf(m).MapIndex(reflect.ValueOf(i)).Interface()
return query(next, qs[1:])
}
return nil
}

func querySlice(m any, t reflect.Type, qs []string) any {
if len(qs) == 0 {
return m
}
v := reflect.ValueOf(m)
if v.Len() == 0 {
return nil
}
i, err := strconv.Atoi(qs[0])
if err != nil {
return fmt.Errorf("cannot access slice with keyword: %s: %v", qs[0], err)
}
if v.Len() <= i {
return nil
}
next := v.Index(i).Interface()
return query(next, qs[1:])
}
11 changes: 11 additions & 0 deletions testee.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"regexp"
"runtime"
"testing"

"github.com/otiai10/mint/mquery"
)

// Testee is holder of interfaces which user want to assert
Expand All @@ -21,6 +23,15 @@ type Testee struct {
result MintResult
required bool
verbose bool

queriedFrom string // Only used when querying
}

// Query queries the actual value with given query string.
func (testee *Testee) Query(query string) *Testee {
testee.queriedFrom = fmt.Sprintf("queried from %T", testee.actual)
testee.actual = mquery.Query(testee.actual, query)
return testee
}

// ToBe can assert the testee to equal the parameter of this func.
Expand Down

0 comments on commit 823aebc

Please sign in to comment.