Skip to content

Commit 666070e

Browse files
committed
Add support to the map operator
Example compiled PlanOut code: { "op": "seq", "seq": [ { "op": "set", "var": "foo", "value": "inside" }, { "op": "set", "var": "baz", "value": { "bar": { "op": "get", "var": "foo" }, "op": "map" } }, { "op": "set", "var": "x", "value": { "a": 2, "b": { "op": "get", "var": "baz" }, "op": "map" } } ] } When the above code is interpreted, the variable 'x' will be assigned a map. This map contains two (k, v) pairs. "a" = 2 "b" = map containing the (k, v) "bar" = "inside". Update test for map operator ... test assignment of an empty dictionary
1 parent 90cd54b commit 666070e

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

core_ops_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package planout
1919
import (
2020
"encoding/json"
2121
"fmt"
22+
"reflect"
2223
"testing"
2324
)
2425

@@ -81,6 +82,42 @@ func TestCoreOps(t *testing.T) {
8182
{"op": "set", "var": "x", "value": {"op": "array", "values": [4, 5, "a"]}}`))
8283
x, _ = expt.Get("x")
8384

85+
// Test Dictionary
86+
expt, _ = runExperiment([]byte(`
87+
{"op": "set", "var": "x", "value": {"op": "map", "a": 2, "b": "foo", "c": [0, 1, 2]}}`))
88+
x, _ = expt.Get("x")
89+
if x == nil {
90+
t.Errorf("Variable x. Expected a map. Actual nil.\n")
91+
} else {
92+
x_map, ok := x.(map[string]interface{})
93+
if !ok {
94+
t.Errorf("Variable x. Expected of type map. Actual %v\n", reflect.TypeOf(x))
95+
}
96+
foo, ok := x_map["b"]
97+
if !ok {
98+
t.Errorf("Variable x['b']. Expected 'foo'. Does not exists.\n")
99+
}
100+
if foo != "foo" {
101+
t.Errorf("Variable x['b']. Expected 'foo'. Actual %v\n", foo)
102+
}
103+
}
104+
105+
// Test empty dictionary
106+
expt, _ = runExperiment([]byte(`
107+
{"op": "set", "var": "x", "value": {"op": "map"}}`))
108+
x, _ = expt.Get("x")
109+
if x == nil {
110+
t.Errorf("Variable x. Expected a map. Actual nil.\n")
111+
} else {
112+
x_map, ok := x.(map[string]interface{})
113+
if !ok {
114+
t.Errorf("Variable x. Expected of type map. Actual %v\n", reflect.TypeOf(x))
115+
}
116+
if len(x_map) != 0 {
117+
t.Errorf("Variable x. Expected empty map. Actual %v\n", x_map)
118+
}
119+
}
120+
84121
// Test Condition
85122
expt, _ = runExperiment([]byte(`
86123
{"op": "cond",

operators.go

+13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func init() {
3232
"set": &set{},
3333
"get": &get{},
3434
"array": &array{},
35+
"map": &dict{},
3536
"index": &index{},
3637
"length": &length{},
3738
"coalesce": &coalesce{},
@@ -127,6 +128,18 @@ func (s *array) execute(m map[string]interface{}, interpreter *Interpreter) inte
127128
return ret
128129
}
129130

131+
type dict struct{}
132+
133+
func (s *dict) execute(m map[string]interface{}, interpreter *Interpreter) interface{} {
134+
dictionary := make(map[string]interface{})
135+
for k, v := range m {
136+
if k != "op" {
137+
dictionary[k] = interpreter.evaluate(v)
138+
}
139+
}
140+
return dictionary
141+
}
142+
130143
type index struct{}
131144

132145
func (s *index) execute(m map[string]interface{}, interpreter *Interpreter) interface{} {

simple_ops_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,50 @@ func TestSimpleOps(t *testing.T) {
182182
t.Errorf("Variable 'z' '%v'. Expected 'test-string'\n", z2)
183183
}
184184
}
185+
186+
func TestMapOp(t *testing.T) {
187+
js := readTest("test/map_operator.json")
188+
189+
data := Struct{Member: 101, String: "test-string"}
190+
params := make(map[string]interface{})
191+
params["struct"] = data
192+
193+
expt := &Interpreter{
194+
Salt: "global_salt",
195+
Evaluated: false,
196+
Inputs: params,
197+
Outputs: map[string]interface{}{},
198+
Overrides: map[string]interface{}{},
199+
Code: js,
200+
}
201+
202+
_, ok := expt.Run()
203+
if !ok {
204+
t.Errorf("Error running experiment 'test/map_operator.json'\n")
205+
return
206+
}
207+
208+
x, exists := expt.Get("x")
209+
if !exists {
210+
t.Errorf("TestMapOp: Expected variable 'x' to be assigned.\n")
211+
}
212+
x_map, ok := x.(map[string]interface{})
213+
if !ok {
214+
t.Errorf("TestMapOp: Expected variable 'x' to be of type map. Actual %v\n", reflect.TypeOf(x))
215+
}
216+
b, exists := x_map["b"]
217+
if !exists {
218+
t.Errorf("TestMapOp: Expected variable 'b' inside the map 'x' to be assigned.\n")
219+
}
220+
b_map, ok := b.(map[string]interface{})
221+
if !ok {
222+
t.Errorf("TestMapOp: Expected variable 'b' to be of type map. Actual %v\n", reflect.TypeOf(b))
223+
}
224+
bar, exists := b_map["bar"]
225+
if !exists {
226+
t.Errorf("TestMapOp: Expected variable 'bar' inside the map 'b' to be assigned.\n")
227+
}
228+
if bar != "inside" {
229+
t.Errorf("TestMapOp: Variable='bar'. Expected value='inside' Actual=%v.\n", bar)
230+
}
231+
}

test/map_operator.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"op": "seq",
3+
"seq": [
4+
{
5+
"op": "set",
6+
"var": "foo",
7+
"value": "inside"
8+
},
9+
{
10+
"op": "set",
11+
"var": "baz",
12+
"value": {
13+
"bar": {
14+
"op": "get",
15+
"var": "foo"
16+
},
17+
"op": "map"
18+
}
19+
},
20+
{
21+
"op": "set",
22+
"var": "x",
23+
"value": {
24+
"a": 2,
25+
"b": {
26+
"op": "get",
27+
"var": "baz"
28+
},
29+
"op": "map"
30+
}
31+
}
32+
]
33+
}

0 commit comments

Comments
 (0)