1// Copyright 2015 Jean Niklas L'orange. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package edn 6 7import ( 8 "fmt" 9 "math/big" 10 "reflect" 11 "testing" 12) 13 14// your basic unit tests.. unfinished, probably. 15 16func TestIntReading(t *testing.T) { 17 intStrs := [...]string{"0", "1", "+100", "-982", "8223372036854775808", "-5N", "-0N"} 18 ints := [...]int64{0, 1, 100, -982, 8223372036854775808, -5, 0} 19 for i, istr := range intStrs { 20 var n int64 21 err := UnmarshalString(istr, &n) 22 if err != nil { 23 t.Errorf("int64 '%s' failed, but expected success", istr) 24 } else if n != ints[i] { 25 t.Errorf("int64 '%s' was decoded to %d, but expected %d", istr, n, ints[i]) 26 } 27 } 28} 29 30func TestFloatReading(t *testing.T) { 31 for s, want := range map[string]float64{ 32 "0.0": 0.0, 33 "0.0000001": 0.0000001, 34 "1E3": 1000.0, 35 } { 36 var have float64 37 err := UnmarshalString(s, &have) 38 if err != nil { 39 t.Errorf("float64 '%s' failed, but expected success", s) 40 } else if have != want { 41 t.Errorf("int64 '%s' was decoded to %f, but expected %f", s, have, want) 42 } 43 } 44} 45 46func TestBigIntReading(t *testing.T) { 47 const huge = "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389647960126939249806625440700685819469589938384356951833568218188663" 48 49 bigIntStrs := [...]string{"0", "1", "-1N", "0N", huge + "N"} 50 51 _1 := func(v *big.Int, _ bool) *big.Int { return v } 52 bigInts := [...]*big.Int{ 53 big.NewInt(0), big.NewInt(1), big.NewInt(-1), 54 big.NewInt(0), _1(big.NewInt(0).SetString(huge, 10)), 55 } 56 for i, istr := range bigIntStrs { 57 var n *big.Int 58 err := UnmarshalString(istr, &n) 59 if err != nil { 60 t.Errorf("*big.Int '%s' failed, but expected success", istr) 61 } else if n.Cmp(bigInts[i]) != 0 { 62 t.Errorf("*big.Int '%s' was decoded to %s, but expected %s", istr, n, bigInts[i]) 63 } 64 } 65} 66 67func TestBigFloat(t *testing.T) { 68 const huge = "123456789123456789123456789123456789123456789123456789.123456789" 69 70 bigFloatStrs := [...]string{"0", "1M", "-0.1M", "1.1e-10M", huge + "M"} 71 72 bigFloat := func(s string) *big.Float { 73 f, _, err := big.ParseFloat(s, 10, 192, big.ToNearestEven) 74 if err != nil { 75 t.Fatal(err) 76 } 77 return f 78 } 79 80 bigFloats := [...]*big.Float{ 81 bigFloat("0"), bigFloat("1"), bigFloat("-0.1"), 82 bigFloat("1.1e-10"), bigFloat(huge), 83 } 84 for i, istr := range bigFloatStrs { 85 var n *big.Float 86 err := UnmarshalString(istr, &n) 87 if err != nil { 88 t.Errorf("*big.Float '%s' failed, but expected success", istr) 89 t.Error(err) 90 } else if n.Cmp(bigFloats[i]) != 0 { 91 t.Errorf("*big.Float '%s' was decoded to %s, but expected %s", istr, n, bigFloats[i]) 92 } 93 } 94} 95 96func TestArray(t *testing.T) { 97 stringArray := `("foo" "bar" "baz")` 98 stringExpected := [...]string{"foo", "bar", "baz"} 99 var sa [3]string 100 err := UnmarshalString(stringArray, &sa) 101 if err != nil { 102 t.Error(`expected '("foo" "bar" "baz")' to decode fine, but didn't`) 103 } else { 104 for i, expected := range stringExpected { 105 if expected != sa[i] { 106 t.Errorf(`Element %d in '("foo" "bar" "baz")' (%q) was encoded to %q`, 107 i, expected, sa[i]) 108 } 109 } 110 } 111} 112 113func TestStruct(t *testing.T) { 114 type Animal struct { 115 Name string 116 Type string `edn:"kind"` 117 } 118 type Person struct { 119 Name string 120 Birthyear int `edn:"born"` 121 Pets []Animal 122 } 123 hans := `{:name "Hans", 124 :born 1970, 125 :pets [{:name "Cap'n Jack" :kind "Sparrow"} 126 {:name "Freddy" :kind "Cockatiel"}]}` 127 goHans := Person{"Hans", 1970, 128 []Animal{{"Cap'n Jack", "Sparrow"}, {"Freddy", "Cockatiel"}}} 129 var ednHans Person 130 err := UnmarshalString(hans, &ednHans) 131 if err != nil { 132 t.Error("Error when decoding Hans") 133 } else if !reflect.DeepEqual(goHans, ednHans) { 134 t.Error("EDN Hans is not equal to Go hans") 135 } 136} 137 138func TestRec(t *testing.T) { 139 type Node struct { 140 Left *Node 141 Val int 142 Right *Node 143 } 144 // here we're using symbols 145 tree := "{left {left {val 3} val 5 right nil} val 10 right {val 15 right {val 17}}}" 146 goTree := Node{Left: &Node{Left: &Node{Val: 3}, Val: 5, Right: nil}, 147 Val: 10, Right: &Node{Val: 15, Right: &Node{Val: 17}}} 148 var ednTree Node 149 err := UnmarshalString(tree, &ednTree) 150 if err != nil { 151 t.Errorf("Couldn't unmarshal tree: %s", err.Error()) 152 } else if !reflect.DeepEqual(goTree, ednTree) { 153 t.Error("Mismatch between the Go tree and the tree encoded as EDN") 154 } 155} 156 157func TestDiscard(t *testing.T) { 158 var s Symbol 159 discarding := "#_ #zap #_ xyz foo bar" 160 expected := Symbol("bar") 161 err := UnmarshalString(discarding, &s) 162 if err != nil { 163 t.Errorf("Expected '#_ #zap #_ xyz foo bar' to successfully read") 164 t.Log(err.Error()) 165 } else if expected != s { 166 t.Error("Mismatch between the Go symbol and the symbol encoded as EDN") 167 } 168 169 discarding = "#_ #foo #foo #foo #_#_bar baz zip quux" 170 expected = Symbol("quux") 171 err = UnmarshalString(discarding, &s) 172 if err != nil { 173 t.Errorf("Expected '#_ #foo #foo #foo #_#_bar baz zip quux' to successfully read") 174 t.Log(err.Error()) 175 } else if expected != s { 176 t.Error("Mismatch between the Go symbol and the symbol encoded as EDN") 177 } 178} 179 180// Test that we can read self-defined unmarshalEDNs 181type testUnmarshalEDN string 182 183func (t *testUnmarshalEDN) UnmarshalEDN(bs []byte) (err error) { 184 var kw Keyword 185 err = Unmarshal(bs, &kw) 186 if err == nil && string(kw) != "all" { 187 return fmt.Errorf("testUnmarshalEDN must be :all if it's a keyword, not %s", kw) 188 } 189 if err == nil { 190 *t = testUnmarshalEDN(kw) 191 return 192 } 193 // try to parse set of keywords 194 var m map[Keyword]bool 195 err = Unmarshal(bs, &m) 196 if err == nil { 197 *t = "set elements" 198 } 199 return 200} 201 202func TestUnmarshalEDN(t *testing.T) { 203 var tm testUnmarshalEDN 204 data := ":all" 205 expected := testUnmarshalEDN("all") 206 err := UnmarshalString(data, &tm) 207 if err != nil { 208 t.Errorf("Expected ':all' to successfully read into testUnmarshalEDN") 209 t.Log(err.Error()) 210 } else if expected != tm { 211 t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value") 212 t.Logf("Was %s, expected %s", tm, expected) 213 } 214 215 data = "#{:foo :bar :baz}" 216 expected = testUnmarshalEDN("set elements") 217 err = UnmarshalString(data, &tm) 218 if err != nil { 219 t.Errorf("Expected '#{:foo :bar :baz}' to successfully read into testUnmarshalEDN") 220 t.Log(err.Error()) 221 } else if expected != tm { 222 t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value") 223 t.Logf("Was %s, expected %s", tm, expected) 224 } 225 226 data = "#{:all #{:foo :bar :baz}}" 227 228 var tms map[testUnmarshalEDN]bool 229 err = UnmarshalString(data, &tms) 230 if err != nil { 231 t.Errorf("Expected '#{:all #{:foo :bar :baz}}' to successfully read into a map[testUnmarshalEDN]bool") 232 t.Log(err.Error()) 233 } else { 234 fail := false 235 if len(tms) != 2 { 236 fail = true 237 } 238 if !tms[testUnmarshalEDN("all")] { 239 fail = true 240 } 241 if !tms[testUnmarshalEDN("set elements")] { 242 fail = true 243 } 244 if fail { 245 t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value") 246 t.Logf("Was %s", tm) 247 } 248 } 249 250 data = "#{:foo :bar :baz :rock'n'roll :ain't_going-anywhere}" 251 expected = testUnmarshalEDN("set elements") 252 err = UnmarshalString(data, &tm) 253 if err != nil { 254 t.Errorf("Expected '%s' to successfully read into testUnmarshalEDN", data) 255 t.Log(err.Error()) 256 } else if expected != tm { 257 t.Error("Mismatch between testUnmarshalEDN unmarshaling and the expected value") 258 t.Logf("Was %s, expected %s", tm, expected) 259 } 260} 261 262type vectorCounter int 263 264func (v *vectorCounter) UnmarshalEDN(bs []byte) (err error) { 265 var vec []interface{} 266 err = Unmarshal(bs, &vec) 267 if err != nil { 268 return 269 } 270 *v = vectorCounter(len(vec)) 271 return 272} 273 274func TestVectorCounter(t *testing.T) { 275 var v vectorCounter 276 data := "[foo bar baz]" 277 278 var expected vectorCounter = 3 279 err := UnmarshalString(data, &v) 280 if err != nil { 281 t.Errorf("Expected '%s' to successfully read into vectorCounter", data) 282 t.Log(err.Error()) 283 } else if expected != v { 284 t.Error("Mismatch between vectorCounter unmarshaling and the expected value") 285 t.Logf("Was %d, expected %d", v, expected) 286 } 287 288 data = "(a b c d e f)" 289 expected = 6 290 err = UnmarshalString(data, &v) 291 if err != nil { 292 t.Errorf("Expected '%s' to successfully read into vectorCounter", data) 293 t.Log(err.Error()) 294 } else if expected != v { 295 t.Error("Mismatch between vectorCounter unmarshaling and the expected value") 296 t.Logf("Was %d, expected %d", v, expected) 297 } 298 299 data = `[[a b c][d e f g h],[#_3 z 2 \c]()["c d e"](2 3.0M)]` 300 var vs []vectorCounter 301 expected2 := []vectorCounter{3, 5, 3, 0, 1, 2} 302 err = UnmarshalString(data, &vs) 303 if err != nil { 304 t.Errorf("Expected '%s' to successfully read into []vectorCounter", data) 305 t.Log(err.Error()) 306 } else if !reflect.DeepEqual(vs, expected2) { 307 t.Errorf("Mismatch between %#v and %#v", vs, expected2) 308 } 309 310 data = `{[a b c] "quux", [] "frob"}` 311 var vmap map[vectorCounter]string 312 expected3 := map[vectorCounter]string{3: "quux", 0: "frob"} 313 err = UnmarshalString(data, &vmap) 314 if err != nil { 315 t.Errorf("Expected '%s' to successfully read into map[vectorCounter]string", data) 316 t.Log(err.Error()) 317 } else if !reflect.DeepEqual(vmap, expected3) { 318 t.Errorf("Mismatch between %#v and %#v", vmap, expected3) 319 } 320} 321 322type mapCounter int 323 324func (mc *mapCounter) UnmarshalEDN(bs []byte) (err error) { 325 var m map[interface{}]interface{} 326 err = Unmarshal(bs, &m) 327 if err != nil { 328 return 329 } 330 *mc = mapCounter(len(m)) 331 return 332} 333 334func TestMapCounter(t *testing.T) { 335 var mc mapCounter 336 data := `{nil foo :a :b :c :d 1 0}` 337 338 var expected mapCounter = 4 339 err := UnmarshalString(data, &mc) 340 if err != nil { 341 t.Errorf("Expected '%s' to successfully read into mapCounter", data) 342 t.Log(err.Error()) 343 } else if expected != mc { 344 t.Error("Mismatch between mapCounter unmarshaling and the expected value") 345 t.Logf("Was %d, expected %d", mc, expected) 346 } 347} 348 349func TestSliceSet(t *testing.T) { 350 var ss []string // no need to specify `edn:",set"` for this 351 data := `#{"a" "b" "c"}` 352 err := UnmarshalString(data, &ss) 353 if err != nil { 354 t.Errorf("Expected '%s' to succesfully read into a string slice", data) 355 t.Log(err.Error()) 356 } else if !reflect.DeepEqual(ss, []string{"a", "b", "c"}) { 357 t.Error("Mismatch between string slice unmarshaling and expected value") 358 t.Logf(`Was %#v, expected []string{"a", "b", "c"}.`, ss) 359 } 360} 361 362type ExtraField struct { 363 Foo string 364} 365 366// TestExtraFields checks whether reading extra fields - in any order, is done 367// correctly. 368func TestExtraFields(t *testing.T) { 369 expected := ExtraField{Foo: "123"} 370 inputs := []string{ 371 `{:foo "123" :extra "456"}`, 372 `{:extra "456" :foo "123"}`, 373 `{:foo "123" :extra 456}`, 374 `{:extra 456 :foo "123"}`, 375 `{nil 456 :foo "123"}`, 376 } 377 for _, input := range inputs { 378 var ef ExtraField 379 err := UnmarshalString(input, &ef) 380 if err != nil { 381 t.Errorf("Expected '%s' to succesfully read into an ExtraField type", input) 382 t.Log(err.Error()) 383 } else if ef != expected { 384 t.Error("Mismatch between struct unmarshaling and expected value") 385 t.Logf(`Was %#v, expected %#v.`, ef, expected) 386 } 387 } 388} 389 390func TestNilSet(t *testing.T) { 391 inputs := []string{ 392 `#{1 2 nil 3}`, 393 `#{nil}`, 394 `#{#{nil} #{nil 1}}`, 395 `#{nil 1 2}`, 396 `#{1 2 3 nil}`, 397 } 398 for _, input := range inputs { 399 var val []interface{} 400 err := UnmarshalString(input, &val) 401 if err != nil { 402 t.Errorf("Expected '%s' to succesfully read into []interface{}", input) 403 t.Log(err.Error()) 404 } 405 var ival interface{} 406 err = UnmarshalString(input, &ival) 407 if err != nil { 408 t.Errorf("Expected '%s' to succesfully read into interface{}", input) 409 t.Log(err.Error()) 410 } 411 var mval map[interface{}]bool 412 err = UnmarshalString(input, &mval) 413 if err != nil { 414 t.Errorf("Expected '%s' to succesfully read into map[interface{}]bool", input) 415 t.Log(err.Error()) 416 } 417 } 418} 419 420func TestNilMap(t *testing.T) { 421 inputs := []string{ 422 `{1 2 nil 3}`, 423 `{nil foo}`, 424 `{{nil nil} 2 nil 1}`, 425 `{nil 1 2 3}`, 426 `{1 2 3 nil}`, 427 } 428 for _, input := range inputs { 429 var ival interface{} 430 err := UnmarshalString(input, &ival) 431 if err != nil { 432 t.Errorf("Expected '%s' to succesfully read into interface{}", input) 433 t.Log(err.Error()) 434 } 435 var mval map[interface{}]interface{} 436 err = UnmarshalString(input, &mval) 437 if err != nil { 438 t.Errorf("Expected '%s' to succesfully read into map[interface{}]interface{}", input) 439 t.Log(err.Error()) 440 } 441 } 442} 443 444func TestNilNotFunnilyCoerced(t *testing.T) { 445 inputs := []string{ 446 `{"1" 2 nil 3}`, 447 } 448 for _, input := range inputs { 449 var val map[string]int 450 err := UnmarshalString(input, &val) 451 if err == nil { 452 t.Errorf("Expected '%s' to error out when read into map[string]int", input) 453 t.Logf("Value is %#v", val) 454 } 455 } 456} 457 458func TestNilNotEmptyString(t *testing.T) { 459 input := "nil" 460 var val string 461 err := UnmarshalString(input, &val) 462 if err == nil { 463 t.Error("Expected nil to not be a string") 464 } 465} 466 467func TestUnhashableBigInt(t *testing.T) { 468 input := "#{0N}" 469 var val interface{} 470 if err := UnmarshalString(input, &val); err != nil { 471 _, unhashable := err.(*UnhashableError) 472 if !unhashable { 473 t.Errorf("unexpected parsing error: %q: %s", input, err) 474 } 475 } else { 476 t.Errorf("expected '%s' to be unparseable", input) 477 } 478} 479 480func TestUnhashableTaggedList(t *testing.T) { 481 input := "{#g()0}" 482 var val interface{} 483 if err := UnmarshalString(input, &val); err != nil { 484 _, unhashable := err.(*UnhashableError) 485 if !unhashable { 486 t.Errorf("unexpected parsing error: %q: %s", input, err) 487 } 488 } else { 489 t.Errorf("expected '%s' to be unparseable", input) 490 } 491} 492 493func TestJSONDecoding(t *testing.T) { 494 var jsonOnly struct { 495 Data string `json:"json"` 496 } 497 var jsonAndEdn struct { 498 Data string `json:"json" edn:"edn"` 499 } 500 inputData := `{:data"hi"}` 501 inputEDN := `{:edn"hi"}` 502 inputJSON := `{:json"hi"}` 503 504 testEmpty := func(obj interface{}, str *string, input string) { 505 *str = "" 506 if err := UnmarshalString(input, obj); err != nil { 507 t.Errorf("Expected %q to parse successfully into #%v", input, obj) 508 t.Log(err.Error()) 509 } 510 if *str != "" { 511 t.Errorf("Expected %q to not parse into fields, but got %#v", input, obj) 512 } 513 } 514 testHi := func(obj interface{}, str *string, input string) { 515 *str = "" 516 if err := UnmarshalString(input, obj); err != nil { 517 t.Errorf("Expected %q to parse successfully into #%v", input, obj) 518 t.Log(err.Error()) 519 } 520 if *str != "hi" { 521 t.Errorf(`Expected %q to not parse "hi" into .Data, but got %#v`, input, obj) 522 } 523 } 524 525 UseJSONAsFallback(false) 526 527 // json tag only 528 testHi(&jsonOnly, &jsonOnly.Data, inputData) 529 testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN) 530 testEmpty(&jsonOnly, &jsonOnly.Data, inputJSON) 531 // json + edn tag 532 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData) 533 testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN) 534 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON) 535 536 UseJSONAsFallback(true) 537 538 // json tag only 539 testEmpty(&jsonOnly, &jsonOnly.Data, inputData) 540 testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN) 541 testHi(&jsonOnly, &jsonOnly.Data, inputJSON) 542 // json + edn tag 543 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData) 544 testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN) 545 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON) 546 547 UseJSONAsFallback(false) 548 549 // json tag only 550 testHi(&jsonOnly, &jsonOnly.Data, inputData) 551 testEmpty(&jsonOnly, &jsonOnly.Data, inputEDN) 552 testEmpty(&jsonOnly, &jsonOnly.Data, inputJSON) 553 // json + edn tag 554 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputData) 555 testHi(&jsonAndEdn, &jsonAndEdn.Data, inputEDN) 556 testEmpty(&jsonAndEdn, &jsonAndEdn.Data, inputJSON) 557} 558