Skip to content

Commit

Permalink
Handle nil values on indexing operations
Browse files Browse the repository at this point in the history
Hitting a nil value previously would cause a crash in the experiment run. This happens in both the
case of the value being in a map, and in the case where the value is part of a struct. This fix causes
the code to instead return a nil.
Unfortunately this is not quite ideal in the case of maps to numerical values.  In a normal go map,
maps with numerical values apparently return a 0 when the requested key is not present. There
doesn't seem to be any simple way to maintain parity with that behavior (though it does seem kind
of odd, looking at it from Java colored glasses), so a concession is made to just return a nil in that
case.
  • Loading branch information
timwu authored and GregBowyer committed Aug 3, 2018
1 parent 0a63106 commit c60a1c7
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
47 changes: 43 additions & 4 deletions index_op_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestArrayInStruct(t *testing.T) {
}

type StructWithMap struct {
Map map[string]string
Map map[string]int64
}

func TestMapField(t *testing.T) {
Expand All @@ -110,8 +110,8 @@ func TestMapField(t *testing.T) {
}

inputs := make(map[string]interface{})
mapField := make(map[string]string)
mapField["key"] = "value"
mapField := make(map[string]int64)
mapField["key"] = 42
inputs["s"] = &StructWithMap{
Map: mapField,
}
Expand All @@ -128,7 +128,46 @@ func TestMapField(t *testing.T) {
t.Fatal("Experiment run failed")
}

if elem := exp.Outputs["element"]; elem != "value" {
if elem := exp.Outputs["element"]; elem != int64(42) {
t.Fail()
}

if exp.Outputs["empty"] != nil {
t.Fail()
}
}

type StructWithNilField struct {
None interface{}
}

func TestStructWithNilField(t *testing.T) {
data, err := ioutil.ReadFile("test/struct_with_nil_field.json")
if err != nil {
t.Fatal(err)
}
var js map[string]interface{}
err = json.Unmarshal(data, &js)
if (err != nil) {
t.Fatal(err)
}

inputs := make(map[string]interface{})
inputs["struct"] = &StructWithNilField{}

exp := &Interpreter{
Name: "struct with nil field",
Salt: "safasdf",
Inputs: inputs,
Outputs: make(map[string]interface{}),
Code: js,
}

if _, ok := exp.Run(); !ok {
t.Fatal("Experiment run failed")
}

if exp.Outputs["nil"] != nil {
t.Fail()
}
}
6 changes: 5 additions & 1 deletion operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,11 @@ func unwrapValue(value reflect.Value) interface{} {
case reflect.Bool:
return value.Bool()
default:
return value.Interface()
if value.IsValid() {
return value.Interface()
} else {
return nil
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions test/map_index_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@
},
"index": "key"
}
},
{
"op": "set",
"var": "empty",
"value": {
"op": "index",
"base": {
"op": "get",
"var": "map"
},
"index": "not there"
}
}
]
}
12 changes: 12 additions & 0 deletions test/struct_with_nil_field.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"op": "set",
"var": "nil",
"value": {
"op": "index",
"base": {
"op": "get",
"var": "struct"
},
"index": "None"
}
}

0 comments on commit c60a1c7

Please sign in to comment.