1
2
3
4
5 package plural
6
7 import (
8 "fmt"
9 "strings"
10 "testing"
11
12 "golang.org/x/text/internal/catmsg"
13 "golang.org/x/text/language"
14 "golang.org/x/text/message/catalog"
15 )
16
17 func TestSelect(t *testing.T) {
18 lang := language.English
19 type test struct {
20 arg interface{}
21 result string
22 err string
23 }
24 testCases := []struct {
25 desc string
26 msg catalog.Message
27 err string
28 tests []test
29 }{{
30 desc: "basic",
31 msg: Selectf(1, "%d", "one", "foo", "other", "bar"),
32 tests: []test{
33 {arg: 0, result: "bar"},
34 {arg: 1, result: "foo"},
35 {arg: 2, result: "bar"},
36 {arg: opposite(1), result: "bar"},
37 {arg: opposite(2), result: "foo"},
38 {arg: "unknown", result: "bar"},
39 },
40 }, {
41 desc: "comparisons",
42 msg: Selectf(1, "%d",
43 "=0", "zero",
44 "=1", "one",
45 "one", "cannot match",
46 "<5", "<5",
47 "=5", "=5",
48 Other, "other"),
49 tests: []test{
50 {arg: 0, result: "zero"},
51 {arg: 1, result: "one"},
52 {arg: 2, result: "<5"},
53 {arg: 4, result: "<5"},
54 {arg: 5, result: "=5"},
55 {arg: 6, result: "other"},
56 {arg: "unknown", result: "other"},
57 },
58 }, {
59 desc: "fractions",
60 msg: Selectf(1, "%.2f", "one", "foo", "other", "bar"),
61 tests: []test{
62
63 {arg: 0, result: "bar"},
64 {arg: 1, result: "bar"},
65 },
66 }, {
67 desc: "decimal without fractions",
68 msg: Selectf(1, "%.0f", "one", "foo", "other", "bar"),
69 tests: []test{
70
71 {arg: 0, result: "bar"},
72 {arg: 1, result: "foo"},
73 },
74 }, {
75 desc: "scientific",
76 msg: Selectf(1, "%.0e", "one", "foo", "other", "bar"),
77 tests: []test{
78 {arg: 0, result: "bar"},
79 {arg: 1, result: "foo"},
80 },
81 }, {
82 desc: "variable",
83 msg: Selectf(1, "%.1g", "one", "foo", "other", "bar"),
84 tests: []test{
85
86 {arg: 0, result: "bar"},
87 {arg: 1, result: "foo"},
88 {arg: 2, result: "bar"},
89 },
90 }, {
91 desc: "default",
92 msg: Selectf(1, "", "one", "foo", "other", "bar"),
93 tests: []test{
94 {arg: 0, result: "bar"},
95 {arg: 1, result: "foo"},
96 {arg: 2, result: "bar"},
97 {arg: 1.0, result: "bar"},
98 },
99 }, {
100 desc: "nested",
101 msg: Selectf(1, "", "other", Selectf(2, "", "one", "foo", "other", "bar")),
102 tests: []test{
103 {arg: 0, result: "bar"},
104 {arg: 1, result: "foo"},
105 {arg: 2, result: "bar"},
106 },
107 }, {
108 desc: "arg unavailable",
109 msg: Selectf(100, "%.2f", "one", "foo", "other", "bar"),
110 tests: []test{{arg: 1, result: "bar"}},
111 }, {
112 desc: "no match",
113 msg: Selectf(1, "%.2f", "one", "foo"),
114 tests: []test{{arg: 0, result: "bar", err: catmsg.ErrNoMatch.Error()}},
115 }, {
116 desc: "error invalid form",
117 err: `invalid plural form "excessive"`,
118 msg: Selectf(1, "%d", "excessive", "foo"),
119 }, {
120 desc: "error form not used by language",
121 err: `form "many" not supported for language "en"`,
122 msg: Selectf(1, "%d", "many", "foo"),
123 }, {
124 desc: "error invalid selector",
125 err: `selector of type int; want string or Form`,
126 msg: Selectf(1, "%d", 1, "foo"),
127 }, {
128 desc: "error missing message",
129 err: `no message defined for selector one`,
130 msg: Selectf(1, "%d", "one"),
131 }, {
132 desc: "error invalid number",
133 err: `invalid number in selector "<1.00"`,
134 msg: Selectf(1, "%d", "<1.00"),
135 }, {
136 desc: "error empty selector",
137 err: `empty selector`,
138 msg: Selectf(1, "%d", "", "foo"),
139 }, {
140 desc: "error invalid message",
141 err: `message of type int; must be string or catalog.Message`,
142 msg: Selectf(1, "%d", "one", 3),
143 }, {
144 desc: "nested error",
145 err: `empty selector`,
146 msg: Selectf(1, "", "other", Selectf(2, "", "")),
147 }}
148 for _, tc := range testCases {
149 t.Run(tc.desc, func(t *testing.T) {
150 data, err := catmsg.Compile(lang, nil, tc.msg)
151 chkError(t, err, tc.err)
152 for _, tx := range tc.tests {
153 t.Run(fmt.Sprint(tx.arg), func(t *testing.T) {
154 r := renderer{arg: tx.arg}
155 d := catmsg.NewDecoder(lang, &r, nil)
156 err := d.Execute(data)
157 chkError(t, err, tx.err)
158 if r.result != tx.result {
159 t.Errorf("got %q; want %q", r.result, tx.result)
160 }
161 })
162 }
163 })
164 }
165 }
166
167 func chkError(t *testing.T, got error, want string) {
168 if (got == nil && want != "") ||
169 (got != nil && (want == "" || !strings.Contains(got.Error(), want))) {
170 t.Fatalf("got %v; want %v", got, want)
171 }
172 if got != nil {
173 t.SkipNow()
174 }
175 }
176
177 type renderer struct {
178 arg interface{}
179 result string
180 }
181
182 func (r *renderer) Render(s string) { r.result += s }
183 func (r *renderer) Arg(i int) interface{} {
184 if i > 10 {
185 return nil
186 }
187 return r.arg
188 }
189
190 type opposite int
191
192 func (o opposite) PluralForm(lang language.Tag, scale int) (Form, int) {
193 if o == 1 {
194 return Other, 1
195 }
196 return One, int(o)
197 }
198
View as plain text