From 6655c8336fa058d61cc9413dd188af0d830418fa Mon Sep 17 00:00:00 2001 From: Albertin Loic Date: Tue, 14 Aug 2018 16:06:46 +0200 Subject: [PATCH] Parses value assignments literals directly as string. Resolves #137. --- tosca/value_assignment.go | 45 ++++++++++++++++++++++++---------- tosca/value_assignment_test.go | 38 ++++++++++++++++++---------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/tosca/value_assignment.go b/tosca/value_assignment.go index ca6c23331..1118f66ac 100644 --- a/tosca/value_assignment.go +++ b/tosca/value_assignment.go @@ -165,7 +165,21 @@ func (p ValueAssignment) String() string { // UnmarshalYAML unmarshals a yaml into a ValueAssignment func (p *ValueAssignment) UnmarshalYAML(unmarshal func(interface{}) error) error { - return p.unmarshalYAMLJSON(unmarshal) + if err := p.unmarshalYAMLJSON(unmarshal); err == nil { + return nil + } + + // Not a List nor a TOSCA function, nor a map or complex type, let's try literal + // For YAML parsing literals are always considered as string + var s string + if err := unmarshal(&s); err != nil { + return err + } + + p.Value = s + p.Type = ValueAssignmentLiteral + return nil + } // UnmarshalJSON unmarshals json into a ValueAssignment @@ -174,7 +188,20 @@ func (p *ValueAssignment) UnmarshalJSON(b []byte) error { jsonUnmarshal := func(itf interface{}) error { return json.Unmarshal(b, itf) } - return p.unmarshalYAMLJSON(jsonUnmarshal) + if err := p.unmarshalYAMLJSON(jsonUnmarshal); err == nil { + return nil + } + + // Not a List nor a TOSCA function, nor a map or complex type, let's try literal + // For JSON it could be any type + var s interface{} + if err := jsonUnmarshal(&s); err != nil { + return err + } + + p.Value = s + p.Type = ValueAssignmentLiteral + return nil } // unmarshalYAMLJSON unmarshals yaml or json into a ValueAssignment @@ -210,20 +237,12 @@ func (p *ValueAssignment) unmarshalYAMLJSON(unmarshal func(interface{}) error) e // JSON map unmarshaling expects a map[string]interface{} var strMap map[string]interface{} - if err := unmarshal(&strMap); err == nil { - p.Value = strMap - p.Type = ValueAssignmentMap - return nil - } - - // Not a List nor a TOSCA function, nor a map or complex type, let's try literal - var s interface{} - if err := unmarshal(&s); err != nil { + if err := unmarshal(&strMap); err != nil { return err } - p.Value = s - p.Type = ValueAssignmentLiteral + p.Value = strMap + p.Type = ValueAssignmentMap return nil } diff --git a/tosca/value_assignment_test.go b/tosca/value_assignment_test.go index dadd0c834..125e8cd56 100644 --- a/tosca/value_assignment_test.go +++ b/tosca/value_assignment_test.go @@ -213,22 +213,24 @@ func TestValueAssignment_UnmarshalYAML(t *testing.T) { yaml string } tests := []struct { - name string - args args - wantErr bool - wantType ValueAssignmentType + name string + args args + wantErr bool + wantType ValueAssignmentType + wantValue string }{ - {"StringLiteral", args{"1"}, false, ValueAssignmentLiteral}, - {"FunctionSimple", args{"{ get_property: [SELF, port] }"}, false, ValueAssignmentFunction}, - {"FunctionNested", args{`{concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port]]}`}, false, ValueAssignmentFunction}, - {"FunctionNestedErr", args{`{ concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port] }`}, true, ValueAssignmentFunction}, - {"ListShort", args{`["1", "two"]`}, false, ValueAssignmentList}, + {"VersionLiteral", args{`1.10`}, false, ValueAssignmentLiteral, "1.10"}, + {"StringLiteral", args{"1"}, false, ValueAssignmentLiteral, "1"}, + {"FunctionSimple", args{"{ get_property: [SELF, port] }"}, false, ValueAssignmentFunction, "get_property: [SELF, port]"}, + {"FunctionNested", args{`{concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port]]}`}, false, ValueAssignmentFunction, `concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port]]`}, + {"FunctionNestedErr", args{`{ concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port] }`}, true, ValueAssignmentFunction, `concat: [get_attribute: [SELF, ip_address], ":", get_property: [SELF, port]"`}, + {"ListShort", args{`["1", "two"]`}, false, ValueAssignmentList, `["1", "two"]`}, {"ListExpend", args{`- "1" - "two" -`}, false, ValueAssignmentList}, - {"MapShort", args{`{"1": "one", 2: "two"}`}, false, ValueAssignmentMap}, +`}, false, ValueAssignmentList, `["1", "two"]`}, + {"MapShort", args{`{"1": "one", 2: "two"}`}, false, ValueAssignmentMap, `{"1": "one", 2: "two"}`}, {"MapExpend", args{`"1": "one" -2: "two"`}, false, ValueAssignmentMap}, +2: "two"`}, false, ValueAssignmentMap, `{"1": "one", 2: "two"}`}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -241,6 +243,15 @@ func TestValueAssignment_UnmarshalYAML(t *testing.T) { } if err == nil { require.Equal(t, tt.wantType, p.Type) + if tt.wantType != ValueAssignmentMap { + // Maps can't be tested reliably as we can't ensure keys order + assert.Equal(t, tt.wantValue, p.String()) + } else { + var m map[interface{}]interface{} + err := yaml.Unmarshal([]byte(tt.wantValue), &m) + require.NoError(t, err) + assert.Equal(t, m, p.Value) + } } }) } @@ -365,6 +376,7 @@ func TestValueAssignment_UnmarshalJSON(t *testing.T) { wantType ValueAssignmentType wantValue interface{} }{ + {"IntLiteral", `1.10`, ValueAssignmentLiteral, 1.10}, {"StringLiteral", `"abc"`, ValueAssignmentLiteral, "abc"}, {"List", `["1", "two"]`, ValueAssignmentList, []interface{}{"1", "two"}}, {"Map", `{"one":"val1","two":"val2"}`, ValueAssignmentMap, @@ -382,7 +394,7 @@ func TestValueAssignment_UnmarshalJSON(t *testing.T) { assert.Equal(t, tt.wantType.String(), v.Type.String(), "Unexpected type error unmarshalling %s", tt.jsonVal) assert.Equal(t, tt.wantValue, v.Value, - "Unexpected value error unmarshalling %s", tt.jsonVal) + "Unexpected value error unmarshalling %s (%t)", tt.jsonVal, v.Value) } }) }