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 }