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  }