// parseCloudConfig parses the provided config into a node structure and logs // any parsing issues into the provided report. Unrecoverable errors are // returned as an error. func parseCloudConfig(cfg []byte, report *Report) (node, error) { yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) { return nameIn } // unmarshal the config into an implicitly-typed form. The yaml library // will implicitly convert types into their normalized form // (e.g. 0744 -> 484, off -> false). var weak map[interface{}]interface{} if err := yaml.Unmarshal(cfg, &weak); err != nil { matches := yamlLineError.FindStringSubmatch(err.Error()) if len(matches) == 3 { line, err := strconv.Atoi(matches[1]) if err != nil { return node{}, err } msg := matches[2] report.Error(line, msg) return node{}, nil } matches = yamlError.FindStringSubmatch(err.Error()) if len(matches) == 2 { report.Error(1, matches[1]) return node{}, nil } return node{}, errors.New("couldn't parse yaml error") } w := NewNode(weak, NewContext(cfg)) w = normalizeNodeNames(w, report) // unmarshal the config into the explicitly-typed form. yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) { return strings.Replace(nameIn, "-", "_", -1) } var strong config.CloudConfig if err := yaml.Unmarshal([]byte(cfg), &strong); err != nil { return node{}, err } s := NewNode(strong, NewContext(cfg)) // coerceNodes weak nodes and strong nodes. strong nodes replace weak nodes // if they are compatible types (this happens when the yaml library // converts the input). // (e.g. weak 484 is replaced by strong 0744, weak 4 is not replaced by // strong false) return coerceNodes(w, s), nil }
func (s *S) TestUnmarshalErrors(c *C) { for _, item := range unmarshalErrorTests { var value interface{} err := yaml.Unmarshal([]byte(item.data), &value) c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value)) } }
func (s *S) TestUnmarshal(c *C) { for i, item := range unmarshalTests { t := reflect.ValueOf(item.value).Type() var value interface{} switch t.Kind() { case reflect.Map: value = reflect.MakeMap(t).Interface() case reflect.String: t := reflect.ValueOf(item.value).Type() v := reflect.New(t) value = v.Interface() default: pt := reflect.ValueOf(item.value).Type() pv := reflect.New(pt.Elem()) value = pv.Interface() } err := yaml.Unmarshal([]byte(item.data), value) c.Assert(err, IsNil, Commentf("Item #%d", i)) if t.Kind() == reflect.String { c.Assert(*value.(*string), Equals, item.value, Commentf("Item #%d", i)) } else { c.Assert(value, DeepEquals, item.value, Commentf("Item #%d", i)) } } }
// NewCloudConfig instantiates a new CloudConfig from the given contents (a // string of YAML), returning any error encountered. It will ignore unknown // fields but log encountering them. func NewCloudConfig(contents string) (*CloudConfig, error) { yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) { return strings.Replace(nameIn, "-", "_", -1) } var cfg CloudConfig err := yaml.Unmarshal([]byte(contents), &cfg) return &cfg, err }
func (s *S) TestUnmarshalWholeDocumentWithSetter(c *C) { obj := &typeWithSetter{} err := yaml.Unmarshal([]byte(setterTests[0].data), obj) c.Assert(err, IsNil) c.Assert(obj.tag, Equals, setterTests[0].tag) value, ok := obj.value.(map[interface{}]interface{}) c.Assert(ok, Equals, true) c.Assert(value["_"], DeepEquals, setterTests[0].value) }
func (s *S) TestUnmarshalWithValueSetter(c *C) { for _, item := range setterTests { obj := &setterValueType{} err := yaml.Unmarshal([]byte(item.data), obj) c.Assert(err, IsNil) c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) c.Assert(obj.Field.tag, Equals, item.tag) c.Assert(obj.Field.value, DeepEquals, item.value) } }
func (s *S) TestUnmarshalNull(c *C) { for _, test := range unmarshalNullTests { item := test() zero := reflect.Zero(reflect.TypeOf(item).Elem()).Interface() err := yaml.Unmarshal([]byte("null"), item) c.Assert(err, IsNil) if reflect.TypeOf(item).Kind() == reflect.Map { c.Assert(reflect.ValueOf(item).Interface(), DeepEquals, reflect.MakeMap(reflect.TypeOf(item)).Interface()) } else { c.Assert(reflect.ValueOf(item).Elem().Interface(), DeepEquals, zero) } } }
func (s *S) TestUnmarshalWithTransform(c *C) { data := `{a_b: 1, c-d: 2, e-f_g: 3, h_i-j: 4}` expect := map[string]int{ "a_b": 1, "c_d": 2, "e_f_g": 3, "h_i_j": 4, } m := map[string]int{} yaml.UnmarshalMappingKeyTransform = func(i string) string { return strings.Replace(i, "-", "_", -1) } err := yaml.Unmarshal([]byte(data), m) c.Assert(err, IsNil) c.Assert(m, DeepEquals, expect) }
func (s *S) TestMergeStruct(c *C) { type Data struct { X, Y, R int Label string } want := Data{1, 2, 10, "center/big"} var m map[string]Data err := yaml.Unmarshal([]byte(mergeTests), &m) c.Assert(err, IsNil) for name, test := range m { if name == "anchors" { continue } c.Assert(test, Equals, want, Commentf("test %q failed", name)) } }
func (s *S) TestMerge(c *C) { var want = map[interface{}]interface{}{ "x": 1, "y": 2, "r": 10, "label": "center/big", } var m map[string]interface{} err := yaml.Unmarshal([]byte(mergeTests), &m) c.Assert(err, IsNil) for name, test := range m { if name == "anchors" { continue } c.Assert(test, DeepEquals, want, Commentf("test %q failed", name)) } }
func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) { setterResult[2] = false setterResult[4] = false defer func() { delete(setterResult, 2) delete(setterResult, 4) }() m := map[string]*typeWithSetter{} data := `{abc: 1, def: 2, ghi: 3, jkl: 4}` err := yaml.Unmarshal([]byte(data), m) c.Assert(err, IsNil) c.Assert(m["abc"], NotNil) c.Assert(m["def"], IsNil) c.Assert(m["ghi"], NotNil) c.Assert(m["jkl"], IsNil) c.Assert(m["abc"].value, Equals, 1) c.Assert(m["ghi"].value, Equals, 3) }
func (s *S) TestUnmarshalNaN(c *C) { value := map[string]interface{}{} err := yaml.Unmarshal([]byte("notanum: .NaN"), &value) c.Assert(err, IsNil) c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true) }