github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/coll/jq_test.go (about) 1 package coll 2 3 import ( 4 "context" 5 "encoding/json" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestJQ(t *testing.T) { 13 ctx := context.Background() 14 in := map[string]interface{}{ 15 "store": map[string]interface{}{ 16 "book": []interface{}{ 17 map[string]interface{}{ 18 "category": "reference", 19 "author": "Nigel Rees", 20 "title": "Sayings of the Century", 21 "price": 8.95, 22 }, 23 map[string]interface{}{ 24 "category": "fiction", 25 "author": "Evelyn Waugh", 26 "title": "Sword of Honour", 27 "price": 12.99, 28 }, 29 map[string]interface{}{ 30 "category": "fiction", 31 "author": "Herman Melville", 32 "title": "Moby Dick", 33 "isbn": "0-553-21311-3", 34 "price": 8.99, 35 }, 36 map[string]interface{}{ 37 "category": "fiction", 38 "author": "J. R. R. Tolkien", 39 "title": "The Lord of the Rings", 40 "isbn": "0-395-19395-8", 41 "price": 22.99, 42 }, 43 }, 44 "bicycle": map[string]interface{}{ 45 "color": "red", 46 "price": 19.95, 47 }, 48 }, 49 } 50 out, err := JQ(ctx, ".store.bicycle.color", in) 51 require.NoError(t, err) 52 assert.Equal(t, "red", out) 53 54 out, err = JQ(ctx, ".store.bicycle.price", in) 55 require.NoError(t, err) 56 assert.InEpsilon(t, 19.95, out, 1e-12) 57 58 out, err = JQ(ctx, ".store.bogus", in) 59 require.NoError(t, err) 60 assert.Nil(t, out) 61 62 _, err = JQ(ctx, "{.store.unclosed", in) 63 require.Error(t, err) 64 65 out, err = JQ(ctx, ".store", in) 66 require.NoError(t, err) 67 assert.EqualValues(t, in["store"], out) 68 69 out, err = JQ(ctx, ".store.book[].author", in) 70 require.NoError(t, err) 71 assert.Len(t, out, 4) 72 assert.Contains(t, out, "Nigel Rees") 73 assert.Contains(t, out, "Evelyn Waugh") 74 assert.Contains(t, out, "Herman Melville") 75 assert.Contains(t, out, "J. R. R. Tolkien") 76 77 out, err = JQ(ctx, ".store.book[]|select(.price < 10.0 )", in) 78 require.NoError(t, err) 79 expected := []interface{}{ 80 map[string]interface{}{ 81 "category": "reference", 82 "author": "Nigel Rees", 83 "title": "Sayings of the Century", 84 "price": 8.95, 85 }, 86 map[string]interface{}{ 87 "category": "fiction", 88 "author": "Herman Melville", 89 "title": "Moby Dick", 90 "isbn": "0-553-21311-3", 91 "price": 8.99, 92 }, 93 } 94 assert.EqualValues(t, expected, out) 95 96 in = map[string]interface{}{ 97 "a": map[string]interface{}{ 98 "aa": map[string]interface{}{ 99 "foo": map[string]interface{}{ 100 "aaa": map[string]interface{}{ 101 "aaaa": map[string]interface{}{ 102 "bar": 1234, 103 }, 104 }, 105 }, 106 }, 107 "ab": map[string]interface{}{ 108 "aba": map[string]interface{}{ 109 "foo": map[string]interface{}{ 110 "abaa": true, 111 "abab": "baz", 112 }, 113 }, 114 }, 115 }, 116 } 117 out, err = JQ(ctx, `tostream|select((.[0]|index("foo")) and (.[0][-1]!="foo") and (.[1])) as $s|($s[0]|index("foo")+1) as $ind|($ind|truncate_stream($s)) as $newstream|$newstream|reduce . as [$p,$v] ({};setpath($p;$v))|add`, in) 118 require.NoError(t, err) 119 assert.Len(t, out, 3) 120 assert.Contains(t, out, map[string]interface{}{"aaaa": map[string]interface{}{"bar": 1234}}) 121 assert.Contains(t, out, true) 122 assert.Contains(t, out, "baz") 123 } 124 125 func TestJQ_typeConversions(t *testing.T) { 126 ctx := context.Background() 127 128 type bicycleType struct { 129 Color string 130 } 131 type storeType struct { 132 Bicycle *bicycleType 133 safe interface{} 134 } 135 136 structIn := &storeType{ 137 Bicycle: &bicycleType{ 138 Color: "red", 139 }, 140 safe: "hidden", 141 } 142 143 out, err := JQ(ctx, ".Bicycle.Color", structIn) 144 require.NoError(t, err) 145 assert.Equal(t, "red", out) 146 147 out, err = JQ(ctx, ".safe", structIn) 148 require.NoError(t, err) 149 assert.Nil(t, out) 150 151 _, err = JQ(ctx, ".*", structIn) 152 require.Error(t, err) 153 154 // a type with an underlying type of map[string]interface{}, just like 155 // gomplate.tmplctx 156 type mapType map[string]interface{} 157 158 out, err = JQ(ctx, ".foo", mapType{"foo": "bar"}) 159 require.NoError(t, err) 160 assert.Equal(t, "bar", out) 161 162 // sometimes it'll be a pointer... 163 out, err = JQ(ctx, ".foo", &mapType{"foo": "bar"}) 164 require.NoError(t, err) 165 assert.Equal(t, "bar", out) 166 167 // underlying slice type 168 type sliceType []interface{} 169 170 out, err = JQ(ctx, ".[1]", sliceType{"foo", "bar"}) 171 require.NoError(t, err) 172 assert.Equal(t, "bar", out) 173 174 out, err = JQ(ctx, ".[2]", &sliceType{"foo", "bar", "baz"}) 175 require.NoError(t, err) 176 assert.Equal(t, "baz", out) 177 178 // other basic types 179 out, err = JQ(ctx, ".", []byte("hello")) 180 require.NoError(t, err) 181 assert.EqualValues(t, "hello", out) 182 183 out, err = JQ(ctx, ".", "hello") 184 require.NoError(t, err) 185 assert.EqualValues(t, "hello", out) 186 187 out, err = JQ(ctx, ".", 1234) 188 require.NoError(t, err) 189 assert.EqualValues(t, 1234, out) 190 191 out, err = JQ(ctx, ".", true) 192 require.NoError(t, err) 193 assert.EqualValues(t, true, out) 194 195 out, err = JQ(ctx, ".", nil) 196 require.NoError(t, err) 197 assert.Nil(t, out) 198 199 // underlying basic types 200 type intType int 201 out, err = JQ(ctx, ".", intType(1234)) 202 require.NoError(t, err) 203 assert.EqualValues(t, 1234, out) 204 205 type byteArrayType []byte 206 out, err = JQ(ctx, ".", byteArrayType("hello")) 207 require.NoError(t, err) 208 assert.EqualValues(t, "hello", out) 209 } 210 211 func TestJQConvertType_passthroughTypes(t *testing.T) { 212 // non-marshalable values, like recursive structs, can't be used 213 type recursive struct{ Self *recursive } 214 v := &recursive{} 215 v.Self = v 216 _, err := jqConvertType(v) 217 require.Error(t, err) 218 219 testdata := []interface{}{ 220 map[string]interface{}{"foo": 1234}, 221 []interface{}{"foo", "bar", "baz", 1, 2, 3}, 222 "foo", 223 []byte("foo"), 224 json.RawMessage(`{"foo": "bar"}`), 225 true, 226 nil, 227 int(1234), int8(123), int16(123), int32(123), int64(123), 228 uint(123), uint8(123), uint16(123), uint32(123), uint64(123), 229 float32(123.45), float64(123.45), 230 } 231 232 for _, d := range testdata { 233 out, err := jqConvertType(d) 234 require.NoError(t, err) 235 assert.Equal(t, d, out) 236 } 237 }