1// Copyright 2013 The Go Authors. 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 language 6 7import ( 8 "reflect" 9 "testing" 10) 11 12func TestTagSize(t *testing.T) { 13 id := Tag{} 14 typ := reflect.TypeOf(id) 15 if typ.Size() > 24 { 16 t.Errorf("size of Tag was %d; want 24", typ.Size()) 17 } 18} 19 20func TestIsRoot(t *testing.T) { 21 loc := Tag{} 22 if !loc.IsRoot() { 23 t.Errorf("unspecified should be root.") 24 } 25 for i, tt := range parseTests() { 26 loc, _ := Parse(tt.in) 27 undef := tt.lang == "und" && tt.script == "" && tt.region == "" && tt.ext == "" 28 if loc.IsRoot() != undef { 29 t.Errorf("%d: was %v; want %v", i, loc.IsRoot(), undef) 30 } 31 } 32} 33 34func TestEquality(t *testing.T) { 35 for i, tt := range parseTests() { 36 s := tt.in 37 tag := Make(s) 38 t1 := Make(tag.String()) 39 if tag != t1 { 40 t.Errorf("%d:%s: equality test 1 failed\n got: %#v\nwant: %#v)", i, s, t1, tag) 41 } 42 t2, _ := Compose(tag) 43 if tag != t2 { 44 t.Errorf("%d:%s: equality test 2 failed\n got: %#v\nwant: %#v", i, s, t2, tag) 45 } 46 } 47} 48 49func TestString(t *testing.T) { 50 tests := []string{ 51 "no-u-rg-dkzzzz", 52 } 53 for i, s := range tests { 54 tag := Make(s) 55 if tag.String() != s { 56 t.Errorf("%d:%s: got %s: want %s (%#v)", i, s, tag.String(), s, tag) 57 } 58 } 59} 60 61func TestMarshal(t *testing.T) { 62 testCases := []string{ 63 // TODO: these values will change with each CLDR update. This issue 64 // will be solved if we decide to fix the indexes. 65 "und", 66 "ca-ES-valencia", 67 "ca-ES-valencia-u-va-posix", 68 "ca-ES-valencia-u-co-phonebk", 69 "ca-ES-valencia-u-co-phonebk-va-posix", 70 "x-klingon", 71 "en-US", 72 "en-US-u-va-posix", 73 "en", 74 "en-u-co-phonebk", 75 "en-001", 76 "sh", 77 78 "en-GB-u-rg-uszzzz", 79 "en-GB-u-rg-uszzzz-va-posix", 80 "en-GB-u-co-phonebk-rg-uszzzz", 81 // Invalid tags should also roundtrip. 82 "en-GB-u-co-phonebk-rg-uszz", 83 } 84 for _, tc := range testCases { 85 var tag Tag 86 err := tag.UnmarshalText([]byte(tc)) 87 if err != nil { 88 t.Errorf("UnmarshalText(%q): unexpected error: %v", tc, err) 89 } 90 b, err := tag.MarshalText() 91 if err != nil { 92 t.Errorf("MarshalText(%q): unexpected error: %v", tc, err) 93 } 94 if got := string(b); got != tc { 95 t.Errorf("%s: got %q; want %q", tc, got, tc) 96 } 97 } 98} 99 100func TestBase(t *testing.T) { 101 tests := []struct { 102 loc, lang string 103 conf Confidence 104 }{ 105 {"und", "en", Low}, 106 {"x-abc", "und", No}, 107 {"en", "en", Exact}, 108 {"und-Cyrl", "ru", High}, 109 // If a region is not included, the official language should be English. 110 {"und-US", "en", High}, 111 // TODO: not-explicitly listed scripts should probably be und, No 112 // Modify addTags to return info on how the match was derived. 113 // {"und-Aghb", "und", No}, 114 } 115 for i, tt := range tests { 116 loc, _ := Parse(tt.loc) 117 lang, conf := loc.Base() 118 if lang.String() != tt.lang { 119 t.Errorf("%d: language was %s; want %s", i, lang, tt.lang) 120 } 121 if conf != tt.conf { 122 t.Errorf("%d: confidence was %d; want %d", i, conf, tt.conf) 123 } 124 } 125} 126 127func TestParseBase(t *testing.T) { 128 tests := []struct { 129 in string 130 out string 131 ok bool 132 }{ 133 {"en", "en", true}, 134 {"EN", "en", true}, 135 {"nld", "nl", true}, 136 {"dut", "dut", true}, // bibliographic 137 {"aaj", "und", false}, // unknown 138 {"qaa", "qaa", true}, 139 {"a", "und", false}, 140 {"", "und", false}, 141 {"aaaa", "und", false}, 142 } 143 for i, tt := range tests { 144 x, err := ParseBase(tt.in) 145 if x.String() != tt.out || err == nil != tt.ok { 146 t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, x, err == nil, tt.out, tt.ok) 147 } 148 if y, _, _ := Raw.Make(tt.out).Raw(); x != y { 149 t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, x, y) 150 } 151 } 152} 153 154func TestScript(t *testing.T) { 155 tests := []struct { 156 loc, scr string 157 conf Confidence 158 }{ 159 {"und", "Latn", Low}, 160 {"en-Latn", "Latn", Exact}, 161 {"en", "Latn", High}, 162 {"sr", "Cyrl", Low}, 163 {"kk", "Cyrl", High}, 164 {"kk-CN", "Arab", Low}, 165 {"cmn", "Hans", Low}, 166 {"ru", "Cyrl", High}, 167 {"ru-RU", "Cyrl", High}, 168 {"yue", "Hant", Low}, 169 {"x-abc", "Zzzz", Low}, 170 {"und-zyyy", "Zyyy", Exact}, 171 } 172 for i, tt := range tests { 173 loc, _ := Parse(tt.loc) 174 sc, conf := loc.Script() 175 if sc.String() != tt.scr { 176 t.Errorf("%d:%s: script was %s; want %s", i, tt.loc, sc, tt.scr) 177 } 178 if conf != tt.conf { 179 t.Errorf("%d:%s: confidence was %d; want %d", i, tt.loc, conf, tt.conf) 180 } 181 } 182} 183 184func TestParseScript(t *testing.T) { 185 tests := []struct { 186 in string 187 out string 188 ok bool 189 }{ 190 {"Latn", "Latn", true}, 191 {"zzzz", "Zzzz", true}, 192 {"zyyy", "Zyyy", true}, 193 {"Latm", "Zzzz", false}, 194 {"Zzz", "Zzzz", false}, 195 {"", "Zzzz", false}, 196 {"Zzzxx", "Zzzz", false}, 197 } 198 for i, tt := range tests { 199 x, err := ParseScript(tt.in) 200 if x.String() != tt.out || err == nil != tt.ok { 201 t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, x, err == nil, tt.out, tt.ok) 202 } 203 if err == nil { 204 if _, y, _ := Raw.Make("und-" + tt.out).Raw(); x != y { 205 t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, x, y) 206 } 207 } 208 } 209} 210 211func TestRegion(t *testing.T) { 212 tests := []struct { 213 loc, reg string 214 conf Confidence 215 }{ 216 {"und", "US", Low}, 217 {"en", "US", Low}, 218 {"zh-Hant", "TW", Low}, 219 {"en-US", "US", Exact}, 220 {"cmn", "CN", Low}, 221 {"ru", "RU", Low}, 222 {"yue", "HK", Low}, 223 {"x-abc", "ZZ", Low}, 224 } 225 for i, tt := range tests { 226 loc, _ := Raw.Parse(tt.loc) 227 reg, conf := loc.Region() 228 if reg.String() != tt.reg { 229 t.Errorf("%d:%s: region was %s; want %s", i, tt.loc, reg, tt.reg) 230 } 231 if conf != tt.conf { 232 t.Errorf("%d:%s: confidence was %d; want %d", i, tt.loc, conf, tt.conf) 233 } 234 } 235} 236 237func TestEncodeM49(t *testing.T) { 238 tests := []struct { 239 m49 int 240 code string 241 ok bool 242 }{ 243 {1, "001", true}, 244 {840, "US", true}, 245 {899, "ZZ", false}, 246 } 247 for i, tt := range tests { 248 if r, err := EncodeM49(tt.m49); r.String() != tt.code || err == nil != tt.ok { 249 t.Errorf("%d:%d: was %s, %v; want %s, %v", i, tt.m49, r, err == nil, tt.code, tt.ok) 250 } 251 } 252 for i := 1; i <= 1000; i++ { 253 if r, err := EncodeM49(i); err == nil && r.M49() == 0 { 254 t.Errorf("%d has no error, but maps to undefined region", i) 255 } 256 } 257} 258 259func TestParseRegion(t *testing.T) { 260 tests := []struct { 261 in string 262 out string 263 ok bool 264 }{ 265 {"001", "001", true}, 266 {"840", "US", true}, 267 {"899", "ZZ", false}, 268 {"USA", "US", true}, 269 {"US", "US", true}, 270 {"BC", "ZZ", false}, 271 {"C", "ZZ", false}, 272 {"CCCC", "ZZ", false}, 273 {"01", "ZZ", false}, 274 } 275 for i, tt := range tests { 276 r, err := ParseRegion(tt.in) 277 if r.String() != tt.out || err == nil != tt.ok { 278 t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, r, err == nil, tt.out, tt.ok) 279 } 280 if err == nil { 281 if _, _, y := Raw.Make("und-" + tt.out).Raw(); r != y { 282 t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, r, y) 283 } 284 } 285 } 286} 287 288func TestIsCountry(t *testing.T) { 289 tests := []struct { 290 reg string 291 country bool 292 }{ 293 {"US", true}, 294 {"001", false}, 295 {"958", false}, 296 {"419", false}, 297 {"203", true}, 298 {"020", true}, 299 {"900", false}, 300 {"999", false}, 301 {"QO", false}, 302 {"EU", false}, 303 {"AA", false}, 304 {"XK", true}, 305 } 306 for i, tt := range tests { 307 r, _ := ParseRegion(tt.reg) 308 if r.IsCountry() != tt.country { 309 t.Errorf("%d: IsCountry(%s) was %v; want %v", i, tt.reg, r.IsCountry(), tt.country) 310 } 311 } 312} 313 314func TestIsGroup(t *testing.T) { 315 tests := []struct { 316 reg string 317 group bool 318 }{ 319 {"US", false}, 320 {"001", true}, 321 {"958", false}, 322 {"419", true}, 323 {"203", false}, 324 {"020", false}, 325 {"900", false}, 326 {"999", false}, 327 {"QO", true}, 328 {"EU", true}, 329 {"AA", false}, 330 {"XK", false}, 331 } 332 for i, tt := range tests { 333 r, _ := ParseRegion(tt.reg) 334 if r.IsGroup() != tt.group { 335 t.Errorf("%d: IsGroup(%s) was %v; want %v", i, tt.reg, r.IsGroup(), tt.group) 336 } 337 } 338} 339 340func TestContains(t *testing.T) { 341 tests := []struct { 342 enclosing, contained string 343 contains bool 344 }{ 345 // A region contains itself. 346 {"US", "US", true}, 347 {"001", "001", true}, 348 349 // Direct containment. 350 {"001", "002", true}, 351 {"039", "XK", true}, 352 {"150", "XK", true}, 353 {"EU", "AT", true}, 354 {"QO", "AQ", true}, 355 356 // Indirect containemnt. 357 {"001", "US", true}, 358 {"001", "419", true}, 359 {"001", "013", true}, 360 361 // No containment. 362 {"US", "001", false}, 363 {"155", "EU", false}, 364 } 365 for i, tt := range tests { 366 r := MustParseRegion(tt.enclosing) 367 con := MustParseRegion(tt.contained) 368 if got := r.Contains(con); got != tt.contains { 369 t.Errorf("%d: %s.Contains(%s) was %v; want %v", i, tt.enclosing, tt.contained, got, tt.contains) 370 } 371 } 372} 373 374func TestRegionCanonicalize(t *testing.T) { 375 for i, tt := range []struct{ in, out string }{ 376 {"UK", "GB"}, 377 {"TP", "TL"}, 378 {"QU", "EU"}, 379 {"SU", "SU"}, 380 {"VD", "VN"}, 381 {"DD", "DE"}, 382 } { 383 r := MustParseRegion(tt.in) 384 want := MustParseRegion(tt.out) 385 if got := r.Canonicalize(); got != want { 386 t.Errorf("%d: got %v; want %v", i, got, want) 387 } 388 } 389} 390 391func TestRegionTLD(t *testing.T) { 392 for _, tt := range []struct { 393 in, out string 394 ok bool 395 }{ 396 {"EH", "EH", true}, 397 {"FR", "FR", true}, 398 {"TL", "TL", true}, 399 400 // In ccTLD before in ISO. 401 {"GG", "GG", true}, 402 403 // Non-standard assignment of ccTLD to ISO code. 404 {"GB", "UK", true}, 405 406 // Exceptionally reserved in ISO and valid ccTLD. 407 {"UK", "UK", true}, 408 {"AC", "AC", true}, 409 {"EU", "EU", true}, 410 {"SU", "SU", true}, 411 412 // Exceptionally reserved in ISO and invalid ccTLD. 413 {"CP", "ZZ", false}, 414 {"DG", "ZZ", false}, 415 {"EA", "ZZ", false}, 416 {"FX", "ZZ", false}, 417 {"IC", "ZZ", false}, 418 {"TA", "ZZ", false}, 419 420 // Transitionally reserved in ISO (e.g. deprecated) but valid ccTLD as 421 // it is still being phased out. 422 {"AN", "AN", true}, 423 {"TP", "TP", true}, 424 425 // Transitionally reserved in ISO (e.g. deprecated) and invalid ccTLD. 426 // Defined in package language as it has a mapping in CLDR. 427 {"BU", "ZZ", false}, 428 {"CS", "ZZ", false}, 429 {"NT", "ZZ", false}, 430 {"YU", "ZZ", false}, 431 {"ZR", "ZZ", false}, 432 // Not defined in package: SF. 433 434 // Indeterminately reserved in ISO. 435 // Defined in package language as it has a legacy mapping in CLDR. 436 {"DY", "ZZ", false}, 437 {"RH", "ZZ", false}, 438 {"VD", "ZZ", false}, 439 // Not defined in package: EW, FL, JA, LF, PI, RA, RB, RC, RI, RL, RM, 440 // RN, RP, WG, WL, WV, and YV. 441 442 // Not assigned in ISO, but legacy definitions in CLDR. 443 {"DD", "ZZ", false}, 444 {"YD", "ZZ", false}, 445 446 // Normal mappings but somewhat special status in ccTLD. 447 {"BL", "BL", true}, 448 {"MF", "MF", true}, 449 {"BV", "BV", true}, 450 {"SJ", "SJ", true}, 451 452 // Have values when normalized, but not as is. 453 {"QU", "ZZ", false}, 454 455 // ISO Private Use. 456 {"AA", "ZZ", false}, 457 {"QM", "ZZ", false}, 458 {"QO", "ZZ", false}, 459 {"XA", "ZZ", false}, 460 {"XK", "ZZ", false}, // Sometimes used for Kosovo, but invalid ccTLD. 461 } { 462 if tt.in == "" { 463 continue 464 } 465 466 r := MustParseRegion(tt.in) 467 var want Region 468 if tt.out != "ZZ" { 469 want = MustParseRegion(tt.out) 470 } 471 tld, err := r.TLD() 472 if got := err == nil; got != tt.ok { 473 t.Errorf("error(%v): got %v; want %v", r, got, tt.ok) 474 } 475 if tld != want { 476 t.Errorf("TLD(%v): got %v; want %v", r, tld, want) 477 } 478 } 479} 480 481func TestCanonicalize(t *testing.T) { 482 // TODO: do a full test using CLDR data in a separate regression test. 483 tests := []struct { 484 in, out string 485 option CanonType 486 }{ 487 {"en-Latn", "en", SuppressScript}, 488 {"sr-Cyrl", "sr-Cyrl", SuppressScript}, 489 {"sh", "sr-Latn", Legacy}, 490 {"sh-HR", "sr-Latn-HR", Legacy}, 491 {"sh-Cyrl-HR", "sr-Cyrl-HR", Legacy}, 492 {"tl", "fil", Legacy}, 493 {"no", "no", Legacy}, 494 {"no", "nb", Legacy | CLDR}, 495 {"cmn", "cmn", Legacy}, 496 {"cmn", "zh", Macro}, 497 {"cmn-u-co-stroke", "zh-u-co-stroke", Macro}, 498 {"yue", "yue", Macro}, 499 {"nb", "no", Macro}, 500 {"nb", "nb", Macro | CLDR}, 501 {"no", "no", Macro}, 502 {"no", "no", Macro | CLDR}, 503 {"iw", "he", DeprecatedBase}, 504 {"iw", "he", Deprecated | CLDR}, 505 {"mo", "ro-MD", Deprecated}, // Adopted by CLDR as of version 25. 506 {"alb", "sq", Legacy}, // bibliographic 507 {"dut", "nl", Legacy}, // bibliographic 508 // As of CLDR 25, mo is no longer considered a legacy mapping. 509 {"mo", "mo", Legacy | CLDR}, 510 {"und-AN", "und-AN", Deprecated}, 511 {"und-YD", "und-YE", DeprecatedRegion}, 512 {"und-YD", "und-YD", DeprecatedBase}, 513 {"und-Qaai", "und-Zinh", DeprecatedScript}, 514 {"und-Qaai", "und-Qaai", DeprecatedBase}, 515 {"drh", "mn", All}, // drh -> khk -> mn 516 517 {"en-GB-u-rg-uszzzz", "en-GB-u-rg-uszzzz", Raw}, 518 {"en-GB-u-rg-USZZZZ", "en-GB-u-rg-uszzzz", Raw}, 519 // TODO: use different exact values for language and regional tag? 520 {"en-GB-u-rg-uszzzz-va-posix", "en-GB-u-rg-uszzzz-va-posix", Raw}, 521 {"en-GB-u-rg-uszzzz-co-phonebk", "en-GB-u-co-phonebk-rg-uszzzz", Raw}, 522 // Invalid region specifications are left as is. 523 {"en-GB-u-rg-usz", "en-GB-u-rg-usz", Raw}, 524 {"en-GB-u-rg-usz-va-posix", "en-GB-u-rg-usz-va-posix", Raw}, 525 {"en-GB-u-rg-usz-co-phonebk", "en-GB-u-co-phonebk-rg-usz", Raw}, 526 } 527 for i, tt := range tests { 528 in, _ := Raw.Parse(tt.in) 529 in, _ = tt.option.Canonicalize(in) 530 if in.String() != tt.out { 531 t.Errorf("%d:%s: was %s; want %s", i, tt.in, in.String(), tt.out) 532 } 533 } 534 // Test idempotence. 535 for _, base := range Supported.BaseLanguages() { 536 tag, _ := Raw.Compose(base) 537 got, _ := All.Canonicalize(tag) 538 want, _ := All.Canonicalize(got) 539 if got != want { 540 t.Errorf("idem(%s): got %s; want %s", tag, got, want) 541 } 542 } 543} 544 545func TestTypeForKey(t *testing.T) { 546 tests := []struct{ key, in, out string }{ 547 {"co", "en", ""}, 548 {"co", "en-u-abc", ""}, 549 {"co", "en-u-co-phonebk", "phonebk"}, 550 {"co", "en-u-co-phonebk-cu-aud", "phonebk"}, 551 {"co", "x-foo-u-co-phonebk", ""}, 552 {"va", "en-US-u-va-posix", "posix"}, 553 {"rg", "en-u-rg-gbzzzz", "gbzzzz"}, 554 {"nu", "en-u-co-phonebk-nu-arabic", "arabic"}, 555 {"kc", "cmn-u-co-stroke", ""}, 556 } 557 for _, tt := range tests { 558 if v := Make(tt.in).TypeForKey(tt.key); v != tt.out { 559 t.Errorf("%q[%q]: was %q; want %q", tt.in, tt.key, v, tt.out) 560 } 561 } 562} 563 564func TestParent(t *testing.T) { 565 tests := []struct{ in, out string }{ 566 // Strip variants and extensions first 567 {"de-u-co-phonebk", "de"}, 568 {"de-1994", "de"}, 569 {"de-Latn-1994", "de"}, // remove superfluous script. 570 571 // Ensure the canonical Tag for an entry is in the chain for base-script 572 // pairs. 573 {"zh-Hans", "zh"}, 574 575 // Skip the script if it is the maximized version. CLDR files for the 576 // skipped tag are always empty. 577 {"zh-Hans-TW", "zh"}, 578 {"zh-Hans-CN", "zh"}, 579 580 // Insert the script if the maximized script is not the same as the 581 // maximized script of the base language. 582 {"zh-TW", "zh-Hant"}, 583 {"zh-HK", "zh-Hant"}, 584 {"zh-Hant-TW", "zh-Hant"}, 585 {"zh-Hant-HK", "zh-Hant"}, 586 587 // Non-default script skips to und. 588 // CLDR 589 {"az-Cyrl", "und"}, 590 {"bs-Cyrl", "und"}, 591 {"en-Dsrt", "und"}, 592 {"ha-Arab", "und"}, 593 {"mn-Mong", "und"}, 594 {"pa-Arab", "und"}, 595 {"shi-Latn", "und"}, 596 {"sr-Latn", "und"}, 597 {"uz-Arab", "und"}, 598 {"uz-Cyrl", "und"}, 599 {"vai-Latn", "und"}, 600 {"zh-Hant", "und"}, 601 // extra 602 {"nl-Cyrl", "und"}, 603 604 // World english inherits from en-001. 605 {"en-150", "en-001"}, 606 {"en-AU", "en-001"}, 607 {"en-BE", "en-001"}, 608 {"en-GG", "en-001"}, 609 {"en-GI", "en-001"}, 610 {"en-HK", "en-001"}, 611 {"en-IE", "en-001"}, 612 {"en-IM", "en-001"}, 613 {"en-IN", "en-001"}, 614 {"en-JE", "en-001"}, 615 {"en-MT", "en-001"}, 616 {"en-NZ", "en-001"}, 617 {"en-PK", "en-001"}, 618 {"en-SG", "en-001"}, 619 620 // Spanish in Latin-American countries have es-419 as parent. 621 {"es-AR", "es-419"}, 622 {"es-BO", "es-419"}, 623 {"es-CL", "es-419"}, 624 {"es-CO", "es-419"}, 625 {"es-CR", "es-419"}, 626 {"es-CU", "es-419"}, 627 {"es-DO", "es-419"}, 628 {"es-EC", "es-419"}, 629 {"es-GT", "es-419"}, 630 {"es-HN", "es-419"}, 631 {"es-MX", "es-419"}, 632 {"es-NI", "es-419"}, 633 {"es-PA", "es-419"}, 634 {"es-PE", "es-419"}, 635 {"es-PR", "es-419"}, 636 {"es-PY", "es-419"}, 637 {"es-SV", "es-419"}, 638 {"es-US", "es-419"}, 639 {"es-UY", "es-419"}, 640 {"es-VE", "es-419"}, 641 // exceptions (according to CLDR) 642 {"es-CW", "es"}, 643 644 // Inherit from pt-PT, instead of pt for these countries. 645 {"pt-AO", "pt-PT"}, 646 {"pt-CV", "pt-PT"}, 647 {"pt-GW", "pt-PT"}, 648 {"pt-MO", "pt-PT"}, 649 {"pt-MZ", "pt-PT"}, 650 {"pt-ST", "pt-PT"}, 651 {"pt-TL", "pt-PT"}, 652 653 {"en-GB-u-co-phonebk-rg-uszzzz", "en-GB"}, 654 {"en-GB-u-rg-uszzzz", "en-GB"}, 655 {"en-US-u-va-posix", "en-US"}, 656 657 // Difference between language and regional tag. 658 {"ca-ES-valencia", "ca-ES"}, 659 {"ca-ES-valencia-u-rg-ptzzzz", "ca-ES"}, 660 {"en-US-u-va-variant", "en-US"}, 661 {"en-u-va-variant", "en"}, 662 {"en-u-rg-gbzzzz", "en"}, 663 {"en-US-u-rg-gbzzzz", "en-US"}, 664 {"nl-US-u-rg-gbzzzz", "nl-US"}, 665 } 666 for _, tt := range tests { 667 tag := Raw.MustParse(tt.in) 668 if p := Raw.MustParse(tt.out); p != tag.Parent() { 669 t.Errorf("%s: was %v; want %v", tt.in, tag.Parent(), p) 670 } 671 } 672} 673 674var ( 675 // Tags without error that don't need to be changed. 676 benchBasic = []string{ 677 "en", 678 "en-Latn", 679 "en-GB", 680 "za", 681 "zh-Hant", 682 "zh", 683 "zh-HK", 684 "ar-MK", 685 "en-CA", 686 "fr-CA", 687 "fr-CH", 688 "fr", 689 "lv", 690 "he-IT", 691 "tlh", 692 "ja", 693 "ja-Jpan", 694 "ja-Jpan-JP", 695 "de-1996", 696 "de-CH", 697 "sr", 698 "sr-Latn", 699 } 700 // Tags with extensions, not changes required. 701 benchExt = []string{ 702 "x-a-b-c-d", 703 "x-aa-bbbb-cccccccc-d", 704 "en-x_cc-b-bbb-a-aaa", 705 "en-c_cc-b-bbb-a-aaa-x-x", 706 "en-u-co-phonebk", 707 "en-Cyrl-u-co-phonebk", 708 "en-US-u-co-phonebk-cu-xau", 709 "en-nedix-u-co-phonebk", 710 "en-t-t0-abcd", 711 "en-t-nl-latn", 712 "en-t-t0-abcd-x-a", 713 } 714 // Change, but not memory allocation required. 715 benchSimpleChange = []string{ 716 "EN", 717 "i-klingon", 718 "en-latn", 719 "zh-cmn-Hans-CN", 720 "iw-NL", 721 } 722 // Change and memory allocation required. 723 benchChangeAlloc = []string{ 724 "en-c_cc-b-bbb-a-aaa", 725 "en-u-cu-xua-co-phonebk", 726 "en-u-cu-xua-co-phonebk-a-cd", 727 "en-u-def-abc-cu-xua-co-phonebk", 728 "en-t-en-Cyrl-NL-1994", 729 "en-t-en-Cyrl-NL-1994-t0-abc-def", 730 } 731 // Tags that result in errors. 732 benchErr = []string{ 733 // IllFormed 734 "x_A.-B-C_D", 735 "en-u-cu-co-phonebk", 736 "en-u-cu-xau-co", 737 "en-t-nl-abcd", 738 // Invalid 739 "xx", 740 "nl-Uuuu", 741 "nl-QB", 742 } 743 benchChange = append(benchSimpleChange, benchChangeAlloc...) 744 benchAll = append(append(append(benchBasic, benchExt...), benchChange...), benchErr...) 745) 746 747func doParse(b *testing.B, tag []string) { 748 for i := 0; i < b.N; i++ { 749 // Use the modulo instead of looping over all tags so that we get a somewhat 750 // meaningful ns/op. 751 Parse(tag[i%len(tag)]) 752 } 753} 754 755func BenchmarkParse(b *testing.B) { 756 doParse(b, benchAll) 757} 758 759func BenchmarkParseBasic(b *testing.B) { 760 doParse(b, benchBasic) 761} 762 763func BenchmarkParseError(b *testing.B) { 764 doParse(b, benchErr) 765} 766 767func BenchmarkParseSimpleChange(b *testing.B) { 768 doParse(b, benchSimpleChange) 769} 770 771func BenchmarkParseChangeAlloc(b *testing.B) { 772 doParse(b, benchChangeAlloc) 773} 774