golang.org/x/text@v0.14.0/language/language_test.go (about) 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 5 package language 6 7 import ( 8 "reflect" 9 "testing" 10 ) 11 12 func 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 20 func 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 34 func 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 49 func 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 61 func 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 100 func 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 127 func 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 154 func 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 184 func 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 211 func 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 237 func 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 259 func 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 288 func 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 314 func 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 340 func 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 374 func 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 391 func 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 481 func 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 // CVE-2020-28851 528 // invalid key-value pair of -u- extension. 529 {"ES-u-000-00", "es-u-000-00", Raw}, 530 {"ES-u-000-00-v-00", "es-u-000-00-v-00", Raw}, 531 // reordered and unknown extension. 532 {"ES-v-00-u-000-00", "es-u-000-00-v-00", Raw}, 533 } 534 for i, tt := range tests { 535 in, _ := Raw.Parse(tt.in) 536 in, _ = tt.option.Canonicalize(in) 537 if in.String() != tt.out { 538 t.Errorf("%d:%s: was %s; want %s", i, tt.in, in.String(), tt.out) 539 } 540 } 541 // Test idempotence. 542 for _, base := range Supported.BaseLanguages() { 543 tag, _ := Raw.Compose(base) 544 got, _ := All.Canonicalize(tag) 545 want, _ := All.Canonicalize(got) 546 if got != want { 547 t.Errorf("idem(%s): got %s; want %s", tag, got, want) 548 } 549 } 550 } 551 552 func TestTypeForKey(t *testing.T) { 553 tests := []struct{ key, in, out string }{ 554 {"co", "en", ""}, 555 {"co", "en-u-abc", ""}, 556 {"co", "en-u-co-phonebk", "phonebk"}, 557 {"co", "en-u-co-phonebk-cu-aud", "phonebk"}, 558 {"co", "x-foo-u-co-phonebk", ""}, 559 {"va", "en-US-u-va-posix", "posix"}, 560 {"rg", "en-u-rg-gbzzzz", "gbzzzz"}, 561 {"nu", "en-u-co-phonebk-nu-arabic", "arabic"}, 562 {"kc", "cmn-u-co-stroke", ""}, 563 {"rg", "cmn-u-rg", ""}, 564 {"rg", "cmn-u-rg-co-stroke", ""}, 565 {"co", "cmn-u-rg-co-stroke", "stroke"}, 566 {"co", "cmn-u-co-rg-gbzzzz", ""}, 567 {"rg", "cmn-u-co-rg-gbzzzz", "gbzzzz"}, 568 {"rg", "cmn-u-rg-gbzzzz-nlzzzz", "gbzzzz"}, 569 } 570 for _, tt := range tests { 571 if v := Make(tt.in).TypeForKey(tt.key); v != tt.out { 572 t.Errorf("%q[%q]: was %q; want %q", tt.in, tt.key, v, tt.out) 573 } 574 } 575 } 576 577 func TestParent(t *testing.T) { 578 tests := []struct{ in, out string }{ 579 // Strip variants and extensions first 580 {"de-u-co-phonebk", "de"}, 581 {"de-1994", "de"}, 582 {"de-Latn-1994", "de"}, // remove superfluous script. 583 584 // Ensure the canonical Tag for an entry is in the chain for base-script 585 // pairs. 586 {"zh-Hans", "zh"}, 587 588 // Skip the script if it is the maximized version. CLDR files for the 589 // skipped tag are always empty. 590 {"zh-Hans-TW", "zh"}, 591 {"zh-Hans-CN", "zh"}, 592 593 // Insert the script if the maximized script is not the same as the 594 // maximized script of the base language. 595 {"zh-TW", "zh-Hant"}, 596 {"zh-HK", "zh-Hant"}, 597 {"zh-Hant-TW", "zh-Hant"}, 598 {"zh-Hant-HK", "zh-Hant"}, 599 600 // Non-default script skips to und. 601 // CLDR 602 {"az-Cyrl", "und"}, 603 {"bs-Cyrl", "und"}, 604 {"en-Dsrt", "und"}, 605 {"ha-Arab", "und"}, 606 {"mn-Mong", "und"}, 607 {"pa-Arab", "und"}, 608 {"shi-Latn", "und"}, 609 {"sr-Latn", "und"}, 610 {"uz-Arab", "und"}, 611 {"uz-Cyrl", "und"}, 612 {"vai-Latn", "und"}, 613 {"zh-Hant", "und"}, 614 // extra 615 {"nl-Cyrl", "und"}, 616 617 // World english inherits from en-001. 618 {"en-150", "en-001"}, 619 {"en-AU", "en-001"}, 620 {"en-BE", "en-001"}, 621 {"en-GG", "en-001"}, 622 {"en-GI", "en-001"}, 623 {"en-HK", "en-001"}, 624 {"en-IE", "en-001"}, 625 {"en-IM", "en-001"}, 626 {"en-IN", "en-001"}, 627 {"en-JE", "en-001"}, 628 {"en-MT", "en-001"}, 629 {"en-NZ", "en-001"}, 630 {"en-PK", "en-001"}, 631 {"en-SG", "en-001"}, 632 633 // Spanish in Latin-American countries have es-419 as parent. 634 {"es-AR", "es-419"}, 635 {"es-BO", "es-419"}, 636 {"es-CL", "es-419"}, 637 {"es-CO", "es-419"}, 638 {"es-CR", "es-419"}, 639 {"es-CU", "es-419"}, 640 {"es-DO", "es-419"}, 641 {"es-EC", "es-419"}, 642 {"es-GT", "es-419"}, 643 {"es-HN", "es-419"}, 644 {"es-MX", "es-419"}, 645 {"es-NI", "es-419"}, 646 {"es-PA", "es-419"}, 647 {"es-PE", "es-419"}, 648 {"es-PR", "es-419"}, 649 {"es-PY", "es-419"}, 650 {"es-SV", "es-419"}, 651 {"es-US", "es-419"}, 652 {"es-UY", "es-419"}, 653 {"es-VE", "es-419"}, 654 // exceptions (according to CLDR) 655 {"es-CW", "es"}, 656 657 // Inherit from pt-PT, instead of pt for these countries. 658 {"pt-AO", "pt-PT"}, 659 {"pt-CV", "pt-PT"}, 660 {"pt-GW", "pt-PT"}, 661 {"pt-MO", "pt-PT"}, 662 {"pt-MZ", "pt-PT"}, 663 {"pt-ST", "pt-PT"}, 664 {"pt-TL", "pt-PT"}, 665 666 {"en-GB-u-co-phonebk-rg-uszzzz", "en-GB"}, 667 {"en-GB-u-rg-uszzzz", "en-GB"}, 668 {"en-US-u-va-posix", "en-US"}, 669 670 // Difference between language and regional tag. 671 {"ca-ES-valencia", "ca-ES"}, 672 {"ca-ES-valencia-u-rg-ptzzzz", "ca-ES"}, 673 {"en-US-u-va-variant", "en-US"}, 674 {"en-u-va-variant", "en"}, 675 {"en-u-rg-gbzzzz", "en"}, 676 {"en-US-u-rg-gbzzzz", "en-US"}, 677 {"nl-US-u-rg-gbzzzz", "nl-US"}, 678 } 679 for _, tt := range tests { 680 tag := Raw.MustParse(tt.in) 681 if p := Raw.MustParse(tt.out); p != tag.Parent() { 682 t.Errorf("%s: was %v; want %v", tt.in, tag.Parent(), p) 683 } 684 } 685 } 686 687 var ( 688 // Tags without error that don't need to be changed. 689 benchBasic = []string{ 690 "en", 691 "en-Latn", 692 "en-GB", 693 "za", 694 "zh-Hant", 695 "zh", 696 "zh-HK", 697 "ar-MK", 698 "en-CA", 699 "fr-CA", 700 "fr-CH", 701 "fr", 702 "lv", 703 "he-IT", 704 "tlh", 705 "ja", 706 "ja-Jpan", 707 "ja-Jpan-JP", 708 "de-1996", 709 "de-CH", 710 "sr", 711 "sr-Latn", 712 } 713 // Tags with extensions, not changes required. 714 benchExt = []string{ 715 "x-a-b-c-d", 716 "x-aa-bbbb-cccccccc-d", 717 "en-x_cc-b-bbb-a-aaa", 718 "en-c_cc-b-bbb-a-aaa-x-x", 719 "en-u-co-phonebk", 720 "en-Cyrl-u-co-phonebk", 721 "en-US-u-co-phonebk-cu-xau", 722 "en-nedix-u-co-phonebk", 723 "en-t-t0-abcd", 724 "en-t-nl-latn", 725 "en-t-t0-abcd-x-a", 726 "en_t_pt_MLt", 727 "en-t-fr-est", 728 } 729 // Change, but not memory allocation required. 730 benchSimpleChange = []string{ 731 "EN", 732 "i-klingon", 733 "en-latn", 734 "zh-cmn-Hans-CN", 735 "iw-NL", 736 } 737 // Change and memory allocation required. 738 benchChangeAlloc = []string{ 739 "en-c_cc-b-bbb-a-aaa", 740 "en-u-cu-xua-co-phonebk", 741 "en-u-cu-xua-co-phonebk-a-cd", 742 "en-u-def-abc-cu-xua-co-phonebk", 743 "en-t-en-Cyrl-NL-1994", 744 "en-t-en-Cyrl-NL-1994-t0-abc-def", 745 } 746 // Tags that result in errors. 747 benchErr = []string{ 748 // IllFormed 749 "x_A.-B-C_D", 750 "en-u-cu-co-phonebk", 751 "en-u-cu-xau-co", 752 "en-t-nl-abcd", 753 // Invalid 754 "xx", 755 "nl-Uuuu", 756 "nl-QB", 757 } 758 benchChange = append(benchSimpleChange, benchChangeAlloc...) 759 benchAll = append(append(append(benchBasic, benchExt...), benchChange...), benchErr...) 760 ) 761 762 func doParse(b *testing.B, tag []string) { 763 for i := 0; i < b.N; i++ { 764 // Use the modulo instead of looping over all tags so that we get a somewhat 765 // meaningful ns/op. 766 Parse(tag[i%len(tag)]) 767 } 768 } 769 770 func BenchmarkParse(b *testing.B) { 771 doParse(b, benchAll) 772 } 773 774 func BenchmarkParseBasic(b *testing.B) { 775 doParse(b, benchBasic) 776 } 777 778 func BenchmarkParseError(b *testing.B) { 779 doParse(b, benchErr) 780 } 781 782 func BenchmarkParseSimpleChange(b *testing.B) { 783 doParse(b, benchSimpleChange) 784 } 785 786 func BenchmarkParseChangeAlloc(b *testing.B) { 787 doParse(b, benchChangeAlloc) 788 }