OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / internal / catmsg / catmsg_test.go
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 catmsg
6
7 import (
8         "errors"
9         "strings"
10         "testing"
11
12         "golang.org/x/text/language"
13 )
14
15 type renderer struct {
16         args   []int
17         result string
18 }
19
20 func (r *renderer) Arg(i int) interface{} {
21         if i >= len(r.args) {
22                 return nil
23         }
24         return r.args[i]
25 }
26
27 func (r *renderer) Render(s string) {
28         if r.result != "" {
29                 r.result += "|"
30         }
31         r.result += s
32 }
33
34 func TestCodec(t *testing.T) {
35         type test struct {
36                 args   []int
37                 out    string
38                 decErr string
39         }
40         single := func(out, err string) []test { return []test{{out: out, decErr: err}} }
41         testCases := []struct {
42                 desc   string
43                 m      Message
44                 enc    string
45                 encErr string
46                 tests  []test
47         }{{
48                 desc:   "unused variable",
49                 m:      &Var{"name", String("foo")},
50                 encErr: errIsVar.Error(),
51                 tests:  single("", ""),
52         }, {
53                 desc:  "empty",
54                 m:     empty{},
55                 tests: single("", ""),
56         }, {
57                 desc:  "sequence with empty",
58                 m:     seq{empty{}},
59                 tests: single("", ""),
60         }, {
61                 desc:  "raw string",
62                 m:     Raw("foo"),
63                 tests: single("foo", ""),
64         }, {
65                 desc:  "raw string no sub",
66                 m:     Raw("${foo}"),
67                 enc:   "\x02${foo}",
68                 tests: single("${foo}", ""),
69         }, {
70                 desc:  "simple string",
71                 m:     String("foo"),
72                 tests: single("foo", ""),
73         }, {
74                 desc:   "missing var",
75                 m:      String("foo${bar}"),
76                 enc:    "\x03\x03foo\x02\x03bar",
77                 encErr: `unknown var "bar"`,
78                 tests:  single("foo|bar", ""),
79         }, {
80                 desc: "empty var",
81                 m: seq{
82                         &Var{"bar", seq{}},
83                         String("foo${bar}"),
84                 },
85                 enc: "\x00\x05\x04\x02bar\x03\x03foo\x00\x00",
86                 // TODO: recognize that it is cheaper to substitute bar.
87                 tests: single("foo|bar", ""),
88         }, {
89                 desc: "var after value",
90                 m: seq{
91                         String("foo${bar}"),
92                         &Var{"bar", String("baz")},
93                 },
94                 encErr: errIsVar.Error(),
95                 tests:  single("foo|bar", ""),
96         }, {
97                 desc: "substitution",
98                 m: seq{
99                         &Var{"bar", String("baz")},
100                         String("foo${bar}"),
101                 },
102                 tests: single("foo|baz", ""),
103         }, {
104                 desc: "shadowed variable",
105                 m: seq{
106                         &Var{"bar", String("baz")},
107                         seq{
108                                 &Var{"bar", String("BAZ")},
109                                 String("foo${bar}"),
110                         },
111                 },
112                 tests: single("foo|BAZ", ""),
113         }, {
114                 desc:  "nested value",
115                 m:     nestedLang{nestedLang{empty{}}},
116                 tests: single("nl|nl", ""),
117         }, {
118                 desc: "not shadowed variable",
119                 m: seq{
120                         &Var{"bar", String("baz")},
121                         seq{
122                                 String("foo${bar}"),
123                                 &Var{"bar", String("BAZ")},
124                         },
125                 },
126                 encErr: errIsVar.Error(),
127                 tests:  single("foo|baz", ""),
128         }, {
129                 desc: "duplicate variable",
130                 m: seq{
131                         &Var{"bar", String("baz")},
132                         &Var{"bar", String("BAZ")},
133                         String("${bar}"),
134                 },
135                 encErr: "catmsg: duplicate variable \"bar\"",
136                 tests:  single("baz", ""),
137         }, {
138                 desc: "complete incomplete variable",
139                 m: seq{
140                         &Var{"bar", incomplete{}},
141                         String("${bar}"),
142                 },
143                 enc: "\x00\t\b\x01\x01\x04\x04\x02bar\x03\x00\x00\x00",
144                 // TODO: recognize that it is cheaper to substitute bar.
145                 tests: single("bar", ""),
146         }, {
147                 desc: "incomplete sequence",
148                 m: seq{
149                         incomplete{},
150                         incomplete{},
151                 },
152                 encErr: ErrIncomplete.Error(),
153                 tests:  single("", ErrNoMatch.Error()),
154         }, {
155                 desc: "compile error variable",
156                 m: seq{
157                         &Var{"bar", errorCompileMsg{}},
158                         String("${bar}"),
159                 },
160                 encErr: errCompileTest.Error(),
161                 tests:  single("bar", ""),
162         }, {
163                 desc:   "compile error message",
164                 m:      errorCompileMsg{},
165                 encErr: errCompileTest.Error(),
166                 tests:  single("", ""),
167         }, {
168                 desc: "compile error sequence",
169                 m: seq{
170                         errorCompileMsg{},
171                         errorCompileMsg{},
172                 },
173                 encErr: errCompileTest.Error(),
174                 tests:  single("", ""),
175         }, {
176                 desc:  "macro",
177                 m:     String("${exists(1)}"),
178                 tests: single("you betya!", ""),
179         }, {
180                 desc:  "macro incomplete",
181                 m:     String("${incomplete(1)}"),
182                 enc:   "\x03\x00\x01\nincomplete\x01",
183                 tests: single("incomplete", ""),
184         }, {
185                 desc:  "macro undefined at end",
186                 m:     String("${undefined(1)}"),
187                 enc:   "\x03\x00\x01\tundefined\x01",
188                 tests: single("undefined", "catmsg: undefined macro \"undefined\""),
189         }, {
190                 desc:  "macro undefined with more text following",
191                 m:     String("${undefined(1)}."),
192                 enc:   "\x03\x00\x01\tundefined\x01\x01.",
193                 tests: single("undefined|.", "catmsg: undefined macro \"undefined\""),
194         }, {
195                 desc:   "macro missing paren",
196                 m:      String("${missing(1}"),
197                 encErr: "catmsg: missing ')'",
198                 tests:  single("$!(MISSINGPAREN)", ""),
199         }, {
200                 desc:   "macro bad num",
201                 m:      String("aa${bad(a)}"),
202                 encErr: "catmsg: invalid number \"a\"",
203                 tests:  single("aa$!(BADNUM)", ""),
204         }, {
205                 desc:   "var missing brace",
206                 m:      String("a${missing"),
207                 encErr: "catmsg: missing '}'",
208                 tests:  single("a$!(MISSINGBRACE)", ""),
209         }}
210         r := &renderer{}
211         dec := NewDecoder(language.Und, r, macros)
212         for _, tc := range testCases {
213                 t.Run(tc.desc, func(t *testing.T) {
214                         // Use a language other than Und so that we can test
215                         // passing the language to nested values.
216                         data, err := Compile(language.Dutch, macros, tc.m)
217                         if failErr(err, tc.encErr) {
218                                 t.Errorf("encoding error: got %+q; want %+q", err, tc.encErr)
219                         }
220                         if tc.enc != "" && data != tc.enc {
221                                 t.Errorf("encoding: got %+q; want %+q", data, tc.enc)
222                         }
223                         for _, st := range tc.tests {
224                                 t.Run("", func(t *testing.T) {
225                                         *r = renderer{args: st.args}
226                                         if err = dec.Execute(data); failErr(err, st.decErr) {
227                                                 t.Errorf("decoding error: got %+q; want %+q", err, st.decErr)
228                                         }
229                                         if r.result != st.out {
230                                                 t.Errorf("decode: got %+q; want %+q", r.result, st.out)
231                                         }
232                                 })
233                         }
234                 })
235         }
236 }
237
238 func failErr(got error, want string) bool {
239         if got == nil {
240                 return want != ""
241         }
242         return want == "" || !strings.Contains(got.Error(), want)
243 }
244
245 type seq []Message
246
247 func (s seq) Compile(e *Encoder) (err error) {
248         err = ErrIncomplete
249         e.EncodeMessageType(First)
250         for _, m := range s {
251                 // Pass only the last error, but allow erroneous or complete messages
252                 // here to allow testing different scenarios.
253                 err = e.EncodeMessage(m)
254         }
255         return err
256 }
257
258 type empty struct{}
259
260 func (empty) Compile(e *Encoder) (err error) { return nil }
261
262 var msgIncomplete = Register(
263         "golang.org/x/text/internal/catmsg.incomplete",
264         func(d *Decoder) bool { return false })
265
266 type incomplete struct{}
267
268 func (incomplete) Compile(e *Encoder) (err error) {
269         e.EncodeMessageType(msgIncomplete)
270         return ErrIncomplete
271 }
272
273 var msgNested = Register(
274         "golang.org/x/text/internal/catmsg.nested",
275         func(d *Decoder) bool {
276                 d.Render(d.DecodeString())
277                 d.ExecuteMessage()
278                 return true
279         })
280
281 type nestedLang struct{ Message }
282
283 func (n nestedLang) Compile(e *Encoder) (err error) {
284         e.EncodeMessageType(msgNested)
285         e.EncodeString(e.Language().String())
286         e.EncodeMessage(n.Message)
287         return nil
288 }
289
290 type errorCompileMsg struct{}
291
292 var errCompileTest = errors.New("catmsg: compile error test")
293
294 func (errorCompileMsg) Compile(e *Encoder) (err error) {
295         return errCompileTest
296 }
297
298 type dictionary struct{}
299
300 var (
301         macros       = dictionary{}
302         dictMessages = map[string]string{
303                 "exists":     compile(String("you betya!")),
304                 "incomplete": compile(incomplete{}),
305         }
306 )
307
308 func (d dictionary) Lookup(key string) (data string, ok bool) {
309         data, ok = dictMessages[key]
310         return
311 }
312
313 func compile(m Message) (data string) {
314         data, _ = Compile(language.Und, macros, m)
315         return data
316 }