golang.org/x/text@v0.14.0/feature/plural/message_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 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"}, // other 39 }, 40 }, { 41 desc: "comparisons", 42 msg: Selectf(1, "%d", 43 "=0", "zero", 44 "=1", "one", 45 "one", "cannot match", // never matches 46 "<5", "<5", // never matches 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 // fractions are always plural in english 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 // fractions are always plural in english 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 // fractions are always plural in english 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 { // Allow testing "arg unavailable" path 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 }