@@ -15,11 +15,143 @@ import (
1515 "github.com/stretchr/testify/require"
1616
1717 "github.com/grafana/alloy/internal/runtime/equality"
18+ "github.com/grafana/alloy/syntax"
1819 "github.com/grafana/alloy/syntax/parser"
1920 "github.com/grafana/alloy/syntax/token/builder"
2021 "github.com/grafana/alloy/syntax/vm"
2122)
2223
24+ func TestUsingTargetCapsule (t * testing.T ) {
25+ type testCase struct {
26+ name string
27+ inputTarget map [string ]string
28+ expression string
29+ decodeInto interface {}
30+ expectedDecodedString string
31+ expectedEvalError string
32+ }
33+
34+ testCases := []testCase {
35+ {
36+ name : "target to map of string -> string" ,
37+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "ice" : "ice" },
38+ expression : "t" ,
39+ decodeInto : map [string ]string {},
40+ expectedDecodedString : `{"a1a"="beachfront avenue", "ice"="ice"}` ,
41+ },
42+ {
43+ name : "target to map of string -> any" ,
44+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "ice" : "ice" },
45+ expression : "t" ,
46+ decodeInto : map [string ]any {},
47+ expectedDecodedString : `{"a1a"="beachfront avenue", "ice"="ice"}` ,
48+ },
49+ {
50+ name : "target to map of any -> any" ,
51+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "ice" : "ice" },
52+ expression : "t" ,
53+ decodeInto : map [any ]any {},
54+ expectedDecodedString : `{"a1a"="beachfront avenue", "ice"="ice"}` ,
55+ },
56+ {
57+ name : "target to map of string -> syntax.Value" ,
58+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" },
59+ expression : "t" ,
60+ decodeInto : map [string ]syntax.Value {},
61+ expectedDecodedString : `{"a1a"="beachfront avenue"}` ,
62+ },
63+ {
64+ name : "target indexing a string value" ,
65+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "hip" : "hop" },
66+ expression : `t["hip"]` ,
67+ decodeInto : "" ,
68+ expectedDecodedString : `hop` ,
69+ },
70+ {
71+ name : "target indexing a non-existing string value" ,
72+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "hip" : "hop" },
73+ expression : `t["boom"]` ,
74+ decodeInto : "" ,
75+ expectedDecodedString : "<nil>" ,
76+ },
77+ {
78+ name : "target indexing a value like an object field" ,
79+ inputTarget : map [string ]string {"a1a" : "beachfront avenue" , "hip" : "hop" },
80+ expression : `t.boom` ,
81+ decodeInto : "" ,
82+ expectedEvalError : `field "boom" does not exist` ,
83+ },
84+ {
85+ name : "targets passed to concat" ,
86+ inputTarget : map [string ]string {"boom" : "bap" , "hip" : "hop" },
87+ expression : `array.concat([t], [t])` ,
88+ decodeInto : []Target {},
89+ expectedDecodedString : `[{"boom"="bap", "hip"="hop"} {"boom"="bap", "hip"="hop"}]` ,
90+ },
91+ {
92+ name : "coalesce an empty target" ,
93+ inputTarget : map [string ]string {},
94+ expression : `coalesce(t, [], t, {}, t, 123, t)` ,
95+ decodeInto : []Target {},
96+ expectedDecodedString : `123` ,
97+ },
98+ {
99+ name : "coalesce a non-empty target" ,
100+ inputTarget : map [string ]string {"big" : "bang" },
101+ expression : `coalesce([], {}, "", t, 321, [])` ,
102+ decodeInto : []Target {},
103+ expectedDecodedString : `{"big"="bang"}` ,
104+ },
105+ {
106+ name : "array.combine_maps with targets" ,
107+ inputTarget : map [string ]string {"a" : "a1" , "b" : "b1" },
108+ expression : `array.combine_maps([t, t], [{"a" = "a1", "c" = "c1"}, {"a" = "a2", "c" = "c2"}], ["a"])` ,
109+ decodeInto : []Target {},
110+ expectedDecodedString : `[map[a:a1 b:b1 c:c1] map[a:a1 b:b1 c:c1]]` ,
111+ },
112+ }
113+ for _ , tc := range testCases {
114+ t .Run (tc .name , func (t * testing.T ) {
115+ target := NewTargetFromMap (tc .inputTarget )
116+ scope := vm .NewScope (map [string ]interface {}{"t" : target })
117+ expr , err := parser .ParseExpression (tc .expression )
118+ require .NoError (t , err )
119+ eval := vm .New (expr )
120+ evalError := eval .Evaluate (scope , & tc .decodeInto )
121+ if tc .expectedEvalError != "" {
122+ require .ErrorContains (t , evalError , tc .expectedEvalError )
123+ } else {
124+ require .NoError (t , evalError )
125+ }
126+ require .Equal (t , tc .expectedDecodedString , fmt .Sprintf ("%v" , tc .decodeInto ))
127+ })
128+ }
129+ }
130+
131+ func TestNestedIndexing (t * testing.T ) {
132+ targets := []Target {
133+ NewTargetFromMap (map [string ]string {"foo" : "bar" , "boom" : "bap" }),
134+ NewTargetFromMap (map [string ]string {"hip" : "hop" , "dont" : "stop" }),
135+ }
136+ scope := vm .NewScope (map [string ]interface {}{"targets" : targets })
137+
138+ expr , err := parser .ParseExpression (`targets[1]["dont"]` )
139+ require .NoError (t , err )
140+ eval := vm .New (expr )
141+ actual := ""
142+ err = eval .Evaluate (scope , & actual )
143+ require .NoError (t , err )
144+ require .Equal (t , "stop" , actual )
145+
146+ expr , err = parser .ParseExpression (`targets[0].boom` )
147+ require .NoError (t , err )
148+ eval = vm .New (expr )
149+ actual = ""
150+ err = eval .Evaluate (scope , & actual )
151+ require .NoError (t , err )
152+ require .Equal (t , "bap" , actual )
153+ }
154+
23155func TestDecodeMap (t * testing.T ) {
24156 type testCase struct {
25157 name string
@@ -68,6 +200,11 @@ func TestDecodeMap(t *testing.T) {
68200 input : `{ "b" = string.format("%x", 31337), "a" = string.join(["2", "0"], ".") }` ,
69201 expected : map [string ]string {"a" : "2.0" , "b" : "7a69" },
70202 },
203+ {
204+ name : "decode with encoding.from_json function" ,
205+ input : "encoding.from_json(`{ \" __address__\" : \" localhost:8080\" , \" x\" : 123 }`)" ,
206+ expected : map [string ]string {"__address__" : "localhost:8080" , "x" : "123" },
207+ },
71208 }
72209
73210 for _ , tc := range tests {
@@ -298,6 +435,40 @@ func TestDecode_TargetArrays(t *testing.T) {
298435 {"e" : "5" , "f" : "10" },
299436 },
300437 },
438+ {
439+ name : "from_json" ,
440+ input : "encoding.from_json(`[ { \" __address__\" : \" localhost:8080\" , \" foo\" : 123 }, {}, {\" bap\" : \" boom\" } ]`)" ,
441+ expected : []map [string ]string {
442+ {"__address__" : "localhost:8080" , "foo" : "123" },
443+ {},
444+ {"bap" : "boom" },
445+ },
446+ },
447+ {
448+ name : "from_json one by one" ,
449+ input : "[encoding.from_json(`{ \" __address__\" : \" localhost:8080\" , \" foo\" : 123 }`), encoding.from_json(`{ \" boom\" : \" bap\" , \" foo\" : 321 }`)]" ,
450+ expected : []map [string ]string {
451+ {"__address__" : "localhost:8080" , "foo" : "123" },
452+ {"boom" : "bap" , "foo" : "321" },
453+ },
454+ },
455+ {
456+ name : "from_yaml" ,
457+ input : "encoding.from_yaml(`[ { __address__: localhost:8080, foo: 123 }, {}, {bap: boom} ]`)" ,
458+ expected : []map [string ]string {
459+ {"__address__" : "localhost:8080" , "foo" : "123" },
460+ {},
461+ {"bap" : "boom" },
462+ },
463+ },
464+ {
465+ name : "combine_maps" ,
466+ input : `array.combine_maps([{"a" = "a1", "b" = "b1"}, {"a" = "a1", "b" = "b1"}], [{"a" = "a1", "c" = "c1"}], ["a"])` ,
467+ expected : []map [string ]string {
468+ {"a" : "a1" , "b" : "b1" , "c" : "c1" },
469+ {"a" : "a1" , "b" : "b1" , "c" : "c1" },
470+ },
471+ },
301472 }
302473
303474 for _ , tc := range tests {
0 commit comments