github.com/go-enjin/golang-org-x-text@v0.12.1-enjin.2/internal/cldrtree/cldrtree_test.go (about) 1 // Copyright 2017 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 cldrtree 6 7 import ( 8 "bytes" 9 "flag" 10 "log" 11 "math/rand" 12 "os" 13 "path/filepath" 14 "reflect" 15 "regexp" 16 "strconv" 17 "strings" 18 "testing" 19 20 "github.com/go-enjin/golang-org-x-text/internal/gen" 21 "github.com/go-enjin/golang-org-x-text/internal/language/compact" 22 "github.com/go-enjin/golang-org-x-text/language" 23 "github.com/go-enjin/golang-org-x-text/unicode/cldr" 24 ) 25 26 var genOutput = flag.Bool("gen", false, "generate output files") 27 28 func TestAliasRegexp(t *testing.T) { 29 testCases := []struct { 30 alias string 31 want []string 32 }{{ 33 alias: "miscPatterns[@numberSystem='latn']", 34 want: []string{ 35 "miscPatterns[@numberSystem='latn']", 36 "miscPatterns", 37 "[@numberSystem='latn']", 38 "numberSystem", 39 "latn", 40 }, 41 }, { 42 alias: `calendar[@type='greg-foo']/days/`, 43 want: []string{ 44 "calendar[@type='greg-foo']", 45 "calendar", 46 "[@type='greg-foo']", 47 "type", 48 "greg-foo", 49 }, 50 }, { 51 alias: "eraAbbr", 52 want: []string{ 53 "eraAbbr", 54 "eraAbbr", 55 "", 56 "", 57 "", 58 }, 59 }, { 60 // match must be anchored at beginning. 61 alias: `../calendar[@type='gregorian']/days/`, 62 }} 63 for _, tc := range testCases { 64 t.Run(tc.alias, func(t *testing.T) { 65 got := aliasRe.FindStringSubmatch(tc.alias) 66 if !reflect.DeepEqual(got, tc.want) { 67 t.Errorf("got %v; want %v", got, tc.want) 68 } 69 }) 70 } 71 } 72 73 func TestBuild(t *testing.T) { 74 tree1, _ := loadTestdata(t, "test1") 75 tree2, _ := loadTestdata(t, "test2") 76 77 // Constants for second test 78 const ( 79 calendar = iota 80 field 81 ) 82 const ( 83 month = iota 84 era 85 filler 86 cyclicNameSet 87 ) 88 const ( 89 abbreviated = iota 90 narrow 91 wide 92 ) 93 94 testCases := []struct { 95 desc string 96 tree *Tree 97 locale string 98 path []uint16 99 isFeature bool 100 result string 101 }{{ 102 desc: "und/chinese month format wide m1", 103 tree: tree1, 104 locale: "und", 105 path: path(calendar, 0, month, 0, wide, 1), 106 result: "cM01", 107 }, { 108 desc: "und/chinese month format wide m12", 109 tree: tree1, 110 locale: "und", 111 path: path(calendar, 0, month, 0, wide, 12), 112 result: "cM12", 113 }, { 114 desc: "und/non-existing value", 115 tree: tree1, 116 locale: "und", 117 path: path(calendar, 0, month, 0, wide, 13), 118 result: "", 119 }, { 120 desc: "und/dangi:chinese month format wide", 121 tree: tree1, 122 locale: "und", 123 path: path(calendar, 1, month, 0, wide, 1), 124 result: "cM01", 125 }, { 126 desc: "und/chinese month format abbreviated:wide", 127 tree: tree1, 128 locale: "und", 129 path: path(calendar, 0, month, 0, abbreviated, 1), 130 result: "cM01", 131 }, { 132 desc: "und/chinese month format narrow:wide", 133 tree: tree1, 134 locale: "und", 135 path: path(calendar, 0, month, 0, narrow, 1), 136 result: "cM01", 137 }, { 138 desc: "und/gregorian month format wide", 139 tree: tree1, 140 locale: "und", 141 path: path(calendar, 2, month, 0, wide, 2), 142 result: "gM02", 143 }, { 144 desc: "und/gregorian month format:stand-alone narrow", 145 tree: tree1, 146 locale: "und", 147 path: path(calendar, 2, month, 0, narrow, 1), 148 result: "1", 149 }, { 150 desc: "und/gregorian month stand-alone:format abbreviated", 151 tree: tree1, 152 locale: "und", 153 path: path(calendar, 2, month, 1, abbreviated, 1), 154 result: "gM01", 155 }, { 156 desc: "und/gregorian month stand-alone:format wide ", 157 tree: tree1, 158 locale: "und", 159 path: path(calendar, 2, month, 1, abbreviated, 1), 160 result: "gM01", 161 }, { 162 desc: "und/dangi:chinese month format narrow:wide ", 163 tree: tree1, 164 locale: "und", 165 path: path(calendar, 1, month, 0, narrow, 4), 166 result: "cM04", 167 }, { 168 desc: "und/field era displayname 0", 169 tree: tree2, 170 locale: "und", 171 path: path(field, 0, 0, 0), 172 result: "Era", 173 }, { 174 desc: "en/field era displayname 0", 175 tree: tree2, 176 locale: "en", 177 path: path(field, 0, 0, 0), 178 result: "era", 179 }, { 180 desc: "und/calendar hebrew format wide 7-leap", 181 tree: tree2, 182 locale: "und", 183 path: path(calendar, 7, month, 0, wide, 0), 184 result: "Adar II", 185 }, { 186 desc: "en-GB:en-001:en:und/calendar hebrew format wide 7-leap", 187 tree: tree2, 188 locale: "en-GB", 189 path: path(calendar, 7, month, 0, wide, 0), 190 result: "Adar II", 191 }, { 192 desc: "und/buddhist month format wide 11", 193 tree: tree2, 194 locale: "und", 195 path: path(calendar, 0, month, 0, wide, 12), 196 result: "genWideM12", 197 }, { 198 desc: "en-GB/gregorian month stand-alone narrow 2", 199 tree: tree2, 200 locale: "en-GB", 201 path: path(calendar, 6, month, 1, narrow, 3), 202 result: "gbNarrowM3", 203 }, { 204 desc: "en-GB/gregorian month format narrow 3/missing in en-GB", 205 tree: tree2, 206 locale: "en-GB", 207 path: path(calendar, 6, month, 0, narrow, 4), 208 result: "enNarrowM4", 209 }, { 210 desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB", 211 tree: tree2, 212 locale: "en-GB", 213 path: path(calendar, 6, month, 0, narrow, 7), 214 result: "gregNarrowM7", 215 }, { 216 desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB", 217 tree: tree2, 218 locale: "en-GB", 219 path: path(calendar, 6, month, 0, narrow, 7), 220 result: "gregNarrowM7", 221 }, { 222 desc: "en-GB/gregorian era narrow", 223 tree: tree2, 224 locale: "en-GB", 225 path: path(calendar, 6, era, abbreviated, 0, 1), 226 isFeature: true, 227 result: "AD", 228 }, { 229 desc: "en-GB/gregorian era narrow", 230 tree: tree2, 231 locale: "en-GB", 232 path: path(calendar, 6, era, narrow, 0, 0), 233 isFeature: true, 234 result: "BC", 235 }, { 236 desc: "en-GB/gregorian era narrow", 237 tree: tree2, 238 locale: "en-GB", 239 path: path(calendar, 6, era, wide, 1, 0), 240 isFeature: true, 241 result: "Before Common Era", 242 }, { 243 desc: "en-GB/dangi:chinese cyclicName, months, format, narrow:abbreviated 2", 244 tree: tree2, 245 locale: "en-GB", 246 path: path(calendar, 1, cyclicNameSet, 3, 0, 1, 2), 247 isFeature: true, 248 result: "year2", 249 }, { 250 desc: "en-GB/field era-narrow ", 251 tree: tree2, 252 locale: "en-GB", 253 path: path(field, 2, 0, 0), 254 result: "era", 255 }, { 256 desc: "en-GB/field month-narrow relativeTime future one", 257 tree: tree2, 258 locale: "en-GB", 259 path: path(field, 5, 2, 0, 1), 260 isFeature: true, 261 result: "001NarrowFutMOne", 262 }, { 263 // Don't fall back to the one of "en". 264 desc: "en-GB/field month-short relativeTime past one:other", 265 tree: tree2, 266 locale: "en-GB", 267 path: path(field, 4, 2, 1, 1), 268 isFeature: true, 269 result: "001ShortPastMOther", 270 }, { 271 desc: "en-GB/field month relativeTime future two:other", 272 tree: tree2, 273 locale: "en-GB", 274 path: path(field, 3, 2, 0, 2), 275 isFeature: true, 276 result: "enFutMOther", 277 }} 278 279 for _, tc := range testCases { 280 t.Run(tc.desc, func(t *testing.T) { 281 tag, _ := compact.RegionalID(compact.Tag(language.MustParse(tc.locale))) 282 s := tc.tree.lookup(tag, tc.isFeature, tc.path...) 283 if s != tc.result { 284 t.Errorf("got %q; want %q", s, tc.result) 285 } 286 }) 287 } 288 } 289 290 func path(e ...uint16) []uint16 { return e } 291 292 func TestGen(t *testing.T) { 293 testCases := []string{"test1", "test2"} 294 for _, tc := range testCases { 295 t.Run(tc, func(t *testing.T) { 296 _, got := loadTestdata(t, tc) 297 298 // Remove sizes that may vary per architecture. 299 re := regexp.MustCompile("// Size: [0-9]*") 300 got = re.ReplaceAllLiteral(got, []byte("// Size: xxxx")) 301 re = regexp.MustCompile("// Total table size [0-9]*") 302 got = re.ReplaceAllLiteral(got, []byte("// Total table size: xxxx")) 303 304 file := filepath.Join("testdata", tc, "output.go") 305 if *genOutput { 306 os.WriteFile(file, got, 0700) 307 t.SkipNow() 308 } 309 310 b, err := os.ReadFile(file) 311 if err != nil { 312 t.Fatalf("failed to open file: %v", err) 313 } 314 if want := string(b); string(got) != want { 315 t.Log(string(got)) 316 t.Errorf("files differ") 317 } 318 }) 319 } 320 } 321 322 func loadTestdata(t *testing.T, test string) (tree *Tree, file []byte) { 323 b := New("test") 324 325 var d cldr.Decoder 326 327 data, err := d.DecodePath(filepath.Join("testdata", test)) 328 if err != nil { 329 t.Fatalf("error decoding testdata: %v", err) 330 } 331 332 context := Enum("context") 333 widthMap := func(s string) string { 334 // Align era with width values. 335 if r, ok := map[string]string{ 336 "eraAbbr": "abbreviated", 337 "eraNarrow": "narrow", 338 "eraNames": "wide", 339 }[s]; ok { 340 s = r 341 } 342 return "w" + strings.Title(s) 343 } 344 width := EnumFunc("width", widthMap, "abbreviated", "narrow", "wide") 345 month := Enum("month", "leap7") 346 relative := EnumFunc("relative", func(s string) string { 347 x, err := strconv.ParseInt(s, 10, 8) 348 if err != nil { 349 log.Fatal("Invalid number:", err) 350 } 351 return []string{ 352 "before1", 353 "current", 354 "after1", 355 }[x+1] 356 }) 357 cycleType := EnumFunc("cycleType", func(s string) string { 358 return "cyc" + strings.Title(s) 359 }) 360 r := rand.New(rand.NewSource(0)) 361 362 for _, loc := range data.Locales() { 363 ldml := data.RawLDML(loc) 364 x := b.Locale(language.Make(loc)) 365 366 if x := x.Index(ldml.Dates.Calendars); x != nil { 367 for _, cal := range ldml.Dates.Calendars.Calendar { 368 x := x.IndexFromType(cal) 369 if x := x.Index(cal.Months); x != nil { 370 for _, mc := range cal.Months.MonthContext { 371 x := x.IndexFromType(mc, context) 372 for _, mw := range mc.MonthWidth { 373 x := x.IndexFromType(mw, width) 374 for _, m := range mw.Month { 375 x.SetValue(m.Yeartype+m.Type, m, month) 376 } 377 } 378 } 379 } 380 if x := x.Index(cal.CyclicNameSets); x != nil { 381 for _, cns := range cal.CyclicNameSets.CyclicNameSet { 382 x := x.IndexFromType(cns, cycleType) 383 for _, cc := range cns.CyclicNameContext { 384 x := x.IndexFromType(cc, context) 385 for _, cw := range cc.CyclicNameWidth { 386 x := x.IndexFromType(cw, width) 387 for _, c := range cw.CyclicName { 388 x.SetValue(c.Type, c) 389 } 390 } 391 } 392 } 393 } 394 if x := x.Index(cal.Eras); x != nil { 395 opts := []Option{width, SharedType()} 396 if x := x.Index(cal.Eras.EraNames, opts...); x != nil { 397 for _, e := range cal.Eras.EraNames.Era { 398 x.IndexFromAlt(e).SetValue(e.Type, e) 399 } 400 } 401 if x := x.Index(cal.Eras.EraAbbr, opts...); x != nil { 402 for _, e := range cal.Eras.EraAbbr.Era { 403 x.IndexFromAlt(e).SetValue(e.Type, e) 404 } 405 } 406 if x := x.Index(cal.Eras.EraNarrow, opts...); x != nil { 407 for _, e := range cal.Eras.EraNarrow.Era { 408 x.IndexFromAlt(e).SetValue(e.Type, e) 409 } 410 } 411 } 412 { 413 // Ensure having more than 2 buckets. 414 f := x.IndexWithName("filler") 415 b := make([]byte, maxStrlen) 416 opt := &options{parent: x} 417 r.Read(b) 418 f.setValue("0", string(b), opt) 419 } 420 } 421 } 422 if x := x.Index(ldml.Dates.Fields); x != nil { 423 for _, f := range ldml.Dates.Fields.Field { 424 x := x.IndexFromType(f) 425 for _, d := range f.DisplayName { 426 x.Index(d).SetValue("", d) 427 } 428 for _, r := range f.Relative { 429 x.Index(r).SetValue(r.Type, r, relative) 430 } 431 for _, rt := range f.RelativeTime { 432 x := x.Index(rt).IndexFromType(rt) 433 for _, p := range rt.RelativeTimePattern { 434 x.SetValue(p.Count, p) 435 } 436 } 437 for _, rp := range f.RelativePeriod { 438 x.Index(rp).SetValue("", rp) 439 } 440 } 441 } 442 } 443 444 tree, err = build(b) 445 if err != nil { 446 t.Fatal("error building tree:", err) 447 } 448 w := gen.NewCodeWriter() 449 generate(b, tree, w) 450 generateTestData(b, w) 451 buf := &bytes.Buffer{} 452 if _, err = w.WriteGo(buf, "test", ""); err != nil { 453 t.Log(buf.String()) 454 t.Fatal("error generating code:", err) 455 } 456 return tree, buf.Bytes() 457 }