github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/encoding/kmgYaml/decode_test.go (about)

     1  package kmgYaml
     2  
     3  import (
     4  	"math"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/bronze1man/kmg/kmgTest"
    10  )
    11  
    12  var unmarshalIntTest = 123
    13  var unmarshalTimeTest = time.Date(2001, 2, 3, 4, 5, 6, 0, time.UTC)
    14  var unmarshalTests = []struct {
    15  	data  string
    16  	value interface{}
    17  }{
    18  	{
    19  		"",
    20  		&struct{}{},
    21  	}, {
    22  		"{}", &struct{}{},
    23  	}, {
    24  		"v: hi",
    25  		map[string]string{"v": "hi"},
    26  	}, {
    27  		"v: hi", map[string]interface{}{"v": "hi"},
    28  	}, {
    29  		"v: true",
    30  		map[string]string{"v": "true"},
    31  	}, {
    32  		"v: true",
    33  		map[string]interface{}{"v": true},
    34  	}, {
    35  		"v: 10",
    36  		map[string]interface{}{"v": 10},
    37  	}, {
    38  		"v: 0b10",
    39  		map[string]interface{}{"v": 2},
    40  	}, {
    41  		"v: 0xA",
    42  		map[string]interface{}{"v": 10},
    43  	}, {
    44  		"v: 4294967296",
    45  		map[string]int64{"v": 4294967296},
    46  	}, {
    47  		"v: 0.1",
    48  		map[string]interface{}{"v": 0.1},
    49  	}, {
    50  		"v: .1",
    51  		map[string]interface{}{"v": 0.1},
    52  	}, {
    53  		"v: .Inf",
    54  		map[string]interface{}{"v": math.Inf(+1)},
    55  	}, {
    56  		"v: -.Inf",
    57  		map[string]interface{}{"v": math.Inf(-1)},
    58  	}, {
    59  		"v: -10",
    60  		map[string]interface{}{"v": -10},
    61  	}, {
    62  		"v: -.1",
    63  		map[string]interface{}{"v": -0.1},
    64  	},
    65  
    66  	// Simple values.
    67  	{
    68  		"123",
    69  		&unmarshalIntTest,
    70  	},
    71  
    72  	// Floats from spec
    73  	{
    74  		"canonical: 6.8523e+5",
    75  		map[string]interface{}{"canonical": 6.8523e+5},
    76  	}, {
    77  		"expo: 685.230_15e+03",
    78  		map[string]interface{}{"expo": 685.23015e+03},
    79  	}, {
    80  		"fixed: 685_230.15",
    81  		map[string]interface{}{"fixed": 685230.15},
    82  	}, {
    83  		"neginf: -.inf",
    84  		map[string]interface{}{"neginf": math.Inf(-1)},
    85  	}, {
    86  		"fixed: 685_230.15",
    87  		map[string]float64{"fixed": 685230.15},
    88  	},
    89  	//{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
    90  	//{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
    91  
    92  	// Bools from spec
    93  	{
    94  		"canonical: y",
    95  		map[string]interface{}{"canonical": true},
    96  	}, {
    97  		"answer: NO",
    98  		map[string]interface{}{"answer": false},
    99  	}, {
   100  		"logical: True",
   101  		map[string]interface{}{"logical": true},
   102  	}, {
   103  		"option: on",
   104  		map[string]interface{}{"option": true},
   105  	}, {
   106  		"option: on",
   107  		map[string]bool{"option": true},
   108  	},
   109  	// Ints from spec
   110  	{
   111  		"canonical: 685230",
   112  		map[string]interface{}{"canonical": 685230},
   113  	}, {
   114  		"decimal: +685_230",
   115  		map[string]interface{}{"decimal": 685230},
   116  	}, {
   117  		"octal: 02472256",
   118  		map[string]interface{}{"octal": 685230},
   119  	}, {
   120  		"hexa: 0x_0A_74_AE",
   121  		map[string]interface{}{"hexa": 685230},
   122  	}, {
   123  		"bin: 0b1010_0111_0100_1010_1110",
   124  		map[string]interface{}{"bin": 685230},
   125  	}, {
   126  		"bin: -0b101010",
   127  		map[string]interface{}{"bin": -42},
   128  	}, {
   129  		"decimal: +685_230",
   130  		map[string]int{"decimal": 685230},
   131  	},
   132  
   133  	//{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
   134  
   135  	// Nulls from spec
   136  	{
   137  		"empty:",
   138  		map[string]interface{}{"empty": nil},
   139  	}, {
   140  		"canonical: ~",
   141  		map[string]interface{}{"canonical": nil},
   142  	}, {
   143  		"english: null",
   144  		map[string]interface{}{"english": nil},
   145  	}, {
   146  		"~: null key",
   147  		map[interface{}]string{nil: "null key"},
   148  	}, {
   149  		"empty:",
   150  		map[string]*bool{"empty": nil},
   151  	},
   152  
   153  	// Flow sequence
   154  	{
   155  		"seq: [A,B]",
   156  		map[string]interface{}{"seq": []interface{}{"A", "B"}},
   157  	}, {
   158  		"seq: [A,B,C,]",
   159  		map[string][]string{"seq": {"A", "B", "C"}},
   160  	}, {
   161  		"seq: [A,1,C]",
   162  		map[string][]string{"seq": {"A", "1", "C"}},
   163  	}, {
   164  		"seq: [A,1,C]",
   165  		map[string][]int{"seq": {1}},
   166  	}, {
   167  		"seq: [A,1,C]",
   168  		map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
   169  	},
   170  	// Block sequence
   171  	{
   172  		"seq:\n - A\n - B",
   173  		map[string]interface{}{"seq": []interface{}{"A", "B"}},
   174  	}, {
   175  		"seq:\n - A\n - B\n - C",
   176  		map[string][]string{"seq": {"A", "B", "C"}},
   177  	}, {
   178  		"seq:\n - A\n - 1\n - C",
   179  		map[string][]string{"seq": {"A", "1", "C"}},
   180  	}, {
   181  		"seq:\n - A\n - 1\n - C",
   182  		map[string][]int{"seq": {1}},
   183  	}, {
   184  		"seq:\n - A\n - 1\n - C",
   185  		map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
   186  	},
   187  
   188  	// Literal block scalar
   189  	{
   190  		"scalar: | # Comment\n\n literal\n\n \ttext\n\n",
   191  		map[string]string{"scalar": "\nliteral\n\n\ttext\n"},
   192  	},
   193  
   194  	// Folded block scalar
   195  	{
   196  		"scalar: > # Comment\n\n folded\n line\n \n next\n line\n  * one\n  * two\n\n last\n line\n\n",
   197  		map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"},
   198  	},
   199  
   200  	// Map inside interface with no type hints.
   201  	{
   202  		"a: {b: c}",
   203  		map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
   204  	},
   205  
   206  	// Structs and type conversions.
   207  	{
   208  		"Hello: world",
   209  		&struct{ Hello string }{"world"},
   210  	}, {
   211  		"A: {B: c}",
   212  		&struct{ A struct{ B string } }{struct{ B string }{"c"}},
   213  	}, {
   214  		"A: {B: c}",
   215  		&struct{ A *struct{ B string } }{&struct{ B string }{"c"}},
   216  	}, {
   217  		"A: {b: c}",
   218  		&struct{ A map[string]string }{map[string]string{"b": "c"}},
   219  	}, {
   220  		"A: {b: c}",
   221  		&struct{ A *map[string]string }{&map[string]string{"b": "c"}},
   222  	}, {
   223  		"A:",
   224  		&struct{ A map[string]string }{},
   225  	}, {
   226  		"A: 1",
   227  		&struct{ A int }{1},
   228  	}, {
   229  		"A: [1, 2]",
   230  		&struct{ A []int }{[]int{1, 2}},
   231  	}, {
   232  		"A: [1, 2]",
   233  		&struct{ A [2]int }{[2]int{1, 2}},
   234  	}, {
   235  		"A: 1",
   236  		&struct{ B int }{0},
   237  	}, {
   238  		"a: 1",
   239  		&struct {
   240  			B int "a"
   241  		}{1},
   242  	}, {
   243  		"A: y",
   244  		&struct{ A bool }{true},
   245  	},
   246  
   247  	// Some cross type conversions
   248  	{
   249  		"v: 42",
   250  		map[string]uint{"v": 42},
   251  	}, {
   252  		"v: -42",
   253  		map[string]uint{},
   254  	}, {
   255  		"v: 4294967296",
   256  		map[string]uint64{"v": 4294967296},
   257  	}, {
   258  		"v: -4294967296",
   259  		map[string]uint64{},
   260  	},
   261  
   262  	// Overflow cases.
   263  	{
   264  		"v: 4294967297",
   265  		map[string]int32{},
   266  	}, {
   267  		"v: 128",
   268  		map[string]int8{},
   269  	},
   270  
   271  	// Quoted values.
   272  	{
   273  		"'1': '\"2\"'",
   274  		map[interface{}]interface{}{"1": "\"2\""},
   275  	}, {
   276  		"v:\n- A\n- 'B\n\n  C'\n",
   277  		map[string][]string{"v": {"A", "B\nC"}},
   278  	},
   279  
   280  	// Explicit tags.
   281  	{
   282  		"v: !!float '1.1'",
   283  		map[string]interface{}{"v": 1.1},
   284  	}, {
   285  		"v: !!null ''",
   286  		map[string]interface{}{"v": nil},
   287  	}, {
   288  		"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
   289  		map[string]interface{}{"v": 1},
   290  	},
   291  
   292  	// Anchors and aliases.
   293  	{
   294  		"A: &x 1\nB: &y 2\nC: *x\nD: *y\n",
   295  		&struct{ A, B, C, D int }{1, 2, 1, 2},
   296  	}, {
   297  		"A: &a {C: 1}\nB: *a",
   298  		&struct {
   299  			A, B struct {
   300  				C int
   301  			}
   302  		}{struct{ C int }{1}, struct{ C int }{1}},
   303  	}, {
   304  		"A: &a [1, 2]\nB: *a",
   305  		&struct{ B []int }{[]int{1, 2}},
   306  	},
   307  
   308  	// Bug #1133337
   309  	{
   310  		"foo: ''",
   311  		map[string]*string{"foo": new(string)},
   312  	}, {
   313  		"foo: null",
   314  		map[string]string{},
   315  	},
   316  
   317  	// Ignored field
   318  	{
   319  		"A: 1\nB: 2\n",
   320  		&struct {
   321  			A int
   322  			B int "-"
   323  		}{1, 0},
   324  	},
   325  
   326  	// Bug #1191981
   327  	{
   328  		"" +
   329  			"%YAML 1.1\n" +
   330  			"--- !!str\n" +
   331  			`"Generic line break (no glyph)\n\` + "\n" +
   332  			` Generic line break (glyphed)\n\` + "\n" +
   333  			` Line separator\u2028\` + "\n" +
   334  			` Paragraph separator\u2029"` + "\n",
   335  		"" +
   336  			"Generic line break (no glyph)\n" +
   337  			"Generic line break (glyphed)\n" +
   338  			"Line separator\u2028Paragraph separator\u2029",
   339  	},
   340  
   341  	// Struct inlining
   342  	{
   343  		"A: 1\nB: 2\nC: 3\n",
   344  		&struct {
   345  			A int
   346  			C inlineB `yaml:",inline"`
   347  		}{1, inlineB{2, inlineC{3}}},
   348  	},
   349  	{
   350  		`0: 2
   351  1: 0.4
   352  2: 0.7
   353  3: 1
   354  4: 1.5
   355  `,
   356  		map[int]float64{
   357  			0: 2.0,
   358  			1: 0.4,
   359  			2: 0.7,
   360  			3: 1.0,
   361  			4: 1.5,
   362  		},
   363  	},
   364  	{
   365  		`2001-02-03T04:05:06Z`,
   366  		&unmarshalTimeTest,
   367  	},
   368  }
   369  
   370  type inlineB struct {
   371  	B       int
   372  	inlineC `yaml:",inline"`
   373  }
   374  
   375  type inlineC struct {
   376  	C int
   377  }
   378  
   379  func (c *S) TestUnmarshal() {
   380  	for _, item := range unmarshalTests {
   381  		t := reflect.ValueOf(item.value).Type()
   382  		var value interface{}
   383  		switch t.Kind() {
   384  		case reflect.Map:
   385  			value = reflect.MakeMap(t).Interface()
   386  		case reflect.String:
   387  			t := reflect.ValueOf(item.value).Type()
   388  			v := reflect.New(t)
   389  			value = v.Interface()
   390  		case reflect.Ptr:
   391  			pt := t
   392  			pv := reflect.New(pt.Elem())
   393  			value = pv.Interface()
   394  		default:
   395  			pt := t
   396  			pv := reflect.New(pt)
   397  			value = pv.Interface()
   398  		}
   399  		err := Unmarshal([]byte(item.data), value)
   400  		c.Equal(err, nil)
   401  		//c.Assert(err, IsNil, Commentf("Item #%d", i))
   402  		if t.Kind() == reflect.String {
   403  			c.Equal(*value.(*string), item.value)
   404  			//c.Assert(*value.(*string), Equals, item.value, Commentf("Item #%d", i))
   405  		} else {
   406  			c.Equal(value, item.value)
   407  			//c.Assert(value, DeepEquals, item.value, Commentf("Item #%d", i))
   408  		}
   409  	}
   410  }
   411  
   412  func TestUnmarshalNaN(ot *testing.T) {
   413  	value := map[string]interface{}{}
   414  	err := Unmarshal([]byte("notanum: .NaN"), &value)
   415  	kmgTest.Equal(err, nil)
   416  	kmgTest.Equal(math.IsNaN(value["notanum"].(float64)), true)
   417  	//c.Assert(err, IsNil)
   418  	//c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
   419  }
   420  
   421  var unmarshalErrorTests = []struct {
   422  	data, error string
   423  }{
   424  	{"v: !!float 'error'", "YAML error: Can't decode !!str 'error' as a !!float"},
   425  	{"v: [A,", "YAML error: line 1: did not find expected node content"},
   426  	{"v:\n- [A,", "YAML error: line 2: did not find expected node content"},
   427  	{"a: *b\n", "YAML error: Unknown anchor 'b' referenced"},
   428  	{"a: &a\n  b: *a\n", "YAML error: Anchor 'a' value contains itself"},
   429  }
   430  
   431  func TestUnmarshalErrors(ot *testing.T) {
   432  	c := kmgTest.NewTestTools(ot)
   433  	for _, item := range unmarshalErrorTests {
   434  		var value interface{}
   435  		err := Unmarshal([]byte(item.data), &value)
   436  		c.Equal(err.Error(), item.error)
   437  	}
   438  }
   439  
   440  var setterTests = []struct {
   441  	data, tag string
   442  	value     interface{}
   443  }{
   444  	{"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
   445  	{"_: [1,A]", "!!seq", []interface{}{1, "A"}},
   446  	{"_: 10", "!!int", 10},
   447  	{"_: null", "!!null", nil},
   448  	{"_: !!foo 'BAR!'", "!!foo", "BAR!"},
   449  }
   450  
   451  var setterResult = map[int]bool{}
   452  
   453  type typeWithSetter struct {
   454  	tag   string
   455  	value interface{}
   456  }
   457  
   458  func (o *typeWithSetter) SetYAML(tag string, value interface{}) (ok bool) {
   459  	o.tag = tag
   460  	o.value = value
   461  	if i, ok := value.(int); ok {
   462  		if result, ok := setterResult[i]; ok {
   463  			return result
   464  		}
   465  	}
   466  	return true
   467  }
   468  
   469  type typeWithSetterField struct {
   470  	Field *typeWithSetter "_"
   471  }
   472  
   473  func TestUnmarshalWithSetter(ot *testing.T) {
   474  	c := kmgTest.NewTestTools(ot)
   475  	for _, item := range setterTests {
   476  		obj := &typeWithSetterField{}
   477  		err := Unmarshal([]byte(item.data), obj)
   478  		c.Equal(err, nil)
   479  		c.Ok(obj.Field != nil)
   480  		c.Equal(obj.Field.tag, item.tag)
   481  		c.Equal(obj.Field.value, item.value)
   482  		/*
   483  			c.Assert(err, IsNil)
   484  			c.Assert(obj.Field, NotNil,
   485  				Commentf("Pointer not initialized (%#v)", item.value))
   486  			c.Assert(obj.Field.tag, Equals, item.tag)
   487  			c.Assert(obj.Field.value, DeepEquals, item.value)
   488  		*/
   489  	}
   490  }
   491  
   492  func TestUnmarshalWholeDocumentWithSetter(ot *testing.T) {
   493  	c := kmgTest.NewTestTools(ot)
   494  	obj := &typeWithSetter{}
   495  	err := Unmarshal([]byte(setterTests[0].data), obj)
   496  	c.Equal(err, nil)
   497  	c.Equal(obj.tag, setterTests[0].tag)
   498  	//c.Assert(err, IsNil)
   499  	//c.Assert(obj.tag, Equals, setterTests[0].tag)
   500  
   501  	value, ok := obj.value.(map[interface{}]interface{})
   502  	c.Equal(ok, true)
   503  	c.Equal(value["_"], setterTests[0].value)
   504  
   505  	//c.Assert(ok, Equals, true)
   506  	//c.Assert(value["_"], DeepEquals, setterTests[0].value)
   507  }
   508  
   509  func TestUnmarshalWithFalseSetterIgnoresValue(ot *testing.T) {
   510  	setterResult[2] = false
   511  	setterResult[4] = false
   512  	defer func() {
   513  		delete(setterResult, 2)
   514  		delete(setterResult, 4)
   515  	}()
   516  
   517  	m := map[string]*typeWithSetter{}
   518  	data := "{abc: 1, def: 2, ghi: 3, jkl: 4}"
   519  	err := Unmarshal([]byte(data), m)
   520  	kmgTest.Equal(err, nil)
   521  	kmgTest.Ok(m["abc"] != nil)
   522  	kmgTest.Equal(m["def"], nil)
   523  	kmgTest.Ok(m["ghi"] != nil)
   524  	kmgTest.Equal(m["jkl"], nil)
   525  	kmgTest.Equal(m["abc"].value, 1)
   526  	kmgTest.Equal(m["ghi"].value, 3)
   527  }
   528  
   529  func TestUnmarshalTypeNotMatch(t *testing.T) {
   530  	data := `t1:
   531       k1: v1`
   532  	out := map[string][]map[string]string{}
   533  	err := Unmarshal([]byte(data), &out)
   534  	kmgTest.Ok(err != nil)
   535  }
   536  
   537  //var data []byte
   538  //func init() {
   539  //	var err error
   540  //	data, err = ioutil.ReadFile("/tmp/file.yaml")
   541  //	if err != nil {
   542  //		panic(err)
   543  //	}
   544  //}
   545  //
   546  //func (s *S) BenchmarkUnmarshal(c *C) {
   547  //	var err error
   548  //	for i := 0; i < c.N; i++ {
   549  //		var v map[string]interface{}
   550  //		err = goyaml.Unmarshal(data, &v)
   551  //	}
   552  //	if err != nil {
   553  //		panic(err)
   554  //	}
   555  //}
   556  //
   557  //func (s *S) BenchmarkMarshal(c *C) {
   558  //	var v map[string]interface{}
   559  //	goyaml.Unmarshal(data, &v)
   560  //	c.ResetTimer()
   561  //	for i := 0; i < c.N; i++ {
   562  //		goyaml.Marshal(&v)
   563  //	}
   564  //}