PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/locale/collate/collate_test.go

https://bitbucket.org/shimberger/go-experimental
Go | 422 lines | 383 code | 29 blank | 10 comment | 38 complexity | a3a050569c3091b928e5b87df0108a91 MD5 | raw file
  1. // Copyright 2012 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. package collate_test
  5. import (
  6. "bytes"
  7. "exp/locale/collate"
  8. "testing"
  9. )
  10. type weightsTest struct {
  11. opt opts
  12. in, out ColElems
  13. }
  14. type opts struct {
  15. lev int
  16. alt collate.AlternateHandling
  17. top int
  18. backwards bool
  19. caseLevel bool
  20. }
  21. func (o opts) level() collate.Level {
  22. if o.lev == 0 {
  23. return collate.Quaternary
  24. }
  25. return collate.Level(o.lev - 1)
  26. }
  27. func (o opts) collator() *collate.Collator {
  28. c := &collate.Collator{
  29. Strength: o.level(),
  30. Alternate: o.alt,
  31. Backwards: o.backwards,
  32. CaseLevel: o.caseLevel,
  33. }
  34. collate.SetTop(c, o.top)
  35. return c
  36. }
  37. const (
  38. maxQ = 0x1FFFFF
  39. )
  40. func wpq(p, q int) collate.Weights {
  41. return collate.W(p, defaults.Secondary, defaults.Tertiary, q)
  42. }
  43. func wsq(s, q int) collate.Weights {
  44. return collate.W(0, s, defaults.Tertiary, q)
  45. }
  46. func wq(q int) collate.Weights {
  47. return collate.W(0, 0, 0, q)
  48. }
  49. var zero = w(0, 0, 0, 0)
  50. var processTests = []weightsTest{
  51. // Shifted
  52. { // simple sequence of non-variables
  53. opt: opts{alt: collate.AltShifted, top: 100},
  54. in: ColElems{w(200), w(300), w(400)},
  55. out: ColElems{wpq(200, maxQ), wpq(300, maxQ), wpq(400, maxQ)},
  56. },
  57. { // first is a variable
  58. opt: opts{alt: collate.AltShifted, top: 250},
  59. in: ColElems{w(200), w(300), w(400)},
  60. out: ColElems{wq(200), wpq(300, maxQ), wpq(400, maxQ)},
  61. },
  62. { // all but first are variable
  63. opt: opts{alt: collate.AltShifted, top: 999},
  64. in: ColElems{w(1000), w(200), w(300), w(400)},
  65. out: ColElems{wpq(1000, maxQ), wq(200), wq(300), wq(400)},
  66. },
  67. { // first is a modifier
  68. opt: opts{alt: collate.AltShifted, top: 999},
  69. in: ColElems{w(0, 10), w(1000)},
  70. out: ColElems{wsq(10, maxQ), wpq(1000, maxQ)},
  71. },
  72. { // primary ignorables
  73. opt: opts{alt: collate.AltShifted, top: 250},
  74. in: ColElems{w(200), w(0, 10), w(300), w(0, 15), w(400)},
  75. out: ColElems{wq(200), zero, wpq(300, maxQ), wsq(15, maxQ), wpq(400, maxQ)},
  76. },
  77. { // secondary ignorables
  78. opt: opts{alt: collate.AltShifted, top: 250},
  79. in: ColElems{w(200), w(0, 0, 10), w(300), w(0, 0, 15), w(400)},
  80. out: ColElems{wq(200), zero, wpq(300, maxQ), w(0, 0, 15, maxQ), wpq(400, maxQ)},
  81. },
  82. { // tertiary ignorables, no change
  83. opt: opts{alt: collate.AltShifted, top: 250},
  84. in: ColElems{w(200), zero, w(300), zero, w(400)},
  85. out: ColElems{wq(200), zero, wpq(300, maxQ), zero, wpq(400, maxQ)},
  86. },
  87. // ShiftTrimmed (same as Shifted)
  88. { // simple sequence of non-variables
  89. opt: opts{alt: collate.AltShiftTrimmed, top: 100},
  90. in: ColElems{w(200), w(300), w(400)},
  91. out: ColElems{wpq(200, maxQ), wpq(300, maxQ), wpq(400, maxQ)},
  92. },
  93. { // first is a variable
  94. opt: opts{alt: collate.AltShiftTrimmed, top: 250},
  95. in: ColElems{w(200), w(300), w(400)},
  96. out: ColElems{wq(200), wpq(300, maxQ), wpq(400, maxQ)},
  97. },
  98. { // all but first are variable
  99. opt: opts{alt: collate.AltShiftTrimmed, top: 999},
  100. in: ColElems{w(1000), w(200), w(300), w(400)},
  101. out: ColElems{wpq(1000, maxQ), wq(200), wq(300), wq(400)},
  102. },
  103. { // first is a modifier
  104. opt: opts{alt: collate.AltShiftTrimmed, top: 999},
  105. in: ColElems{w(0, 10), w(1000)},
  106. out: ColElems{wsq(10, maxQ), wpq(1000, maxQ)},
  107. },
  108. { // primary ignorables
  109. opt: opts{alt: collate.AltShiftTrimmed, top: 250},
  110. in: ColElems{w(200), w(0, 10), w(300), w(0, 15), w(400)},
  111. out: ColElems{wq(200), zero, wpq(300, maxQ), wsq(15, maxQ), wpq(400, maxQ)},
  112. },
  113. { // secondary ignorables
  114. opt: opts{alt: collate.AltShiftTrimmed, top: 250},
  115. in: ColElems{w(200), w(0, 0, 10), w(300), w(0, 0, 15), w(400)},
  116. out: ColElems{wq(200), zero, wpq(300, maxQ), w(0, 0, 15, maxQ), wpq(400, maxQ)},
  117. },
  118. { // tertiary ignorables, no change
  119. opt: opts{alt: collate.AltShiftTrimmed, top: 250},
  120. in: ColElems{w(200), zero, w(300), zero, w(400)},
  121. out: ColElems{wq(200), zero, wpq(300, maxQ), zero, wpq(400, maxQ)},
  122. },
  123. // Blanked
  124. { // simple sequence of non-variables
  125. opt: opts{alt: collate.AltBlanked, top: 100},
  126. in: ColElems{w(200), w(300), w(400)},
  127. out: ColElems{w(200), w(300), w(400)},
  128. },
  129. { // first is a variable
  130. opt: opts{alt: collate.AltBlanked, top: 250},
  131. in: ColElems{w(200), w(300), w(400)},
  132. out: ColElems{zero, w(300), w(400)},
  133. },
  134. { // all but first are variable
  135. opt: opts{alt: collate.AltBlanked, top: 999},
  136. in: ColElems{w(1000), w(200), w(300), w(400)},
  137. out: ColElems{w(1000), zero, zero, zero},
  138. },
  139. { // first is a modifier
  140. opt: opts{alt: collate.AltBlanked, top: 999},
  141. in: ColElems{w(0, 10), w(1000)},
  142. out: ColElems{w(0, 10), w(1000)},
  143. },
  144. { // primary ignorables
  145. opt: opts{alt: collate.AltBlanked, top: 250},
  146. in: ColElems{w(200), w(0, 10), w(300), w(0, 15), w(400)},
  147. out: ColElems{zero, zero, w(300), w(0, 15), w(400)},
  148. },
  149. { // secondary ignorables
  150. opt: opts{alt: collate.AltBlanked, top: 250},
  151. in: ColElems{w(200), w(0, 0, 10), w(300), w(0, 0, 15), w(400)},
  152. out: ColElems{zero, zero, w(300), w(0, 0, 15), w(400)},
  153. },
  154. { // tertiary ignorables, no change
  155. opt: opts{alt: collate.AltBlanked, top: 250},
  156. in: ColElems{w(200), zero, w(300), zero, w(400)},
  157. out: ColElems{zero, zero, w(300), zero, w(400)},
  158. },
  159. // Non-ignorable: input is always equal to output.
  160. { // all but first are variable
  161. opt: opts{alt: collate.AltNonIgnorable, top: 999},
  162. in: ColElems{w(1000), w(200), w(300), w(400)},
  163. out: ColElems{w(1000), w(200), w(300), w(400)},
  164. },
  165. { // primary ignorables
  166. opt: opts{alt: collate.AltNonIgnorable, top: 250},
  167. in: ColElems{w(200), w(0, 10), w(300), w(0, 15), w(400)},
  168. out: ColElems{w(200), w(0, 10), w(300), w(0, 15), w(400)},
  169. },
  170. { // secondary ignorables
  171. opt: opts{alt: collate.AltNonIgnorable, top: 250},
  172. in: ColElems{w(200), w(0, 0, 10), w(300), w(0, 0, 15), w(400)},
  173. out: ColElems{w(200), w(0, 0, 10), w(300), w(0, 0, 15), w(400)},
  174. },
  175. { // tertiary ignorables, no change
  176. opt: opts{alt: collate.AltNonIgnorable, top: 250},
  177. in: ColElems{w(200), zero, w(300), zero, w(400)},
  178. out: ColElems{w(200), zero, w(300), zero, w(400)},
  179. },
  180. }
  181. func TestProcessWeights(t *testing.T) {
  182. for i, tt := range processTests {
  183. res := collate.ProcessWeights(tt.opt.alt, tt.opt.top, tt.in)
  184. if len(res) != len(tt.out) {
  185. t.Errorf("%d: len(ws) was %d; want %d (%v should be %v)", i, len(res), len(tt.out), res, tt.out)
  186. continue
  187. }
  188. for j, w := range res {
  189. if w != tt.out[j] {
  190. t.Errorf("%d: Weights %d was %v; want %v", i, j, w, tt.out[j])
  191. }
  192. }
  193. }
  194. }
  195. type keyFromElemTest struct {
  196. opt opts
  197. in ColElems
  198. out []byte
  199. }
  200. var defS = byte(defaults.Secondary)
  201. var defT = byte(defaults.Tertiary)
  202. const sep = 0 // separator byte
  203. var keyFromElemTests = []keyFromElemTest{
  204. { // simple primary and secondary weights.
  205. opts{},
  206. ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
  207. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  208. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  209. sep, sep, defT, defT, defT, defT, // tertiary
  210. sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary
  211. },
  212. },
  213. { // same as first, but with zero element that need to be removed
  214. opts{},
  215. ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
  216. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  217. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  218. sep, sep, defT, defT, defT, defT, // tertiary
  219. sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary
  220. },
  221. },
  222. { // same as first, with large primary values
  223. opts{},
  224. ColElems{w(0x200), w(0x8000), w(0, 0x30), w(0x12345)},
  225. []byte{0x2, 0, 0x80, 0x80, 0x00, 0x81, 0x23, 0x45, // primary
  226. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  227. sep, sep, defT, defT, defT, defT, // tertiary
  228. sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary
  229. },
  230. },
  231. { // same as first, but with the secondary level backwards
  232. opts{backwards: true},
  233. ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
  234. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  235. sep, sep, 0, defS, 0, 0x30, 0, defS, 0, defS, // secondary
  236. sep, sep, defT, defT, defT, defT, // tertiary
  237. sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary
  238. },
  239. },
  240. { // same as first, ignoring quaternary level
  241. opts{lev: 3},
  242. ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
  243. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  244. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  245. sep, sep, defT, defT, defT, defT, // tertiary
  246. },
  247. },
  248. { // same as first, ignoring tertiary level
  249. opts{lev: 2},
  250. ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
  251. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  252. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  253. },
  254. },
  255. { // same as first, ignoring secondary level
  256. opts{lev: 1},
  257. ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
  258. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00},
  259. },
  260. { // simple primary and secondary weights.
  261. opts{alt: collate.AltShiftTrimmed, top: 0x250},
  262. ColElems{w(0x300), w(0x200), w(0x7FFF), w(0, 0x30), w(0x800)},
  263. []byte{0x3, 0, 0x7F, 0xFF, 0x8, 0x00, // primary
  264. sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
  265. sep, sep, defT, defT, defT, defT, // tertiary
  266. sep, 0xFF, 0x2, 0, // quaternary
  267. },
  268. },
  269. { // as first, primary with case level enabled
  270. opts{lev: 1, caseLevel: true},
  271. ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
  272. []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
  273. sep, sep, // secondary
  274. sep, sep, defT, defT, defT, defT, // tertiary
  275. },
  276. },
  277. }
  278. func TestKeyFromElems(t *testing.T) {
  279. buf := collate.Buffer{}
  280. for i, tt := range keyFromElemTests {
  281. buf.ResetKeys()
  282. ws := collate.ProcessWeights(tt.opt.alt, tt.opt.top, tt.in)
  283. res := collate.KeyFromElems(tt.opt.collator(), &buf, ws)
  284. if len(res) != len(tt.out) {
  285. t.Errorf("%d: len(ws) was %d; want %d (%X should be %X)", i, len(res), len(tt.out), res, tt.out)
  286. }
  287. n := len(res)
  288. if len(tt.out) < n {
  289. n = len(tt.out)
  290. }
  291. for j, c := range res[:n] {
  292. if c != tt.out[j] {
  293. t.Errorf("%d: byte %d was %X; want %X", i, j, c, tt.out[j])
  294. }
  295. }
  296. }
  297. }
  298. func TestGetColElems(t *testing.T) {
  299. for i, tt := range appendNextTests {
  300. c, err := makeTable(tt.in)
  301. if err != nil {
  302. // error is reported in TestAppendNext
  303. continue
  304. }
  305. buf := collate.Buffer{}
  306. // Create one large test per table
  307. str := make([]byte, 0, 4000)
  308. out := ColElems{}
  309. for len(str) < 3000 {
  310. for _, chk := range tt.chk {
  311. str = append(str, chk.in[:chk.n]...)
  312. out = append(out, chk.out...)
  313. }
  314. }
  315. for j, chk := range append(tt.chk, check{string(str), len(str), out}) {
  316. ws := collate.GetColElems(c, &buf, []byte(chk.in)[:chk.n])
  317. if len(ws) != len(chk.out) {
  318. t.Errorf("%d:%d: len(ws) was %d; want %d", i, j, len(ws), len(chk.out))
  319. continue
  320. }
  321. cnt := 0
  322. for k, w := range ws {
  323. if w != chk.out[k] {
  324. t.Errorf("%d:%d: Weights %d was %v; want %v", i, j, k, w, chk.out[k])
  325. cnt++
  326. }
  327. if cnt > 10 {
  328. break
  329. }
  330. }
  331. }
  332. }
  333. }
  334. type keyTest struct {
  335. in string
  336. out []byte
  337. }
  338. var keyTests = []keyTest{
  339. {"abc",
  340. []byte{0, 100, 0, 200, 1, 44, 0, 0, 0, 32, 0, 32, 0, 32, 0, 0, 2, 2, 2, 0, 255, 255, 255},
  341. },
  342. {"a\u0301",
  343. []byte{0, 102, 0, 0, 0, 32, 0, 0, 2, 0, 255},
  344. },
  345. {"aaaaa",
  346. []byte{0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 0,
  347. 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 0,
  348. 2, 2, 2, 2, 2, 0,
  349. 255, 255, 255, 255, 255,
  350. },
  351. },
  352. }
  353. func TestKey(t *testing.T) {
  354. c, _ := makeTable(appendNextTests[4].in)
  355. buf := collate.Buffer{}
  356. keys1 := [][]byte{}
  357. keys2 := [][]byte{}
  358. for _, tt := range keyTests {
  359. keys1 = append(keys1, c.Key(&buf, []byte(tt.in)))
  360. keys2 = append(keys2, c.KeyFromString(&buf, tt.in))
  361. }
  362. // Separate generation from testing to ensure buffers are not overwritten.
  363. for i, tt := range keyTests {
  364. if bytes.Compare(keys1[i], tt.out) != 0 {
  365. t.Errorf("%d: Key(%q) = %d; want %d", i, tt.in, keys1[i], tt.out)
  366. }
  367. if bytes.Compare(keys2[i], tt.out) != 0 {
  368. t.Errorf("%d: KeyFromString(%q) = %d; want %d", i, tt.in, keys2[i], tt.out)
  369. }
  370. }
  371. }
  372. type compareTest struct {
  373. a, b string
  374. res int // comparison result
  375. }
  376. var compareTests = []compareTest{
  377. {"a\u0301", "a", 1},
  378. {"a", "a\u0301", -1},
  379. {"a\u0301", "a\u0301", 0},
  380. {"a", "a", 0},
  381. }
  382. func TestCompare(t *testing.T) {
  383. c, _ := makeTable(appendNextTests[4].in)
  384. buf := collate.Buffer{}
  385. for i, tt := range compareTests {
  386. if res := c.Compare(&buf, []byte(tt.a), []byte(tt.b)); res != tt.res {
  387. t.Errorf("%d: Compare(%q, %q) == %d; want %d", i, tt.a, tt.b, res, tt.res)
  388. }
  389. if res := c.CompareString(&buf, tt.a, tt.b); res != tt.res {
  390. t.Errorf("%d: CompareString(%q, %q) == %d; want %d", i, tt.a, tt.b, res, tt.res)
  391. }
  392. }
  393. }