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

     1  package kmgYaml
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  var marshalIntTest = 123
    12  
    13  var marshalTests = []struct {
    14  	value interface{}
    15  	data  string
    16  }{
    17  	{
    18  		&struct{}{},
    19  		"{}\n",
    20  	}, {
    21  		map[string]string{"v": "hi"},
    22  		"v: hi\n",
    23  	}, {
    24  		map[string]interface{}{"v": "hi"},
    25  		"v: hi\n",
    26  	}, {
    27  		map[string]string{"v": "true"},
    28  		"v: \"true\"\n",
    29  	}, {
    30  		map[string]string{"v": "false"},
    31  		"v: \"false\"\n",
    32  	}, {
    33  		map[string]interface{}{"v": true},
    34  		"v: true\n",
    35  	}, {
    36  		map[string]interface{}{"v": false},
    37  		"v: false\n",
    38  	}, {
    39  		map[string]interface{}{"v": 10},
    40  		"v: 10\n",
    41  	}, {
    42  		map[string]interface{}{"v": -10},
    43  		"v: -10\n",
    44  	}, {
    45  		map[string]uint{"v": 42},
    46  		"v: 42\n",
    47  	}, {
    48  		map[string]interface{}{"v": int64(4294967296)},
    49  		"v: 4294967296\n",
    50  	}, {
    51  		map[string]int64{"v": int64(4294967296)},
    52  		"v: 4294967296\n",
    53  	}, {
    54  		map[string]uint64{"v": 4294967296},
    55  		"v: 4294967296\n",
    56  	}, {
    57  		map[string]interface{}{"v": "10"},
    58  		"v: \"10\"\n",
    59  	}, {
    60  		map[string]interface{}{"v": 0.1},
    61  		"v: 0.1\n",
    62  	}, {
    63  		map[string]interface{}{"v": float64(0.1)},
    64  		"v: 0.1\n",
    65  	}, {
    66  		map[string]interface{}{"v": -0.1},
    67  		"v: -0.1\n",
    68  	}, {
    69  		map[string]interface{}{"v": math.Inf(+1)},
    70  		"v: .inf\n",
    71  	}, {
    72  		map[string]interface{}{"v": math.Inf(-1)},
    73  		"v: -.inf\n",
    74  	}, {
    75  		map[string]interface{}{"v": math.NaN()},
    76  		"v: .nan\n",
    77  	}, {
    78  		map[string]interface{}{"v": nil},
    79  		"v: null\n",
    80  	}, {
    81  		map[string]interface{}{"v": ""},
    82  		"v: \"\"\n",
    83  	}, {
    84  		map[string][]string{"v": {"A", "B"}},
    85  		"v:\n- A\n- B\n",
    86  	}, {
    87  		map[string][]string{"v": {"A", "B\nC"}},
    88  		"v:\n- A\n- 'B\n\n  C'\n",
    89  	}, {
    90  		map[string][]interface{}{"v": {"A", 1, map[string][]int{"B": {2, 3}}}},
    91  		"v:\n- A\n- 1\n- B:\n  - 2\n  - 3\n",
    92  	}, {
    93  		map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
    94  		"a:\n  b: c\n",
    95  	}, {
    96  		time.Date(2001, 2, 3, 4, 5, 6, 0, time.UTC),
    97  		"2001-02-03T04:05:06Z\n",
    98  	},
    99  
   100  	// Simple values.
   101  	{
   102  		&marshalIntTest,
   103  		"123\n",
   104  	},
   105  
   106  	// Structures
   107  	{
   108  		&struct{ Hello string }{"world"},
   109  		"Hello: world\n",
   110  	}, {
   111  		&struct {
   112  			A struct {
   113  				B string
   114  			}
   115  		}{struct{ B string }{"c"}},
   116  		"A:\n  B: c\n",
   117  	}, {
   118  		&struct {
   119  			A *struct {
   120  				B string
   121  			}
   122  		}{&struct{ B string }{"c"}},
   123  		"A:\n  B: c\n",
   124  	}, {
   125  		&struct {
   126  			A *struct {
   127  				B string
   128  			}
   129  		}{},
   130  		"A: null\n",
   131  	}, {
   132  		&struct{ A int }{1},
   133  		"A: 1\n",
   134  	}, {
   135  		&struct{ A []int }{[]int{1, 2}},
   136  		"A:\n- 1\n- 2\n",
   137  	}, {
   138  		&struct {
   139  			B int "a"
   140  		}{1},
   141  		"a: 1\n",
   142  	}, {
   143  		&struct{ A bool }{true},
   144  		"A: true\n",
   145  	},
   146  
   147  	// Conditional flag
   148  	{
   149  		&struct {
   150  			A int "a,omitempty"
   151  			B int "b,omitempty"
   152  		}{1, 0},
   153  		"a: 1\n",
   154  	}, {
   155  		&struct {
   156  			A int "a,omitempty"
   157  			B int "b,omitempty"
   158  		}{0, 0},
   159  		"{}\n",
   160  	}, {
   161  		&struct {
   162  			A *struct{ X int } "a,omitempty"
   163  			B int              "b,omitempty"
   164  		}{nil, 0},
   165  		"{}\n",
   166  	},
   167  
   168  	// Flow flag
   169  	{
   170  		&struct {
   171  			A []int "a,flow"
   172  		}{[]int{1, 2}},
   173  		"a: [1, 2]\n",
   174  	}, {
   175  		&struct {
   176  			A map[string]string "a,flow"
   177  		}{map[string]string{"b": "c", "d": "e"}},
   178  		"a: {b: c, d: e}\n",
   179  	}, {
   180  		&struct {
   181  			A struct {
   182  				B, D string
   183  			} "a,flow"
   184  		}{struct{ B, D string }{"c", "e"}},
   185  		"a: {B: c, D: e}\n",
   186  	},
   187  
   188  	// Unexported field
   189  	{
   190  		&struct {
   191  			u int
   192  			A int
   193  		}{0, 1},
   194  		"A: 1\n",
   195  	},
   196  
   197  	// Ignored field
   198  	{
   199  		&struct {
   200  			A int
   201  			B int "-"
   202  		}{1, 2},
   203  		"A: 1\n",
   204  	},
   205  
   206  	// Struct inlining
   207  	{
   208  		&struct {
   209  			A int
   210  			C inlineB `yaml:",inline"`
   211  		}{1, inlineB{2, inlineC{3}}},
   212  		"A: 1\nB: 2\nC: 3\n",
   213  	},
   214  }
   215  
   216  func (t *S) TestMarshal() {
   217  	for _, item := range marshalTests {
   218  		data, err := Marshal(item.value)
   219  		t.Equal(err, nil)
   220  		t.Equal(string(data), item.data)
   221  	}
   222  }
   223  
   224  type T1 struct {
   225  	T2
   226  }
   227  type T2 struct {
   228  	Start int
   229  	End   int
   230  }
   231  
   232  //对golang系统的inline的支持
   233  func (t *S) TestGolangInline() {
   234  	data, err := Marshal(T1{T2{Start: 1, End: 2}})
   235  	t.Equal(err, nil)
   236  	t.Equal(string(data), "Start: 1\nEnd: 2\n")
   237  }
   238  
   239  var marshalErrorTests = []struct {
   240  	value interface{}
   241  	error string
   242  }{
   243  	{
   244  		&struct {
   245  			B       int
   246  			inlineB ",inline"
   247  		}{1, inlineB{2, inlineC{3}}},
   248  		`Duplicated key 'B' in struct struct { B int; kmgYaml.inlineB ",inline" }`,
   249  	},
   250  }
   251  
   252  func (t *S) TestMarshalErrors() {
   253  	for _, item := range marshalErrorTests {
   254  		_, err := Marshal(item.value)
   255  		t.Ok(err != nil)
   256  		t.Equal(err.Error(), item.error)
   257  	}
   258  }
   259  
   260  var marshalTaggedIfaceTest interface{} = &struct{ A string }{"B"}
   261  
   262  var getterTests = []struct {
   263  	data, tag string
   264  	value     interface{}
   265  }{
   266  	{"_:\n  hi: there\n", "", map[interface{}]interface{}{"hi": "there"}},
   267  	{"_:\n- 1\n- A\n", "", []interface{}{1, "A"}},
   268  	{"_: 10\n", "", 10},
   269  	{"_: null\n", "", nil},
   270  	{"_: !foo BAR!\n", "!foo", "BAR!"},
   271  	{"_: !foo 1\n", "!foo", "1"},
   272  	{"_: !foo '\"1\"'\n", "!foo", "\"1\""},
   273  	{"_: !foo 1.1\n", "!foo", 1.1},
   274  	{"_: !foo 1\n", "!foo", 1},
   275  	{"_: !foo 1\n", "!foo", uint(1)},
   276  	{"_: !foo true\n", "!foo", true},
   277  	{"_: !foo\n- A\n- B\n", "!foo", []string{"A", "B"}},
   278  	{"_: !foo\n  A: B\n", "!foo", map[string]string{"A": "B"}},
   279  	{"_: !foo\n  A: B\n", "!foo", &marshalTaggedIfaceTest},
   280  }
   281  
   282  func (t *S) TestMarshalTypeCache() {
   283  	var data []byte
   284  	var err error
   285  	func() {
   286  		type T struct{ A int }
   287  		data, err = Marshal(&T{})
   288  		t.Equal(err, nil)
   289  	}()
   290  	func() {
   291  		type T struct{ B int }
   292  		data, err = Marshal(&T{})
   293  		t.Equal(err, nil)
   294  	}()
   295  	t.Equal(string(data), "B: 0\n")
   296  }
   297  
   298  type typeWithGetter struct {
   299  	tag   string
   300  	value interface{}
   301  }
   302  
   303  func (o typeWithGetter) GetYAML() (tag string, value interface{}) {
   304  	return o.tag, o.value
   305  }
   306  
   307  type typeWithGetterField struct {
   308  	Field typeWithGetter "_"
   309  }
   310  
   311  func (t *S) TestMashalWithGetter() {
   312  	for _, item := range getterTests {
   313  		obj := &typeWithGetterField{}
   314  		obj.Field.tag = item.tag
   315  		obj.Field.value = item.value
   316  		data, err := Marshal(obj)
   317  		t.Equal(err, nil)
   318  		t.Equal(string(data), string(item.data))
   319  	}
   320  }
   321  
   322  func (t *S) TestUnmarshalWholeDocumentWithGetter() {
   323  	obj := &typeWithGetter{}
   324  	obj.tag = ""
   325  	obj.value = map[string]string{"hello": "world!"}
   326  	data, err := Marshal(obj)
   327  	t.Equal(err, nil)
   328  	t.Equal(string(data), "hello: world!\n")
   329  }
   330  
   331  func (t *S) TestSortedOutput() {
   332  	order := []interface{}{
   333  		false,
   334  		true,
   335  		1,
   336  		uint(1),
   337  		1.0,
   338  		1.1,
   339  		1.2,
   340  		2,
   341  		uint(2),
   342  		2.0,
   343  		2.1,
   344  		"",
   345  		".1",
   346  		".2",
   347  		".a",
   348  		"1",
   349  		"2",
   350  		"a!10",
   351  		"a/10",
   352  		"a/2",
   353  		"ab/1",
   354  		"a~10",
   355  		"b/01",
   356  		"b/02",
   357  		"b/03",
   358  		"b/1",
   359  		"b/2",
   360  		"b/3",
   361  		"b01",
   362  		"b1",
   363  		"b3",
   364  		"c10.2",
   365  		"c2.10",
   366  		"d1",
   367  		"d12",
   368  		"d12a",
   369  	}
   370  	m := make(map[interface{}]int)
   371  	for _, k := range order {
   372  		m[k] = 1
   373  	}
   374  	data, err := Marshal(m)
   375  	t.Equal(err, nil)
   376  	out := "\n" + string(data)
   377  	last := 0
   378  	for i, k := range order {
   379  		repr := fmt.Sprint(k)
   380  		if s, ok := k.(string); ok {
   381  			if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
   382  				repr = `"` + repr + `"`
   383  			}
   384  		}
   385  		index := strings.Index(out, "\n"+repr+":")
   386  		if index == -1 {
   387  			t.Fatalf("%#v is not in the output: %#v", k, out)
   388  		}
   389  		if index < last {
   390  			t.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
   391  		}
   392  		last = index
   393  	}
   394  }