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.
13 "golang.org/x/text/internal"
14 "golang.org/x/text/internal/catmsg"
15 "golang.org/x/text/language"
23 var testCases = []struct {
28 desc: "empty catalog",
37 {"en", "hello", "Hello!"},
42 {"en", "hello", "Hello!"},
43 {"en-US", "hello", "Hello!"},
44 {"en-GB", "hello", "Hello!"},
45 {"en-oxendict", "hello", "Hello!"},
46 {"en-oxendict-u-ms-metric", "hello", "Hello!"},
49 desc: "hierarchical languages",
51 {"en", "hello", "Hello!"},
52 {"en-GB", "hello", "Hellø!"},
53 {"en-US", "hello", "Howdy!"},
54 {"en", "greetings", "Greetings!"},
59 {"en", "hello", "Hello!"},
60 {"en-US", "hello", "Howdy!"},
61 {"en-GB", "hello", "Hellø!"},
62 {"en-oxendict", "hello", "Hello!"},
63 {"en-US-oxendict-u-ms-metric", "hello", "Howdy!"},
65 {"und", "greetings", ""},
66 {"nl", "greetings", ""},
67 {"en", "greetings", "Greetings!"},
68 {"en-US", "greetings", "Greetings!"},
69 {"en-GB", "greetings", "Greetings!"},
70 {"en-oxendict", "greetings", "Greetings!"},
71 {"en-US-oxendict-u-ms-metric", "greetings", "Greetings!"},
76 {"en", "hello %s", []Message{
77 Var("person", String("Jane")),
78 String("Hello ${person}!"),
80 {"en", "hello error", []Message{
81 Var("person", String("Jane")),
82 noMatchMessage{}, // trigger sequence path.
83 String("Hello ${person."),
85 {"en", "fallback to var value", []Message{
86 Var("you", noMatchMessage{}, noMatchMessage{}),
87 String("Hello ${you}."),
89 {"en", "scopes", []Message{
90 Var("person1", String("Mark")),
91 Var("person2", String("Jane")),
93 Var("person1", String("Joe")),
94 String("${person1} and ${person2}")),
95 String("Hello ${couple}."),
97 {"en", "missing var", String("Hello ${missing}.")},
100 {"en", "hello %s", "Hello Jane!"},
101 {"en", "hello error", "Hello $!(MISSINGBRACE)"},
102 {"en", "fallback to var value", "Hello you."},
103 {"en", "scopes", "Hello Joe and Jane."},
104 {"en", "missing var", "Hello missing."},
109 {"en", "macro1", String("Hello ${macro1(1)}.")},
110 {"en", "macro2", String("Hello ${ macro1(2) }!")},
111 {"en", "macroWS", String("Hello ${ macro1( 2 ) }!")},
112 {"en", "missing", String("Hello ${ missing(1 }.")},
113 {"en", "badnum", String("Hello ${ badnum(1b) }.")},
114 {"en", "undefined", String("Hello ${ undefined(1) }.")},
115 {"en", "macroU", String("Hello ${ macroU(2) }!")},
118 {"en", "macro1", "Hello Joe."},
119 {"en", "macro2", "Hello Joe!"},
120 {"en-US", "macroWS", "Hello Joe!"},
121 {"en-NL", "missing", "Hello $!(MISSINGPAREN)."},
122 {"en", "badnum", "Hello $!(BADNUM)."},
123 {"en", "undefined", "Hello undefined."},
124 {"en", "macroU", "Hello macroU!"},
127 func initCat(entries []entry) (*Catalog, []language.Tag) {
128 tags := []language.Tag{}
130 for _, e := range entries {
131 tag := language.MustParse(e.tag)
132 tags = append(tags, tag)
133 switch msg := e.msg.(type) {
135 cat.SetString(tag, e.key, msg)
137 cat.Set(tag, e.key, msg)
139 cat.Set(tag, e.key, msg...)
142 return cat, internal.UniqueTags(tags)
145 func TestCatalog(t *testing.T) {
146 for _, tc := range testCases {
147 t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) {
148 cat, wantTags := initCat(tc.cat)
149 cat.SetMacro(language.English, "macro1", String("Joe"))
150 cat.SetMacro(language.Und, "macro2", String("${macro1(1)}"))
151 cat.SetMacro(language.English, "macroU", noMatchMessage{})
153 if got := cat.Languages(); !reflect.DeepEqual(got, wantTags) {
154 t.Errorf("%s:Languages: got %v; want %v", tc.desc, got, wantTags)
157 for _, e := range tc.lookup {
158 t.Run(fmt.Sprintf("%s/%s", e.tag, e.key), func(t *testing.T) {
159 tag := language.MustParse(e.tag)
160 buf := testRenderer{}
161 ctx := cat.Context(tag, &buf)
162 want := e.msg.(string)
163 err := ctx.Execute(e.key)
164 gotFound := err != ErrNotFound
165 wantFound := want != ""
166 if gotFound != wantFound {
167 t.Fatalf("err: got %v (%v); want %v", gotFound, err, wantFound)
169 if got := buf.buf.String(); got != want {
170 t.Errorf("Lookup:\ngot %q\nwant %q", got, want)
178 type testRenderer struct {
182 func (f *testRenderer) Arg(i int) interface{} { return nil }
183 func (f *testRenderer) Render(s string) { f.buf.WriteString(s) }
185 var msgNoMatch = catmsg.Register("no match", func(d *catmsg.Decoder) bool {
186 return false // no match
189 type noMatchMessage struct{}
191 func (noMatchMessage) Compile(e *catmsg.Encoder) error {
192 e.EncodeMessageType(msgNoMatch)
193 return catmsg.ErrIncomplete