github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/ast/api_test.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ast 18 19 import ( 20 "strings" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24 ) 25 26 type Path = []interface{} 27 28 type testGetApi struct { 29 json string 30 path Path 31 } 32 33 type checkError func(error) bool 34 35 func isSyntaxError(err error) bool { 36 if err == nil { 37 return false 38 } 39 return strings.HasPrefix(err.Error(), `"Syntax error at index`) 40 } 41 42 func isEmptySource(err error) bool { 43 if err == nil { 44 return false 45 } 46 return strings.Contains(err.Error(), "no sources available") 47 } 48 49 func isErrNotExist(err error) bool { 50 return err == ErrNotExist 51 } 52 53 func isErrUnsupportType(err error) bool { 54 return err == ErrUnsupportType 55 } 56 57 func testSyntaxJson(t *testing.T, json string, path ...interface{}) { 58 search := NewSearcher(json) 59 _, err := search.GetByPath(path...) 60 assert.True(t, isSyntaxError(err)) 61 } 62 63 func TestGetFromEmptyJson(t *testing.T) { 64 tests := []testGetApi{ 65 {"", nil}, 66 {"", Path{}}, 67 {"", Path{""}}, 68 {"", Path{0}}, 69 {"", Path{"", ""}}, 70 } 71 for _, test := range tests { 72 f := func(t *testing.T) { 73 search := NewSearcher(test.json) 74 _, err := search.GetByPath(test.path...) 75 assert.True(t, isEmptySource(err)) 76 } 77 t.Run(test.json, f) 78 } 79 } 80 81 func TestGetFromSyntaxError(t *testing.T) { 82 tests := []testGetApi{ 83 {" \r\n\f\t", Path{}}, 84 {"123.", Path{}}, 85 {"+124", Path{}}, 86 {"-", Path{}}, 87 {"-e123", Path{}}, 88 {"-1.e123", Path{}}, 89 {"-12e456.1", Path{}}, 90 {"-12e.1", Path{}}, 91 {"[", Path{}}, 92 {"{", Path{}}, 93 {"[}", Path{}}, 94 {"{]", Path{}}, 95 {"{,}", Path{}}, 96 {"[,]", Path{}}, 97 {"tru", Path{}}, 98 {"fals", Path{}}, 99 {"nul", Path{}}, 100 {`{"a":"`, Path{"a"}}, 101 {`{"`, Path{}}, 102 {`"`, Path{}}, 103 {`"\"`, Path{}}, 104 {`"\\\"`, Path{}}, 105 {`"hello`, Path{}}, 106 {`{{}}`, Path{}}, 107 {`{[]}`, Path{}}, 108 {`{:,}`, Path{}}, 109 {`{test:error}`, Path{}}, 110 {`{":true}`, Path{}}, 111 {`{"" false}`, Path{}}, 112 {`{ "" : "false }`, Path{}}, 113 {`{"":"",}`, Path{}}, 114 {`{ " test : true}`, Path{}}, 115 {`{ "test" : tru }`, Path{}}, 116 {`{ "test" : true , }`, Path{}}, 117 {`{ {"test" : true , } }`, Path{}}, 118 {`{"test":1. }`, Path{}}, 119 {`{"\\\""`, Path{}}, 120 {`{"\\\"":`, Path{}}, 121 {`{"\\\":",""}`, Path{}}, 122 {`[{]`, Path{}}, 123 {`[tru]`, Path{}}, 124 {`[-1.]`, Path{}}, 125 {`[[]`, Path{}}, 126 {`[[],`, Path{}}, 127 {`[ true , false , [ ]`, Path{}}, 128 {`[true, false, [],`, Path{}}, 129 {`[true, false, [],]`, Path{}}, 130 {`{"key": [true, false, []], "key2": {{}}`, Path{}}, 131 } 132 133 for _, test := range tests { 134 f := func(t *testing.T) { 135 testSyntaxJson(t, test.json, test.path...) 136 path := append(Path{"key"}, test.path...) 137 testSyntaxJson(t, `{"key":`+test.json, path...) 138 path = append(Path{""}, test.path...) 139 testSyntaxJson(t, `{"":`+test.json, path...) 140 path = append(Path{1}, test.path...) 141 testSyntaxJson(t, `["",`+test.json, path...) 142 } 143 t.Run(test.json, f) 144 } 145 } 146 147 // NOTE: GetByPath API not validate the undemanded fields for performance. 148 func TestGetWithInvalidUndemandedField(t *testing.T) { 149 type Any = interface{} 150 tests := []struct { 151 json string 152 path Path 153 exp Any 154 }{ 155 {"-0xyz", Path{}, Any(float64(-0))}, 156 {"-12e4xyz", Path{}, Any(float64(-12e4))}, 157 {"truex", Path{}, Any(true)}, 158 {"false,", Path{}, Any(false)}, 159 {`{"a":{,xxx},"b":true}`, Path{"b"}, Any(true)}, 160 {`{"a":[,xxx],"b":true}`, Path{"b"}, Any(true)}, 161 } 162 163 for _, test := range tests { 164 f := func(t *testing.T) { 165 search := NewSearcher(test.json) 166 node, err := search.GetByPath(test.path...) 167 assert.NoError(t, err) 168 v, err := node.Interface() 169 assert.NoError(t, err) 170 assert.Equal(t, v, test.exp) 171 } 172 t.Run(test.json, f) 173 } 174 } 175 176 func TestGet_InvalidPathType(t *testing.T) { 177 assert.Panics(t, assert.PanicTestFunc(func() { 178 data := `{"a":[{"b":true}]}` 179 s := NewSearcher(data) 180 s.GetByPath("a", true) 181 182 s = NewSearcher(data) 183 s.GetByPath("a", nil) 184 185 s = NewSearcher(data) 186 s.GetByPath("a", -1) 187 })) 188 }