123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- // Copyright 2017 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package cldrtree
- import (
- "bytes"
- "flag"
- "io/ioutil"
- "log"
- "math/rand"
- "path/filepath"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "testing"
- "golang.org/x/text/internal/gen"
- "golang.org/x/text/internal/language/compact"
- "golang.org/x/text/language"
- "golang.org/x/text/unicode/cldr"
- )
- var genOutput = flag.Bool("gen", false, "generate output files")
- func TestAliasRegexp(t *testing.T) {
- testCases := []struct {
- alias string
- want []string
- }{{
- alias: "miscPatterns[@numberSystem='latn']",
- want: []string{
- "miscPatterns[@numberSystem='latn']",
- "miscPatterns",
- "[@numberSystem='latn']",
- "numberSystem",
- "latn",
- },
- }, {
- alias: `calendar[@type='greg-foo']/days/`,
- want: []string{
- "calendar[@type='greg-foo']",
- "calendar",
- "[@type='greg-foo']",
- "type",
- "greg-foo",
- },
- }, {
- alias: "eraAbbr",
- want: []string{
- "eraAbbr",
- "eraAbbr",
- "",
- "",
- "",
- },
- }, {
- // match must be anchored at beginning.
- alias: `../calendar[@type='gregorian']/days/`,
- }}
- for _, tc := range testCases {
- t.Run(tc.alias, func(t *testing.T) {
- got := aliasRe.FindStringSubmatch(tc.alias)
- if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("got %v; want %v", got, tc.want)
- }
- })
- }
- }
- func TestBuild(t *testing.T) {
- tree1, _ := loadTestdata(t, "test1")
- tree2, _ := loadTestdata(t, "test2")
- // Constants for second test
- const (
- calendar = iota
- field
- )
- const (
- month = iota
- era
- filler
- cyclicNameSet
- )
- const (
- abbreviated = iota
- narrow
- wide
- )
- testCases := []struct {
- desc string
- tree *Tree
- locale string
- path []uint16
- isFeature bool
- result string
- }{{
- desc: "und/chinese month format wide m1",
- tree: tree1,
- locale: "und",
- path: path(calendar, 0, month, 0, wide, 1),
- result: "cM01",
- }, {
- desc: "und/chinese month format wide m12",
- tree: tree1,
- locale: "und",
- path: path(calendar, 0, month, 0, wide, 12),
- result: "cM12",
- }, {
- desc: "und/non-existing value",
- tree: tree1,
- locale: "und",
- path: path(calendar, 0, month, 0, wide, 13),
- result: "",
- }, {
- desc: "und/dangi:chinese month format wide",
- tree: tree1,
- locale: "und",
- path: path(calendar, 1, month, 0, wide, 1),
- result: "cM01",
- }, {
- desc: "und/chinese month format abbreviated:wide",
- tree: tree1,
- locale: "und",
- path: path(calendar, 0, month, 0, abbreviated, 1),
- result: "cM01",
- }, {
- desc: "und/chinese month format narrow:wide",
- tree: tree1,
- locale: "und",
- path: path(calendar, 0, month, 0, narrow, 1),
- result: "cM01",
- }, {
- desc: "und/gregorian month format wide",
- tree: tree1,
- locale: "und",
- path: path(calendar, 2, month, 0, wide, 2),
- result: "gM02",
- }, {
- desc: "und/gregorian month format:stand-alone narrow",
- tree: tree1,
- locale: "und",
- path: path(calendar, 2, month, 0, narrow, 1),
- result: "1",
- }, {
- desc: "und/gregorian month stand-alone:format abbreviated",
- tree: tree1,
- locale: "und",
- path: path(calendar, 2, month, 1, abbreviated, 1),
- result: "gM01",
- }, {
- desc: "und/gregorian month stand-alone:format wide ",
- tree: tree1,
- locale: "und",
- path: path(calendar, 2, month, 1, abbreviated, 1),
- result: "gM01",
- }, {
- desc: "und/dangi:chinese month format narrow:wide ",
- tree: tree1,
- locale: "und",
- path: path(calendar, 1, month, 0, narrow, 4),
- result: "cM04",
- }, {
- desc: "und/field era displayname 0",
- tree: tree2,
- locale: "und",
- path: path(field, 0, 0, 0),
- result: "Era",
- }, {
- desc: "en/field era displayname 0",
- tree: tree2,
- locale: "en",
- path: path(field, 0, 0, 0),
- result: "era",
- }, {
- desc: "und/calendar hebrew format wide 7-leap",
- tree: tree2,
- locale: "und",
- path: path(calendar, 7, month, 0, wide, 0),
- result: "Adar II",
- }, {
- desc: "en-GB:en-001:en:und/calendar hebrew format wide 7-leap",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 7, month, 0, wide, 0),
- result: "Adar II",
- }, {
- desc: "und/buddhist month format wide 11",
- tree: tree2,
- locale: "und",
- path: path(calendar, 0, month, 0, wide, 12),
- result: "genWideM12",
- }, {
- desc: "en-GB/gregorian month stand-alone narrow 2",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, month, 1, narrow, 3),
- result: "gbNarrowM3",
- }, {
- desc: "en-GB/gregorian month format narrow 3/missing in en-GB",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, month, 0, narrow, 4),
- result: "enNarrowM4",
- }, {
- desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, month, 0, narrow, 7),
- result: "gregNarrowM7",
- }, {
- desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, month, 0, narrow, 7),
- result: "gregNarrowM7",
- }, {
- desc: "en-GB/gregorian era narrow",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, era, abbreviated, 0, 1),
- isFeature: true,
- result: "AD",
- }, {
- desc: "en-GB/gregorian era narrow",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, era, narrow, 0, 0),
- isFeature: true,
- result: "BC",
- }, {
- desc: "en-GB/gregorian era narrow",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 6, era, wide, 1, 0),
- isFeature: true,
- result: "Before Common Era",
- }, {
- desc: "en-GB/dangi:chinese cyclicName, months, format, narrow:abbreviated 2",
- tree: tree2,
- locale: "en-GB",
- path: path(calendar, 1, cyclicNameSet, 3, 0, 1, 2),
- isFeature: true,
- result: "year2",
- }, {
- desc: "en-GB/field era-narrow ",
- tree: tree2,
- locale: "en-GB",
- path: path(field, 2, 0, 0),
- result: "era",
- }, {
- desc: "en-GB/field month-narrow relativeTime future one",
- tree: tree2,
- locale: "en-GB",
- path: path(field, 5, 2, 0, 1),
- isFeature: true,
- result: "001NarrowFutMOne",
- }, {
- // Don't fall back to the one of "en".
- desc: "en-GB/field month-short relativeTime past one:other",
- tree: tree2,
- locale: "en-GB",
- path: path(field, 4, 2, 1, 1),
- isFeature: true,
- result: "001ShortPastMOther",
- }, {
- desc: "en-GB/field month relativeTime future two:other",
- tree: tree2,
- locale: "en-GB",
- path: path(field, 3, 2, 0, 2),
- isFeature: true,
- result: "enFutMOther",
- }}
- for _, tc := range testCases {
- t.Run(tc.desc, func(t *testing.T) {
- tag, _ := compact.RegionalID(compact.Tag(language.MustParse(tc.locale)))
- s := tc.tree.lookup(tag, tc.isFeature, tc.path...)
- if s != tc.result {
- t.Errorf("got %q; want %q", s, tc.result)
- }
- })
- }
- }
- func path(e ...uint16) []uint16 { return e }
- func TestGen(t *testing.T) {
- testCases := []string{"test1", "test2"}
- for _, tc := range testCases {
- t.Run(tc, func(t *testing.T) {
- _, got := loadTestdata(t, tc)
- // Remove sizes that may vary per architecture.
- re := regexp.MustCompile("// Size: [0-9]*")
- got = re.ReplaceAllLiteral(got, []byte("// Size: xxxx"))
- re = regexp.MustCompile("// Total table size [0-9]*")
- got = re.ReplaceAllLiteral(got, []byte("// Total table size: xxxx"))
- file := filepath.Join("testdata", tc, "output.go")
- if *genOutput {
- ioutil.WriteFile(file, got, 0700)
- t.SkipNow()
- }
- b, err := ioutil.ReadFile(file)
- if err != nil {
- t.Fatalf("failed to open file: %v", err)
- }
- if want := string(b); string(got) != want {
- t.Log(string(got))
- t.Errorf("files differ")
- }
- })
- }
- }
- func loadTestdata(t *testing.T, test string) (tree *Tree, file []byte) {
- b := New("test")
- var d cldr.Decoder
- data, err := d.DecodePath(filepath.Join("testdata", test))
- if err != nil {
- t.Fatalf("error decoding testdata: %v", err)
- }
- context := Enum("context")
- widthMap := func(s string) string {
- // Align era with width values.
- if r, ok := map[string]string{
- "eraAbbr": "abbreviated",
- "eraNarrow": "narrow",
- "eraNames": "wide",
- }[s]; ok {
- s = r
- }
- return "w" + strings.Title(s)
- }
- width := EnumFunc("width", widthMap, "abbreviated", "narrow", "wide")
- month := Enum("month", "leap7")
- relative := EnumFunc("relative", func(s string) string {
- x, err := strconv.ParseInt(s, 10, 8)
- if err != nil {
- log.Fatal("Invalid number:", err)
- }
- return []string{
- "before1",
- "current",
- "after1",
- }[x+1]
- })
- cycleType := EnumFunc("cycleType", func(s string) string {
- return "cyc" + strings.Title(s)
- })
- r := rand.New(rand.NewSource(0))
- for _, loc := range data.Locales() {
- ldml := data.RawLDML(loc)
- x := b.Locale(language.Make(loc))
- if x := x.Index(ldml.Dates.Calendars); x != nil {
- for _, cal := range ldml.Dates.Calendars.Calendar {
- x := x.IndexFromType(cal)
- if x := x.Index(cal.Months); x != nil {
- for _, mc := range cal.Months.MonthContext {
- x := x.IndexFromType(mc, context)
- for _, mw := range mc.MonthWidth {
- x := x.IndexFromType(mw, width)
- for _, m := range mw.Month {
- x.SetValue(m.Yeartype+m.Type, m, month)
- }
- }
- }
- }
- if x := x.Index(cal.CyclicNameSets); x != nil {
- for _, cns := range cal.CyclicNameSets.CyclicNameSet {
- x := x.IndexFromType(cns, cycleType)
- for _, cc := range cns.CyclicNameContext {
- x := x.IndexFromType(cc, context)
- for _, cw := range cc.CyclicNameWidth {
- x := x.IndexFromType(cw, width)
- for _, c := range cw.CyclicName {
- x.SetValue(c.Type, c)
- }
- }
- }
- }
- }
- if x := x.Index(cal.Eras); x != nil {
- opts := []Option{width, SharedType()}
- if x := x.Index(cal.Eras.EraNames, opts...); x != nil {
- for _, e := range cal.Eras.EraNames.Era {
- x.IndexFromAlt(e).SetValue(e.Type, e)
- }
- }
- if x := x.Index(cal.Eras.EraAbbr, opts...); x != nil {
- for _, e := range cal.Eras.EraAbbr.Era {
- x.IndexFromAlt(e).SetValue(e.Type, e)
- }
- }
- if x := x.Index(cal.Eras.EraNarrow, opts...); x != nil {
- for _, e := range cal.Eras.EraNarrow.Era {
- x.IndexFromAlt(e).SetValue(e.Type, e)
- }
- }
- }
- {
- // Ensure having more than 2 buckets.
- f := x.IndexWithName("filler")
- b := make([]byte, maxStrlen)
- opt := &options{parent: x}
- r.Read(b)
- f.setValue("0", string(b), opt)
- }
- }
- }
- if x := x.Index(ldml.Dates.Fields); x != nil {
- for _, f := range ldml.Dates.Fields.Field {
- x := x.IndexFromType(f)
- for _, d := range f.DisplayName {
- x.Index(d).SetValue("", d)
- }
- for _, r := range f.Relative {
- x.Index(r).SetValue(r.Type, r, relative)
- }
- for _, rt := range f.RelativeTime {
- x := x.Index(rt).IndexFromType(rt)
- for _, p := range rt.RelativeTimePattern {
- x.SetValue(p.Count, p)
- }
- }
- for _, rp := range f.RelativePeriod {
- x.Index(rp).SetValue("", rp)
- }
- }
- }
- }
- tree, err = build(b)
- if err != nil {
- t.Fatal("error building tree:", err)
- }
- w := gen.NewCodeWriter()
- generate(b, tree, w)
- generateTestData(b, w)
- buf := &bytes.Buffer{}
- if _, err = w.WriteGo(buf, "test", ""); err != nil {
- t.Log(buf.String())
- t.Fatal("error generating code:", err)
- }
- return tree, buf.Bytes()
- }
|