...

Source file src/golang.org/x/text/language/display/display_test.go

Documentation: golang.org/x/text/language/display

     1  // Copyright 2014 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 display
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  	"unicode"
    13  
    14  	"golang.org/x/text/internal/testtext"
    15  	"golang.org/x/text/language"
    16  	"golang.org/x/text/message"
    17  )
    18  
    19  // TODO: test that tables are properly dropped by the linker for various use
    20  // cases.
    21  
    22  var (
    23  	firstLang2aa  = language.MustParseBase("aa")
    24  	lastLang2zu   = language.MustParseBase("zu")
    25  	firstLang3ace = language.MustParseBase("ace")
    26  	lastLang3zza  = language.MustParseBase("zza")
    27  	firstTagAr001 = language.MustParse("ar-001")
    28  	lastTagZhHant = language.MustParse("zh-Hant")
    29  )
    30  
    31  // TestValues tests that for all languages, regions, and scripts in Values, at
    32  // least one language has a name defined for it by checking it exists in
    33  // English, which is assumed to be the most comprehensive. It is also tested
    34  // that a Namer returns "" for unsupported values.
    35  func TestValues(t *testing.T) {
    36  	type testcase struct {
    37  		kind string
    38  		n    Namer
    39  	}
    40  	// checkDefined checks that a value exists in a Namer.
    41  	checkDefined := func(x interface{}, namers []testcase) {
    42  		for _, n := range namers {
    43  			testtext.Run(t, fmt.Sprintf("%s.Name(%s)", n.kind, x), func(t *testing.T) {
    44  				if n.n.Name(x) == "" {
    45  					// As of version 28 there is no data for az-Arab in English,
    46  					// although there is useful data in other languages.
    47  					if x.(fmt.Stringer).String() == "az-Arab" {
    48  						return
    49  					}
    50  					t.Errorf("supported but no result")
    51  				}
    52  			})
    53  		}
    54  	}
    55  	// checkUnsupported checks that a value does not exist in a Namer.
    56  	checkUnsupported := func(x interface{}, namers []testcase) {
    57  		for _, n := range namers {
    58  			if got := n.n.Name(x); got != "" {
    59  				t.Fatalf("%s.Name(%s): unsupported tag gave non-empty result: %q", n.kind, x, got)
    60  			}
    61  		}
    62  	}
    63  
    64  	tags := map[language.Tag]bool{}
    65  	namers := []testcase{
    66  		{"Languages(en)", Languages(language.English)},
    67  		{"Tags(en)", Tags(language.English)},
    68  		{"English.Languages()", English.Languages()},
    69  		{"English.Tags()", English.Tags()},
    70  	}
    71  	for _, tag := range Values.Tags() {
    72  		checkDefined(tag, namers)
    73  		tags[tag] = true
    74  	}
    75  	for _, base := range language.Supported.BaseLanguages() {
    76  		tag, _ := language.All.Compose(base)
    77  		if !tags[tag] {
    78  			checkUnsupported(tag, namers)
    79  		}
    80  	}
    81  
    82  	regions := map[language.Region]bool{}
    83  	namers = []testcase{
    84  		{"Regions(en)", Regions(language.English)},
    85  		{"English.Regions()", English.Regions()},
    86  	}
    87  	for _, r := range Values.Regions() {
    88  		checkDefined(r, namers)
    89  		regions[r] = true
    90  	}
    91  	for _, r := range language.Supported.Regions() {
    92  		if r = r.Canonicalize(); !regions[r] {
    93  			checkUnsupported(r, namers)
    94  		}
    95  	}
    96  
    97  	scripts := map[language.Script]bool{}
    98  	namers = []testcase{
    99  		{"Scripts(en)", Scripts(language.English)},
   100  		{"English.Scripts()", English.Scripts()},
   101  	}
   102  	for _, s := range Values.Scripts() {
   103  		checkDefined(s, namers)
   104  		scripts[s] = true
   105  	}
   106  	for _, s := range language.Supported.Scripts() {
   107  		// Canonicalize the script.
   108  		tag, _ := language.DeprecatedScript.Compose(s)
   109  		if _, s, _ = tag.Raw(); !scripts[s] {
   110  			checkUnsupported(s, namers)
   111  		}
   112  	}
   113  }
   114  
   115  // TestSupported tests that we have at least some Namers for languages that we
   116  // claim to support. To test the claims in the documentation, it also verifies
   117  // that if a Namer is returned, it will have at least some data.
   118  func TestSupported(t *testing.T) {
   119  	supportedTags := Supported.Tags()
   120  	if len(supportedTags) != numSupported {
   121  		t.Errorf("number of supported was %d; want %d", len(supportedTags), numSupported)
   122  	}
   123  
   124  	namerFuncs := []struct {
   125  		kind string
   126  		fn   func(language.Tag) Namer
   127  	}{
   128  		{"Tags", Tags},
   129  		{"Languages", Languages},
   130  		{"Regions", Regions},
   131  		{"Scripts", Scripts},
   132  	}
   133  
   134  	// Verify that we have at least one Namer for all tags we claim to support.
   135  	tags := make(map[language.Tag]bool)
   136  	for _, tag := range supportedTags {
   137  		// Test we have at least one Namer for this supported Tag.
   138  		found := false
   139  		for _, kind := range namerFuncs {
   140  			if defined(t, kind.kind, kind.fn(tag), tag) {
   141  				found = true
   142  			}
   143  		}
   144  		if !found {
   145  			t.Errorf("%s: supported, but no data available", tag)
   146  		}
   147  		if tags[tag] {
   148  			t.Errorf("%s: included in Supported.Tags more than once", tag)
   149  		}
   150  		tags[tag] = true
   151  	}
   152  
   153  	// Verify that we have no Namers for tags we don't claim to support.
   154  	for _, base := range language.Supported.BaseLanguages() {
   155  		tag, _ := language.All.Compose(base)
   156  		// Skip tags that are supported after matching.
   157  		if _, _, conf := matcher.Match(tag); conf != language.No {
   158  			continue
   159  		}
   160  		// Test there are no Namers for this tag.
   161  		for _, kind := range namerFuncs {
   162  			if defined(t, kind.kind, kind.fn(tag), tag) {
   163  				t.Errorf("%[1]s(%[2]s) returns a Namer, but %[2]s is not in the set of supported Tags.", kind.kind, tag)
   164  			}
   165  		}
   166  	}
   167  }
   168  
   169  // defined reports whether n is a proper Namer, which means it is non-nil and
   170  // must have at least one non-empty value.
   171  func defined(t *testing.T, kind string, n Namer, tag language.Tag) bool {
   172  	if n == nil {
   173  		return false
   174  	}
   175  	switch kind {
   176  	case "Tags":
   177  		for _, t := range Values.Tags() {
   178  			if n.Name(t) != "" {
   179  				return true
   180  			}
   181  		}
   182  	case "Languages":
   183  		for _, t := range Values.BaseLanguages() {
   184  			if n.Name(t) != "" {
   185  				return true
   186  			}
   187  		}
   188  	case "Regions":
   189  		for _, t := range Values.Regions() {
   190  			if n.Name(t) != "" {
   191  				return true
   192  			}
   193  		}
   194  	case "Scripts":
   195  		for _, t := range Values.Scripts() {
   196  			if n.Name(t) != "" {
   197  				return true
   198  			}
   199  		}
   200  	}
   201  	t.Errorf("%s(%s) returns non-nil Namer without content", kind, tag)
   202  	return false
   203  }
   204  
   205  func TestCoverage(t *testing.T) {
   206  	en := language.English
   207  	tests := []struct {
   208  		n Namer
   209  		x interface{}
   210  	}{
   211  		{Languages(en), Values.Tags()},
   212  		{Scripts(en), Values.Scripts()},
   213  		{Regions(en), Values.Regions()},
   214  	}
   215  	for i, tt := range tests {
   216  		uniq := make(map[string]interface{})
   217  
   218  		v := reflect.ValueOf(tt.x)
   219  		for j := 0; j < v.Len(); j++ {
   220  			x := v.Index(j).Interface()
   221  			// As of version 28 there is no data for az-Arab in English,
   222  			// although there is useful data in other languages.
   223  			if x.(fmt.Stringer).String() == "az-Arab" {
   224  				continue
   225  			}
   226  			s := tt.n.Name(x)
   227  			if s == "" {
   228  				t.Errorf("%d:%d:%s: missing content", i, j, x)
   229  			} else if uniq[s] != nil {
   230  				t.Errorf("%d:%d:%s: identical return value %q for %v and %v", i, j, x, s, x, uniq[s])
   231  			}
   232  			uniq[s] = x
   233  		}
   234  	}
   235  }
   236  
   237  // TestUpdate tests whether dictionary entries for certain languages need to be
   238  // updated. For some languages, some of the headers may be empty or they may be
   239  // identical to the parent. This code detects if such entries need to be updated
   240  // after a table update.
   241  func TestUpdate(t *testing.T) {
   242  	tests := []struct {
   243  		d   *Dictionary
   244  		tag string
   245  	}{
   246  		{ModernStandardArabic, "ar-001"},
   247  		{AmericanEnglish, "en-US"},
   248  		{EuropeanSpanish, "es-ES"},
   249  		{BrazilianPortuguese, "pt-BR"},
   250  		{SimplifiedChinese, "zh-Hans"},
   251  	}
   252  
   253  	for _, tt := range tests {
   254  		_, i, _ := matcher.Match(language.MustParse(tt.tag))
   255  		if !reflect.DeepEqual(tt.d.lang, langHeaders[i]) {
   256  			t.Errorf("%s: lang table update needed", tt.tag)
   257  		}
   258  		if !reflect.DeepEqual(tt.d.script, scriptHeaders[i]) {
   259  			t.Errorf("%s: script table update needed", tt.tag)
   260  		}
   261  		if !reflect.DeepEqual(tt.d.region, regionHeaders[i]) {
   262  			t.Errorf("%s: region table update needed", tt.tag)
   263  		}
   264  	}
   265  }
   266  
   267  func TestIndex(t *testing.T) {
   268  	notIn := []string{"aa", "xx", "zz", "aaa", "xxx", "zzz", "Aaaa", "Xxxx", "Zzzz"}
   269  	tests := []tagIndex{
   270  		{
   271  			"",
   272  			"",
   273  			"",
   274  		},
   275  		{
   276  			"bb",
   277  			"",
   278  			"",
   279  		},
   280  		{
   281  			"",
   282  			"bbb",
   283  			"",
   284  		},
   285  		{
   286  			"",
   287  			"",
   288  			"Bbbb",
   289  		},
   290  		{
   291  			"bb",
   292  			"bbb",
   293  			"Bbbb",
   294  		},
   295  		{
   296  			"bbccddyy",
   297  			"bbbcccdddyyy",
   298  			"BbbbCcccDdddYyyy",
   299  		},
   300  	}
   301  	for i, tt := range tests {
   302  		// Create the test set from the tagIndex.
   303  		cnt := 0
   304  		for sz := 2; sz <= 4; sz++ {
   305  			a := tt[sz-2]
   306  			for j := 0; j < len(a); j += sz {
   307  				s := a[j : j+sz]
   308  				if idx := tt.index(s); idx != cnt {
   309  					t.Errorf("%d:%s: index was %d; want %d", i, s, idx, cnt)
   310  				}
   311  				cnt++
   312  			}
   313  		}
   314  		if n := tt.len(); n != cnt {
   315  			t.Errorf("%d: len was %d; want %d", i, n, cnt)
   316  		}
   317  		for _, x := range notIn {
   318  			if idx := tt.index(x); idx != -1 {
   319  				t.Errorf("%d:%s: index was %d; want -1", i, x, idx)
   320  			}
   321  		}
   322  	}
   323  }
   324  
   325  func TestTag(t *testing.T) {
   326  	tests := []struct {
   327  		dict string
   328  		tag  string
   329  		name string
   330  	}{
   331  		// sr is in Value.Languages(), but is not supported by agq.
   332  		{"agq", "sr", "|[language: sr]"},
   333  		{"nl", "nl", "Nederlands"},
   334  		// CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
   335  		// Flemish in English, though. TODO: check if this is a CLDR bug.
   336  		// {"nl", "nl-BE", "Vlaams"},
   337  		{"nl", "nl-BE", "Nederlands (België)"},
   338  		{"nl", "vls", "West-Vlaams"},
   339  		{"en", "nl-BE", "Flemish"},
   340  		{"en", "en", "English"},
   341  		{"en", "en-GB", "British English"},
   342  		{"en", "en-US", "American English"}, // American English in CLDR 24+
   343  		{"ru", "ru", "русский"},
   344  		{"ru", "ru-RU", "русский (Россия)"},
   345  		{"ru", "ru-Cyrl", "русский (кириллица)"},
   346  		{"en", lastLang2zu.String(), "Zulu"},
   347  		{"en", firstLang2aa.String(), "Afar"},
   348  		{"en", lastLang3zza.String(), "Zaza"},
   349  		{"en", firstLang3ace.String(), "Achinese"},
   350  		{"en", firstTagAr001.String(), "Modern Standard Arabic"},
   351  		{"en", lastTagZhHant.String(), "Traditional Chinese"},
   352  		{"en", "aaa", "|Unknown language (aaa)"},
   353  		{"en", "zzj", "|Unknown language (zzj)"},
   354  		// If full tag doesn't match, try without script or region.
   355  		{"en", "aa-Hans", "Afar (Simplified Han)"},
   356  		{"en", "af-Arab", "Afrikaans (Arabic)"},
   357  		{"en", "zu-Cyrl", "Zulu (Cyrillic)"},
   358  		{"en", "aa-GB", "Afar (United Kingdom)"},
   359  		{"en", "af-NA", "Afrikaans (Namibia)"},
   360  		{"en", "zu-BR", "Zulu (Brazil)"},
   361  		// Correct inheritance and language selection.
   362  		{"zh", "zh-TW", "中文 (台湾)"},
   363  		{"zh", "zh-Hant-TW", "繁体中文 (台湾)"},
   364  		{"zh-Hant", "zh-TW", "中文 (台灣)"},
   365  		{"zh-Hant", "zh-Hant-TW", "繁體中文 (台灣)"},
   366  		// Some rather arbitrary interpretations for Serbian. This is arguably
   367  		// correct and consistent with the way zh-[Hant-]TW is handled. It will
   368  		// also give results more in line with the expectations if users
   369  		// explicitly use "sh".
   370  		{"sr-Latn", "sr-ME", "srpski (Crna Gora)"},
   371  		{"sr-Latn", "sr-Latn-ME", "srpskohrvatski (Crna Gora)"},
   372  		// Double script and region
   373  		{"nl", "en-Cyrl-BE", "Engels (Cyrillisch, België)"},
   374  	}
   375  	for _, tt := range tests {
   376  		t.Run(tt.dict+"/"+tt.tag, func(t *testing.T) {
   377  			name, fmtName := splitName(tt.name)
   378  			dict := language.MustParse(tt.dict)
   379  			tag := language.Raw.MustParse(tt.tag)
   380  			d := Tags(dict)
   381  			if n := d.Name(tag); n != name {
   382  				// There are inconsistencies w.r.t. capitalization in the tests
   383  				// due to CLDR's update procedure which treats modern and other
   384  				// languages differently.
   385  				// See https://unicode.org/cldr/trac/ticket/8051.
   386  				// TODO: use language capitalization to sanitize the strings.
   387  				t.Errorf("Name(%s) = %q; want %q", tag, n, name)
   388  			}
   389  
   390  			p := message.NewPrinter(dict)
   391  			if n := p.Sprint(Tag(tag)); n != fmtName {
   392  				t.Errorf("Tag(%s) = %q; want %q", tag, n, fmtName)
   393  			}
   394  		})
   395  	}
   396  }
   397  
   398  func splitName(names string) (name, formatName string) {
   399  	split := strings.Split(names, "|")
   400  	name, formatName = split[0], split[0]
   401  	if len(split) > 1 {
   402  		formatName = split[1]
   403  	}
   404  	return name, formatName
   405  }
   406  
   407  func TestLanguage(t *testing.T) {
   408  	tests := []struct {
   409  		dict string
   410  		tag  string
   411  		name string
   412  	}{
   413  		// sr is in Value.Languages(), but is not supported by agq.
   414  		{"agq", "sr", "|[language: sr]"},
   415  		// CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
   416  		// Flemish in English, though. TODO: this is probably incorrect.
   417  		// West-Vlaams (vls) is not Vlaams. West-Vlaams could be considered its
   418  		// own language, whereas Vlaams is generally Dutch. So expect to have
   419  		// to change these tests back.
   420  		{"nl", "nl", "Nederlands"},
   421  		{"nl", "vls", "West-Vlaams"},
   422  		{"nl", "nl-BE", "Nederlands"},
   423  		{"en", "pt", "Portuguese"},
   424  		{"en", "pt-PT", "European Portuguese"},
   425  		{"en", "pt-BR", "Brazilian Portuguese"},
   426  		{"en", "en", "English"},
   427  		{"en", "en-GB", "British English"},
   428  		{"en", "en-US", "American English"}, // American English in CLDR 24+
   429  		{"en", lastLang2zu.String(), "Zulu"},
   430  		{"en", firstLang2aa.String(), "Afar"},
   431  		{"en", lastLang3zza.String(), "Zaza"},
   432  		{"en", firstLang3ace.String(), "Achinese"},
   433  		{"en", firstTagAr001.String(), "Modern Standard Arabic"},
   434  		{"en", lastTagZhHant.String(), "Traditional Chinese"},
   435  		{"en", "aaa", "|Unknown language (aaa)"},
   436  		{"en", "zzj", "|Unknown language (zzj)"},
   437  		// If full tag doesn't match, try without script or region.
   438  		{"en", "aa-Hans", "Afar"},
   439  		{"en", "af-Arab", "Afrikaans"},
   440  		{"en", "zu-Cyrl", "Zulu"},
   441  		{"en", "aa-GB", "Afar"},
   442  		{"en", "af-NA", "Afrikaans"},
   443  		{"en", "zu-BR", "Zulu"},
   444  		{"agq", "zh-Hant", "|[language: zh-Hant]"},
   445  		{"en", "sh", "Serbo-Croatian"},
   446  		{"en", "sr-Latn", "Serbo-Croatian"},
   447  		{"en", "sr", "Serbian"},
   448  		{"en", "sr-ME", "Serbian"},
   449  		{"en", "sr-Latn-ME", "Serbo-Croatian"}, // See comments in TestTag.
   450  	}
   451  	for _, tt := range tests {
   452  		testtext.Run(t, tt.dict+"/"+tt.tag, func(t *testing.T) {
   453  			name, fmtName := splitName(tt.name)
   454  			dict := language.MustParse(tt.dict)
   455  			tag := language.Raw.MustParse(tt.tag)
   456  			p := message.NewPrinter(dict)
   457  			d := Languages(dict)
   458  			if n := d.Name(tag); n != name {
   459  				t.Errorf("Name(%v) = %q; want %q", tag, n, name)
   460  			}
   461  			if n := p.Sprint(Language(tag)); n != fmtName {
   462  				t.Errorf("Language(%v) = %q; want %q", tag, n, fmtName)
   463  			}
   464  			if len(tt.tag) <= 3 {
   465  				base := language.MustParseBase(tt.tag)
   466  				if n := d.Name(base); n != name {
   467  					t.Errorf("Name(%v) = %q; want %q", base, n, name)
   468  				}
   469  				if n := p.Sprint(Language(base)); n != fmtName {
   470  					t.Errorf("Language(%v) = %q; want %q", base, n, fmtName)
   471  				}
   472  			}
   473  		})
   474  	}
   475  }
   476  
   477  func TestScript(t *testing.T) {
   478  	tests := []struct {
   479  		dict string
   480  		scr  string
   481  		name string
   482  	}{
   483  		{"nl", "Arab", "Arabisch"},
   484  		{"en", "Arab", "Arabic"},
   485  		{"en", "Zzzz", "Unknown Script"},
   486  		{"zh-Hant", "Hang", "韓文字"},
   487  		{"zh-Hant-HK", "Hang", "韓文字"},
   488  		{"zh", "Arab", "阿拉伯文"},
   489  		{"zh-Hans-HK", "Arab", "阿拉伯文"}, // same as zh
   490  		{"zh-Hant", "Arab", "阿拉伯文"},
   491  		{"zh-Hant-HK", "Arab", "阿拉伯文"}, // same as zh
   492  		// Canonicalized form
   493  		{"en", "Qaai", "Inherited"},    // deprecated script, now is Zinh
   494  		{"en", "sh", "Unknown Script"}, // sh canonicalizes to sr-Latn
   495  		{"en", "en", "Unknown Script"},
   496  		// Don't introduce scripts with canonicalization.
   497  		{"en", "sh", "Unknown Script"}, // sh canonicalizes to sr-Latn
   498  	}
   499  	for _, tt := range tests {
   500  		t.Run(tt.dict+"/"+tt.scr, func(t *testing.T) {
   501  			name, fmtName := splitName(tt.name)
   502  			dict := language.MustParse(tt.dict)
   503  			p := message.NewPrinter(dict)
   504  			d := Scripts(dict)
   505  			var tag language.Tag
   506  			if unicode.IsUpper(rune(tt.scr[0])) {
   507  				x := language.MustParseScript(tt.scr)
   508  				if n := d.Name(x); n != name {
   509  					t.Errorf("Name(%v) = %q; want %q", x, n, name)
   510  				}
   511  				if n := p.Sprint(Script(x)); n != fmtName {
   512  					t.Errorf("Script(%v) = %q; want %q", x, n, fmtName)
   513  				}
   514  				tag, _ = language.Raw.Compose(x)
   515  			} else {
   516  				tag = language.Raw.MustParse(tt.scr)
   517  			}
   518  			if n := d.Name(tag); n != name {
   519  				t.Errorf("Name(%v) = %q; want %q", tag, n, name)
   520  			}
   521  			if n := p.Sprint(Script(tag)); n != fmtName {
   522  				t.Errorf("Script(%v) = %q; want %q", tag, n, fmtName)
   523  			}
   524  		})
   525  	}
   526  }
   527  
   528  func TestRegion(t *testing.T) {
   529  	tests := []struct {
   530  		dict string
   531  		reg  string
   532  		name string
   533  	}{
   534  		{"nl", "NL", "Nederland"},
   535  		{"en", "US", "United States"},
   536  		{"en", "ZZ", "Unknown Region"},
   537  		{"en-GB", "NL", "Netherlands"},
   538  		// Canonical equivalents
   539  		{"en", "UK", "United Kingdom"},
   540  		// No region
   541  		{"en", "pt", "Unknown Region"},
   542  		{"en", "und", "Unknown Region"},
   543  		// Don't introduce regions with canonicalization.
   544  		{"en", "mo", "Unknown Region"},
   545  	}
   546  	for _, tt := range tests {
   547  		t.Run(tt.dict+"/"+tt.reg, func(t *testing.T) {
   548  			dict := language.MustParse(tt.dict)
   549  			p := message.NewPrinter(dict)
   550  			d := Regions(dict)
   551  			var tag language.Tag
   552  			if unicode.IsUpper(rune(tt.reg[0])) {
   553  				// Region
   554  				x := language.MustParseRegion(tt.reg)
   555  				if n := d.Name(x); n != tt.name {
   556  					t.Errorf("Name(%v) = %q; want %q", x, n, tt.name)
   557  				}
   558  				if n := p.Sprint(Region(x)); n != tt.name {
   559  					t.Errorf("Region(%v) = %q; want %q", x, n, tt.name)
   560  				}
   561  				tag, _ = language.Raw.Compose(x)
   562  			} else {
   563  				tag = language.Raw.MustParse(tt.reg)
   564  			}
   565  			if n := d.Name(tag); n != tt.name {
   566  				t.Errorf("Name(%v) = %q; want %q", tag, n, tt.name)
   567  			}
   568  			if n := p.Sprint(Region(tag)); n != tt.name {
   569  				t.Errorf("Region(%v) = %q; want %q", tag, n, tt.name)
   570  			}
   571  		})
   572  	}
   573  }
   574  
   575  func TestSelf(t *testing.T) {
   576  	tests := []struct {
   577  		tag  string
   578  		name string
   579  	}{
   580  		{"nl", "Nederlands"},
   581  		// CLDR 30 dropped Vlaams as the word for nl-BE. It is still called
   582  		// Flemish in English, though. TODO: check if this is a CLDR bug.
   583  		// {"nl-BE", "Vlaams"},
   584  		{"nl-BE", "Nederlands"},
   585  		{"en-GB", "British English"},
   586  		{lastLang2zu.String(), "isiZulu"},
   587  		{firstLang2aa.String(), ""},  // not defined
   588  		{lastLang3zza.String(), ""},  // not defined
   589  		{firstLang3ace.String(), ""}, // not defined
   590  		{firstTagAr001.String(), "العربية الرسمية الحديثة"},
   591  		{"ar", "العربية"},
   592  		{lastTagZhHant.String(), "繁體中文"},
   593  		{"aaa", ""},
   594  		{"zzj", ""},
   595  		// Drop entries that are not in the requested script, even if there is
   596  		// an entry for the language.
   597  		{"aa-Hans", ""},
   598  		{"af-Arab", ""},
   599  		{"zu-Cyrl", ""},
   600  		// Append the country name in the language of the matching language.
   601  		{"af-NA", "Afrikaans"},
   602  		{"zh", "中文"},
   603  		// zh-TW should match zh-Hant instead of zh!
   604  		{"zh-TW", "繁體中文"},
   605  		{"zh-Hant", "繁體中文"},
   606  		{"zh-Hans", "简体中文"},
   607  		{"zh-Hant-TW", "繁體中文"},
   608  		{"zh-Hans-TW", "简体中文"},
   609  		// Take the entry for sr which has the matching script.
   610  		// TODO: Capitalization changed as of CLDR 26, but change seems
   611  		// arbitrary. Revisit capitalization with revision 27. See
   612  		// https://unicode.org/cldr/trac/ticket/8051.
   613  		{"sr", "српски"},
   614  		// TODO: sr-ME should show up as Serbian or Montenegrin, not Serbo-
   615  		// Croatian. This is an artifact of the current algorithm, which is the
   616  		// way it is to have the preferred behavior for other languages such as
   617  		// Chinese. We can hardwire this case in the table generator or package
   618  		// code, but we first check if CLDR can be updated.
   619  		// {"sr-ME", "Srpski"}, // Is Srpskohrvatski
   620  		{"sr-Latn-ME", "srpskohrvatski"},
   621  		{"sr-Cyrl-ME", "српски"},
   622  		{"sr-NL", "српски"},
   623  		// NOTE: kk is defined, but in Cyrillic script. For China, Arab is the
   624  		// dominant script. We do not have data for kk-Arab and we chose to not
   625  		// fall back in such cases.
   626  		{"kk-CN", ""},
   627  	}
   628  	for i, tt := range tests {
   629  		d := Self
   630  		if n := d.Name(language.Raw.MustParse(tt.tag)); n != tt.name {
   631  			t.Errorf("%d:%s: was %q; want %q", i, tt.tag, n, tt.name)
   632  		}
   633  	}
   634  }
   635  
   636  func TestEquivalence(t *testing.T) {
   637  	testCases := []struct {
   638  		desc  string
   639  		namer Namer
   640  	}{
   641  		{"Self", Self},
   642  		{"Tags", Tags(language.Romanian)},
   643  		{"Languages", Languages(language.Romanian)},
   644  		{"Scripts", Scripts(language.Romanian)},
   645  	}
   646  	for _, tc := range testCases {
   647  		t.Run(tc.desc, func(t *testing.T) {
   648  			ro := tc.namer.Name(language.Raw.MustParse("ro-MD"))
   649  			mo := tc.namer.Name(language.Raw.MustParse("mo"))
   650  			if ro != mo {
   651  				t.Errorf("%q != %q", ro, mo)
   652  			}
   653  		})
   654  	}
   655  }
   656  
   657  func TestDictionaryLang(t *testing.T) {
   658  	tests := []struct {
   659  		d    *Dictionary
   660  		tag  string
   661  		name string
   662  	}{
   663  		{English, "en", "English"},
   664  		{Portuguese, "af", "africâner"},
   665  		{EuropeanPortuguese, "af", "africanês"},
   666  		{English, "nl-BE", "Flemish"},
   667  	}
   668  	for i, test := range tests {
   669  		tag := language.MustParse(test.tag)
   670  		if got := test.d.Tags().Name(tag); got != test.name {
   671  			t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
   672  		}
   673  		if base, _ := language.Compose(tag.Base()); base == tag {
   674  			if got := test.d.Languages().Name(base); got != test.name {
   675  				t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
   676  			}
   677  		}
   678  	}
   679  }
   680  
   681  func TestDictionaryRegion(t *testing.T) {
   682  	tests := []struct {
   683  		d      *Dictionary
   684  		region string
   685  		name   string
   686  	}{
   687  		{English, "FR", "France"},
   688  		{Portuguese, "009", "Oceania"},
   689  		{EuropeanPortuguese, "009", "Oceânia"},
   690  	}
   691  	for i, test := range tests {
   692  		tag := language.MustParseRegion(test.region)
   693  		if got := test.d.Regions().Name(tag); got != test.name {
   694  			t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
   695  		}
   696  	}
   697  }
   698  
   699  func TestDictionaryScript(t *testing.T) {
   700  	tests := []struct {
   701  		d      *Dictionary
   702  		script string
   703  		name   string
   704  	}{
   705  		{English, "Cyrl", "Cyrillic"},
   706  		{EuropeanPortuguese, "Gujr", "guzerate"},
   707  	}
   708  	for i, test := range tests {
   709  		tag := language.MustParseScript(test.script)
   710  		if got := test.d.Scripts().Name(tag); got != test.name {
   711  			t.Errorf("%d:%v: got %s; want %s", i, tag, got, test.name)
   712  		}
   713  	}
   714  }
   715  

View as plain text