github.com/go-kivik/kivik/v4@v4.3.2/pouchdb/find_test.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 //go:build js 14 15 package pouchdb 16 17 import ( 18 "context" 19 "encoding/json" 20 "fmt" 21 "runtime" 22 "strconv" 23 "strings" 24 "testing" 25 26 "github.com/gopherjs/gopherjs/js" 27 "gitlab.com/flimzy/testy" 28 29 "github.com/go-kivik/kivik/v4/driver" 30 "github.com/go-kivik/kivik/v4/pouchdb/bindings" 31 "github.com/go-kivik/kivik/v4/pouchdb/internal" 32 ) 33 34 func init() { 35 memPouch := js.Global.Get("PouchDB").Call("defaults", map[string]interface{}{ 36 "db": js.Global.Call("require", "memdown"), 37 }) 38 js.Global.Set("PouchDB", memPouch) 39 } 40 41 func TestBuildIndex(t *testing.T) { 42 tests := []struct { 43 Ddoc string 44 Name string 45 Index interface{} 46 Expected string 47 }{ 48 {Expected: `{}`}, 49 {Index: `{"fields":["foo"]}`, Expected: `{"fields":["foo"]}`}, 50 {Index: `{"fields":["foo"]}`, Name: "test", Expected: `{"fields":["foo"],"name":"test"}`}, 51 {Index: `{"fields":["foo"]}`, Name: "test", Ddoc: "_foo", Expected: `{"fields":["foo"],"name":"test","ddoc":"_foo"}`}, 52 } 53 for i, test := range tests { 54 t.Run(strconv.Itoa(i), func(t *testing.T) { 55 result, err := buildIndex(test.Ddoc, test.Name, test.Index) 56 if err != nil { 57 t.Errorf("Build Index failed: %s", err) 58 } 59 r := js.Global.Get("JSON").Call("stringify", result).String() 60 if d := testy.DiffJSON([]byte(test.Expected), []byte(r)); d != nil { 61 t.Errorf("BuildIndex result differs:\n%s\n", d) 62 } 63 }) 64 } 65 } 66 67 func TestExplain(t *testing.T) { 68 defaultLimit := int64(0) 69 if ver := internal.PouchDBVersion(t); strings.HasPrefix(ver, "9") { 70 defaultLimit = 25 71 } 72 type test struct { 73 db *db 74 query interface{} 75 expected *driver.QueryPlan 76 err string 77 } 78 tests := testy.NewTable() 79 tests.Add("query error", test{ 80 db: &db{db: bindings.GlobalPouchDB().New("foo", nil)}, 81 query: nil, 82 err: "TypeError: Cannot read propert", 83 }) 84 tests.Add("simple selector", func(t *testing.T) interface{} { 85 options := map[string]interface{}{ 86 "bookmark": "nil", 87 "conflicts": false, 88 "r": []interface{}{49}, 89 "sort": map[string]interface{}{}, 90 "use_index": []interface{}{}, 91 } 92 if defaultLimit > 0 { 93 options["limit"] = defaultLimit 94 } 95 96 return test{ 97 db: &db{db: bindings.GlobalPouchDB().New("foo", nil)}, 98 query: map[string]interface{}{"selector": map[string]interface{}{"_id": "foo"}}, 99 expected: &driver.QueryPlan{ 100 DBName: "foo", 101 Limit: defaultLimit, 102 Index: map[string]interface{}{ 103 "ddoc": nil, 104 "def": map[string]interface{}{ 105 "fields": []interface{}{map[string]interface{}{"_id": "asc"}}, 106 }, 107 "name": "_all_docs", 108 "type": "special", 109 }, 110 Options: options, 111 Selector: map[string]interface{}{"_id": map[string]interface{}{"$eq": "foo"}}, 112 Fields: func() []interface{} { 113 fmt.Println(runtime.Version()) 114 if ver := runtime.Version(); strings.HasPrefix(ver, "go1.16") { 115 return []interface{}{} 116 } 117 // From GopherJS 17 on, null arrays are properly converted to nil 118 return nil 119 }(), 120 Range: map[string]interface{}{}, 121 }, 122 } 123 }) 124 tests.Add("fields list", func(t *testing.T) interface{} { 125 options := map[string]interface{}{ 126 "bookmark": "nil", 127 "conflicts": false, 128 "fields": []interface{}{"_id", map[string]interface{}{"type": "desc"}}, 129 "r": []interface{}{49}, 130 "sort": map[string]interface{}{}, 131 "use_index": []interface{}{}, 132 } 133 if defaultLimit > 0 { 134 options["limit"] = defaultLimit 135 } 136 137 return test{ 138 db: &db{db: bindings.GlobalPouchDB().New("foo", nil)}, 139 query: map[string]interface{}{ 140 "selector": map[string]interface{}{"_id": "foo"}, 141 "fields": []interface{}{"_id", map[string]interface{}{"type": "desc"}}, 142 }, 143 expected: &driver.QueryPlan{ 144 DBName: "foo", 145 Limit: defaultLimit, 146 Index: map[string]interface{}{ 147 "ddoc": nil, 148 "def": map[string]interface{}{ 149 "fields": []interface{}{map[string]interface{}{"_id": "asc"}}, 150 }, 151 "name": "_all_docs", 152 "type": "special", 153 }, 154 Options: options, 155 Selector: map[string]interface{}{"_id": map[string]interface{}{"$eq": "foo"}}, 156 Fields: []interface{}{"_id", map[string]interface{}{"type": "desc"}}, 157 Range: map[string]interface{}{}, 158 }, 159 } 160 }) 161 tests.Run(t, func(t *testing.T, tt test) { 162 result, err := tt.db.Explain(context.Background(), tt.query, nil) 163 if !testy.ErrorMatchesRE(tt.err, err) { 164 t.Errorf("Unexpected error: %s", err) 165 } 166 if err != nil { 167 return 168 } 169 if d := testy.DiffAsJSON(tt.expected, result); d != nil { 170 t.Error(d) 171 } 172 }) 173 } 174 175 func TestUnmarshalQueryPlan(t *testing.T) { 176 tests := []struct { 177 name string 178 input string 179 expected *queryPlan 180 err string 181 }{ 182 { 183 name: "non-array", 184 input: `{"fields":{}}`, 185 err: "json: cannot unmarshal object into Go", 186 }, 187 { 188 name: "all_fields", 189 input: `{"fields":"all_fields","dbname":"foo"}`, 190 expected: &queryPlan{DBName: "foo"}, 191 }, 192 { 193 name: "simple field list", 194 input: `{"fields":["foo","bar"],"dbname":"foo"}`, 195 expected: &queryPlan{Fields: []interface{}{"foo", "bar"}, DBName: "foo"}, 196 }, 197 { 198 name: "complex field list", 199 input: `{"dbname":"foo", "fields":[{"foo":"asc"},{"bar":"desc"}]}`, 200 expected: &queryPlan{ 201 DBName: "foo", 202 Fields: []interface{}{ 203 map[string]interface{}{"foo": "asc"}, 204 map[string]interface{}{"bar": "desc"}, 205 }, 206 }, 207 }, 208 { 209 name: "invalid bare string", 210 input: `{"fields":"not_all_fields"}`, 211 err: "json: cannot unmarshal string into Go", 212 }, 213 } 214 for _, test := range tests { 215 t.Run(test.name, func(t *testing.T) { 216 result := new(queryPlan) 217 err := json.Unmarshal([]byte(test.input), &result) 218 if !testy.ErrorMatchesRE(test.err, err) { 219 t.Errorf("Unexpected error: %s", err) 220 } 221 if err != nil { 222 return 223 } 224 if d := testy.DiffInterface(test.expected, result); d != nil { 225 t.Error(d) 226 } 227 }) 228 } 229 }