github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/text/cases/context_test.go (about) 1 // Copyright 2014 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 cases 6 7 import ( 8 "strings" 9 "testing" 10 "unicode" 11 12 "golang.org/x/text/language" 13 "golang.org/x/text/transform" 14 "golang.org/x/text/unicode/norm" 15 "golang.org/x/text/unicode/rangetable" 16 ) 17 18 // The following definitions are taken directly from Chapter 3 of The Unicode 19 // Standard. 20 21 func propCased(r rune) bool { 22 return propLower(r) || propUpper(r) || unicode.IsTitle(r) 23 } 24 25 func propLower(r rune) bool { 26 return unicode.IsLower(r) || unicode.Is(unicode.Other_Lowercase, r) 27 } 28 29 func propUpper(r rune) bool { 30 return unicode.IsUpper(r) || unicode.Is(unicode.Other_Uppercase, r) 31 } 32 33 func propIgnore(r rune) bool { 34 if unicode.In(r, unicode.Mn, unicode.Me, unicode.Cf, unicode.Lm, unicode.Sk) { 35 return true 36 } 37 return caseIgnorable[r] 38 } 39 40 func hasBreakProp(r rune) bool { 41 // binary search over ranges 42 lo := 0 43 hi := len(breakProp) 44 for lo < hi { 45 m := lo + (hi-lo)/2 46 bp := &breakProp[m] 47 if bp.lo <= r && r <= bp.hi { 48 return true 49 } 50 if r < bp.lo { 51 hi = m 52 } else { 53 lo = m + 1 54 } 55 } 56 return false 57 } 58 59 func contextFromRune(r rune) *context { 60 c := context{dst: make([]byte, 128), src: []byte(string(r)), atEOF: true} 61 c.next() 62 return &c 63 } 64 65 func TestCaseProperties(t *testing.T) { 66 assigned := rangetable.Assigned(UnicodeVersion) 67 coreVersion := rangetable.Assigned(unicode.Version) 68 for r := rune(0); r <= lastRuneForTesting; r++ { 69 if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) { 70 continue 71 } 72 c := contextFromRune(r) 73 if got, want := c.info.isCaseIgnorable(), propIgnore(r); got != want { 74 t.Errorf("caseIgnorable(%U): got %v; want %v (%x)", r, got, want, c.info) 75 } 76 // New letters may change case types, but existing case pairings should 77 // not change. See Case Pair Stability in 78 // http://unicode.org/policies/stability_policy.html. 79 if rf := unicode.SimpleFold(r); rf != r && unicode.In(rf, assigned) { 80 if got, want := c.info.isCased(), propCased(r); got != want { 81 t.Errorf("cased(%U): got %v; want %v (%x)", r, got, want, c.info) 82 } 83 if got, want := c.caseType() == cUpper, propUpper(r); got != want { 84 t.Errorf("upper(%U): got %v; want %v (%x)", r, got, want, c.info) 85 } 86 if got, want := c.caseType() == cLower, propLower(r); got != want { 87 t.Errorf("lower(%U): got %v; want %v (%x)", r, got, want, c.info) 88 } 89 } 90 if got, want := c.info.isBreak(), hasBreakProp(r); got != want { 91 t.Errorf("isBreak(%U): got %v; want %v (%x)", r, got, want, c.info) 92 } 93 } 94 // TODO: get title case from unicode file. 95 } 96 97 func TestMapping(t *testing.T) { 98 assigned := rangetable.Assigned(UnicodeVersion) 99 coreVersion := rangetable.Assigned(unicode.Version) 100 apply := func(r rune, f func(c *context) bool) string { 101 c := contextFromRune(r) 102 f(c) 103 return string(c.dst[:c.pDst]) 104 } 105 106 for r, tt := range special { 107 if got, want := apply(r, lower), tt.toLower; got != want { 108 t.Errorf("lowerSpecial:(%U): got %+q; want %+q", r, got, want) 109 } 110 if got, want := apply(r, title), tt.toTitle; got != want { 111 t.Errorf("titleSpecial:(%U): got %+q; want %+q", r, got, want) 112 } 113 if got, want := apply(r, upper), tt.toUpper; got != want { 114 t.Errorf("upperSpecial:(%U): got %+q; want %+q", r, got, want) 115 } 116 } 117 118 for r := rune(0); r <= lastRuneForTesting; r++ { 119 if !unicode.In(r, assigned) || !unicode.In(r, coreVersion) { 120 continue 121 } 122 if rf := unicode.SimpleFold(r); rf == r || !unicode.In(rf, assigned) { 123 continue 124 } 125 if _, ok := special[r]; ok { 126 continue 127 } 128 want := string(unicode.ToLower(r)) 129 if got := apply(r, lower); got != want { 130 t.Errorf("lower:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) 131 } 132 133 want = string(unicode.ToUpper(r)) 134 if got := apply(r, upper); got != want { 135 t.Errorf("upper:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) 136 } 137 138 want = string(unicode.ToTitle(r)) 139 if got := apply(r, title); got != want { 140 t.Errorf("title:%q (%U): got %q %U; want %q %U", r, r, got, []rune(got), want, []rune(want)) 141 } 142 } 143 } 144 145 func TestCCC(t *testing.T) { 146 assigned := rangetable.Assigned(UnicodeVersion) 147 normVersion := rangetable.Assigned(norm.Version) 148 for r := rune(0); r <= lastRuneForTesting; r++ { 149 if !unicode.In(r, assigned) || !unicode.In(r, normVersion) { 150 continue 151 } 152 c := contextFromRune(r) 153 154 p := norm.NFC.PropertiesString(string(r)) 155 want := cccOther 156 switch p.CCC() { 157 case 0: 158 want = cccZero 159 case above: 160 want = cccAbove 161 } 162 if got := c.info.cccType(); got != want { 163 t.Errorf("%U: got %x; want %x", r, got, want) 164 } 165 } 166 } 167 168 func TestWordBreaks(t *testing.T) { 169 for i, tt := range breakTest { 170 parts := strings.Split(tt, "|") 171 want := "" 172 for _, s := range parts { 173 want += Title(language.Und).String(s) 174 } 175 src := strings.Join(parts, "") 176 got := Title(language.Und).String(src) 177 if got != want { 178 t.Errorf("%d: title(%q) = %q; want %q", i, src, got, want) 179 } 180 } 181 } 182 183 func TestContext(t *testing.T) { 184 tests := []struct { 185 desc string 186 dstSize int 187 atEOF bool 188 src string 189 out string 190 nSrc int 191 err error 192 ops string 193 prefixArg string 194 prefixWant bool 195 }{{ 196 desc: "next: past end, atEOF, no checkpoint", 197 dstSize: 10, 198 atEOF: true, 199 src: "12", 200 out: "", 201 nSrc: 2, 202 ops: "next;next;next", 203 // Test that calling prefix with a non-empty argument when the buffer 204 // is depleted returns false. 205 prefixArg: "x", 206 prefixWant: false, 207 }, { 208 desc: "next: not at end, atEOF, no checkpoint", 209 dstSize: 10, 210 atEOF: false, 211 src: "12", 212 out: "", 213 nSrc: 0, 214 err: transform.ErrShortSrc, 215 ops: "next;next", 216 prefixArg: "", 217 prefixWant: true, 218 }, { 219 desc: "next: past end, !atEOF, no checkpoint", 220 dstSize: 10, 221 atEOF: false, 222 src: "12", 223 out: "", 224 nSrc: 0, 225 err: transform.ErrShortSrc, 226 ops: "next;next;next", 227 prefixArg: "", 228 prefixWant: true, 229 }, { 230 desc: "next: past end, !atEOF, checkpoint", 231 dstSize: 10, 232 atEOF: false, 233 src: "12", 234 out: "", 235 nSrc: 2, 236 ops: "next;next;checkpoint;next", 237 prefixArg: "", 238 prefixWant: true, 239 }, { 240 desc: "copy: exact count, atEOF, no checkpoint", 241 dstSize: 2, 242 atEOF: true, 243 src: "12", 244 out: "12", 245 nSrc: 2, 246 ops: "next;copy;next;copy;next", 247 prefixArg: "", 248 prefixWant: true, 249 }, { 250 desc: "copy: past end, !atEOF, no checkpoint", 251 dstSize: 2, 252 atEOF: false, 253 src: "12", 254 out: "", 255 nSrc: 0, 256 err: transform.ErrShortSrc, 257 ops: "next;copy;next;copy;next", 258 prefixArg: "", 259 prefixWant: true, 260 }, { 261 desc: "copy: past end, !atEOF, checkpoint", 262 dstSize: 2, 263 atEOF: false, 264 src: "12", 265 out: "12", 266 nSrc: 2, 267 ops: "next;copy;next;copy;checkpoint;next", 268 prefixArg: "", 269 prefixWant: true, 270 }, { 271 desc: "copy: short dst", 272 dstSize: 1, 273 atEOF: false, 274 src: "12", 275 out: "", 276 nSrc: 0, 277 err: transform.ErrShortDst, 278 ops: "next;copy;next;copy;checkpoint;next", 279 prefixArg: "12", 280 prefixWant: false, 281 }, { 282 desc: "copy: short dst, checkpointed", 283 dstSize: 1, 284 atEOF: false, 285 src: "12", 286 out: "1", 287 nSrc: 1, 288 err: transform.ErrShortDst, 289 ops: "next;copy;checkpoint;next;copy;next", 290 prefixArg: "", 291 prefixWant: true, 292 }, { 293 desc: "writeString: simple", 294 dstSize: 3, 295 atEOF: true, 296 src: "1", 297 out: "1ab", 298 nSrc: 1, 299 ops: "next;copy;writeab;next", 300 prefixArg: "", 301 prefixWant: true, 302 }, { 303 desc: "writeString: short dst", 304 dstSize: 2, 305 atEOF: true, 306 src: "12", 307 out: "", 308 nSrc: 0, 309 err: transform.ErrShortDst, 310 ops: "next;copy;writeab;next", 311 prefixArg: "2", 312 prefixWant: true, 313 }, { 314 desc: "writeString: simple", 315 dstSize: 3, 316 atEOF: true, 317 src: "12", 318 out: "1ab", 319 nSrc: 2, 320 ops: "next;copy;next;writeab;next", 321 prefixArg: "", 322 prefixWant: true, 323 }, { 324 desc: "writeString: short dst", 325 dstSize: 2, 326 atEOF: true, 327 src: "12", 328 out: "", 329 nSrc: 0, 330 err: transform.ErrShortDst, 331 ops: "next;copy;next;writeab;next", 332 prefixArg: "1", 333 prefixWant: false, 334 }, { 335 desc: "prefix", 336 dstSize: 2, 337 atEOF: true, 338 src: "12", 339 out: "", 340 nSrc: 0, 341 // Context will assign an ErrShortSrc if the input wasn't exhausted. 342 err: transform.ErrShortSrc, 343 prefixArg: "12", 344 prefixWant: true, 345 }} 346 for _, tt := range tests { 347 c := context{dst: make([]byte, tt.dstSize), src: []byte(tt.src), atEOF: tt.atEOF} 348 349 for _, op := range strings.Split(tt.ops, ";") { 350 switch op { 351 case "next": 352 c.next() 353 case "checkpoint": 354 c.checkpoint() 355 case "writeab": 356 c.writeString("ab") 357 case "copy": 358 c.copy() 359 case "": 360 default: 361 t.Fatalf("unknown op %q", op) 362 } 363 } 364 if got := c.hasPrefix(tt.prefixArg); got != tt.prefixWant { 365 t.Errorf("%s:\nprefix was %v; want %v", tt.desc, got, tt.prefixWant) 366 } 367 nDst, nSrc, err := c.ret() 368 if err != tt.err { 369 t.Errorf("%s:\nerror was %v; want %v", tt.desc, err, tt.err) 370 } 371 if out := string(c.dst[:nDst]); out != tt.out { 372 t.Errorf("%s:\nout was %q; want %q", tt.desc, out, tt.out) 373 } 374 if nSrc != tt.nSrc { 375 t.Errorf("%s:\nnSrc was %d; want %d", tt.desc, nSrc, tt.nSrc) 376 } 377 } 378 }