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
5package colltab
6
7import (
8	"reflect"
9	"strings"
10	"testing"
11
12	"golang.org/x/text/internal/testtext"
13)
14
15const (
16	digSec  = defaultSecondary
17	digTert = defaultTertiary
18)
19
20var tPlus3 = e(0, 50, digTert+3)
21
22// numWeighter is a testWeighter used for testing numericWeighter.
23var numWeighter = testWeighter{
24	"0": p(100),
25	"0": []Elem{e(100, digSec, digTert+1)}, // U+FF10 FULLWIDTH DIGIT ZERO
26	"₀": []Elem{e(100, digSec, digTert+5)}, // U+2080 SUBSCRIPT ZERO
27
28	"1": p(101),
29	// Allow non-primary collation elements to be inserted.
30	"١": append(p(101), tPlus3), // U+0661 ARABIC-INDIC DIGIT ONE
31	// Allow varying tertiary weight if the number is Nd.
32	"1": []Elem{e(101, digSec, digTert+1)}, // U+FF11 FULLWIDTH DIGIT ONE
33	"2": p(102),
34	// Allow non-primary collation elements to be inserted.
35	"٢": append(p(102), tPlus3), // U+0662 ARABIC-INDIC DIGIT TWO
36	// Varying tertiary weights should be ignored.
37	"2": []Elem{e(102, digSec, digTert+3)}, // U+FF12 FULLWIDTH DIGIT TWO
38	"3": p(103),
39	"4": p(104),
40	"5": p(105),
41	"6": p(106),
42	"7": p(107),
43	// Weights must be strictly monotonically increasing, but do not need to be
44	// consecutive.
45	"8": p(118),
46	"9": p(119),
47	// Allow non-primary collation elements to be inserted.
48	"٩": append(p(119), tPlus3), // U+0669 ARABIC-INDIC DIGIT NINE
49	// Varying tertiary weights should be ignored.
50	"9": []Elem{e(119, digSec, digTert+1)}, // U+FF19 FULLWIDTH DIGIT NINE
51	"₉": []Elem{e(119, digSec, digTert+5)}, // U+2089 SUBSCRIPT NINE
52
53	"a": p(5),
54	"b": p(6),
55	"c": p(8, 2),
56
57	"klm": p(99),
58
59	"nop": p(121),
60
61	"x": p(200),
62	"y": p(201),
63}
64
65func p(w ...int) (elems []Elem) {
66	for _, x := range w {
67		e, _ := MakeElem(x, digSec, digTert, 0)
68		elems = append(elems, e)
69	}
70	return elems
71}
72
73func TestNumericAppendNext(t *testing.T) {
74	for _, tt := range []struct {
75		in string
76		w  []Elem
77	}{
78		{"a", p(5)},
79		{"klm", p(99)},
80		{"aa", p(5, 5)},
81		{"1", p(120, 1, 101)},
82		{"0", p(120, 0)},
83		{"01", p(120, 1, 101)},
84		{"0001", p(120, 1, 101)},
85		{"10", p(120, 2, 101, 100)},
86		{"99", p(120, 2, 119, 119)},
87		{"9999", p(120, 4, 119, 119, 119, 119)},
88		{"1a", p(120, 1, 101, 5)},
89		{"0b", p(120, 0, 6)},
90		{"01c", p(120, 1, 101, 8, 2)},
91		{"10x", p(120, 2, 101, 100, 200)},
92		{"99y", p(120, 2, 119, 119, 201)},
93		{"9999nop", p(120, 4, 119, 119, 119, 119, 121)},
94
95		// Allow follow-up collation elements if they have a zero non-primary.
96		{"١٢٩", []Elem{e(120), e(3), e(101), tPlus3, e(102), tPlus3, e(119), tPlus3}},
97		{
98			"129",
99			[]Elem{
100				e(120), e(3),
101				e(101, digSec, digTert+1),
102				e(102, digSec, digTert+3),
103				e(119, digSec, digTert+1),
104			},
105		},
106
107		// Ensure AppendNext* adds to the given buffer.
108		{"a10", p(5, 120, 2, 101, 100)},
109	} {
110		nw := NewNumericWeighter(numWeighter)
111
112		b := []byte(tt.in)
113		got := []Elem(nil)
114		for n, sz := 0, 0; n < len(b); {
115			got, sz = nw.AppendNext(got, b[n:])
116			n += sz
117		}
118		if !reflect.DeepEqual(got, tt.w) {
119			t.Errorf("AppendNext(%q) =\n%v; want\n%v", tt.in, got, tt.w)
120		}
121
122		got = nil
123		for n, sz := 0, 0; n < len(tt.in); {
124			got, sz = nw.AppendNextString(got, tt.in[n:])
125			n += sz
126		}
127		if !reflect.DeepEqual(got, tt.w) {
128			t.Errorf("AppendNextString(%q) =\n%v; want\n%v", tt.in, got, tt.w)
129		}
130	}
131}
132
133func TestNumericOverflow(t *testing.T) {
134	manyDigits := strings.Repeat("9", maxDigits+1) + "a"
135
136	nw := NewNumericWeighter(numWeighter)
137
138	got, n := nw.AppendNextString(nil, manyDigits)
139
140	if n != maxDigits {
141		t.Errorf("n: got %d; want %d", n, maxDigits)
142	}
143
144	if got[1].Primary() != maxDigits {
145		t.Errorf("primary(e[1]): got %d; want %d", n, maxDigits)
146	}
147}
148
149func TestNumericWeighterAlloc(t *testing.T) {
150	buf := make([]Elem, 100)
151	w := NewNumericWeighter(numWeighter)
152	s := "1234567890a"
153
154	nNormal := testtext.AllocsPerRun(3, func() { numWeighter.AppendNextString(buf, s) })
155	nNumeric := testtext.AllocsPerRun(3, func() { w.AppendNextString(buf, s) })
156	if n := nNumeric - nNormal; n > 0 {
157		t.Errorf("got %f; want 0", n)
158	}
159}
160