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
5package colltab
6
7import (
8	"fmt"
9	"testing"
10	"unicode"
11)
12
13func (e Elem) String() string {
14	q := ""
15	if v := e.Quaternary(); v == MaxQuaternary {
16		q = "max"
17	} else {
18		q = fmt.Sprint(v)
19	}
20	return fmt.Sprintf("[%d, %d, %d, %s]",
21		e.Primary(),
22		e.Secondary(),
23		e.Tertiary(),
24		q)
25}
26
27type ceTest struct {
28	f   func(inout []int) (Elem, ceType)
29	arg []int
30}
31
32func makeCE(weights []int) Elem {
33	ce, _ := MakeElem(weights[0], weights[1], weights[2], uint8(weights[3]))
34	return ce
35}
36
37var defaultValues = []int{0, defaultSecondary, defaultTertiary, 0}
38
39func e(w ...int) Elem {
40	return makeCE(append(w, defaultValues[len(w):]...))
41}
42
43func makeContractIndex(index, n, offset int) Elem {
44	const (
45		contractID            = 0xC0000000
46		maxNBits              = 4
47		maxTrieIndexBits      = 12
48		maxContractOffsetBits = 13
49	)
50	ce := Elem(contractID)
51	ce += Elem(offset << (maxNBits + maxTrieIndexBits))
52	ce += Elem(index << maxNBits)
53	ce += Elem(n)
54	return ce
55}
56
57func makeExpandIndex(index int) Elem {
58	const expandID = 0xE0000000
59	return expandID + Elem(index)
60}
61
62func makeDecompose(t1, t2 int) Elem {
63	const decompID = 0xF0000000
64	return Elem(t2<<8+t1) + decompID
65}
66
67func normalCE(inout []int) (ce Elem, t ceType) {
68	ce = makeCE(inout)
69	inout[0] = ce.Primary()
70	inout[1] = ce.Secondary()
71	inout[2] = int(ce.Tertiary())
72	inout[3] = int(ce.CCC())
73	return ce, ceNormal
74}
75
76func expandCE(inout []int) (ce Elem, t ceType) {
77	ce = makeExpandIndex(inout[0])
78	inout[0] = splitExpandIndex(ce)
79	return ce, ceExpansionIndex
80}
81
82func contractCE(inout []int) (ce Elem, t ceType) {
83	ce = makeContractIndex(inout[0], inout[1], inout[2])
84	i, n, o := splitContractIndex(ce)
85	inout[0], inout[1], inout[2] = i, n, o
86	return ce, ceContractionIndex
87}
88
89func decompCE(inout []int) (ce Elem, t ceType) {
90	ce = makeDecompose(inout[0], inout[1])
91	t1, t2 := splitDecompose(ce)
92	inout[0], inout[1] = int(t1), int(t2)
93	return ce, ceDecompose
94}
95
96var ceTests = []ceTest{
97	{normalCE, []int{0, 0, 0, 0}},
98	{normalCE, []int{0, 30, 3, 0}},
99	{normalCE, []int{0, 30, 3, 0xFF}},
100	{normalCE, []int{100, defaultSecondary, defaultTertiary, 0}},
101	{normalCE, []int{100, defaultSecondary, defaultTertiary, 0xFF}},
102	{normalCE, []int{100, defaultSecondary, 3, 0}},
103	{normalCE, []int{0x123, defaultSecondary, 8, 0xFF}},
104
105	{contractCE, []int{0, 0, 0}},
106	{contractCE, []int{1, 1, 1}},
107	{contractCE, []int{1, (1 << maxNBits) - 1, 1}},
108	{contractCE, []int{(1 << maxTrieIndexBits) - 1, 1, 1}},
109	{contractCE, []int{1, 1, (1 << maxContractOffsetBits) - 1}},
110
111	{expandCE, []int{0}},
112	{expandCE, []int{5}},
113	{expandCE, []int{(1 << maxExpandIndexBits) - 1}},
114
115	{decompCE, []int{0, 0}},
116	{decompCE, []int{1, 1}},
117	{decompCE, []int{0x1F, 0x1F}},
118}
119
120func TestColElem(t *testing.T) {
121	for i, tt := range ceTests {
122		inout := make([]int, len(tt.arg))
123		copy(inout, tt.arg)
124		ce, typ := tt.f(inout)
125		if ce.ctype() != typ {
126			t.Errorf("%d: type is %d; want %d (ColElem: %X)", i, ce.ctype(), typ, ce)
127		}
128		for j, a := range tt.arg {
129			if inout[j] != a {
130				t.Errorf("%d: argument %d is %X; want %X (ColElem: %X)", i, j, inout[j], a, ce)
131			}
132		}
133	}
134}
135
136type implicitTest struct {
137	r rune
138	p int
139}
140
141var implicitTests = []implicitTest{
142	{0x33FF, 0x533FF},
143	{0x3400, 0x23400},
144	{0x4DC0, 0x54DC0},
145	{0x4DFF, 0x54DFF},
146	{0x4E00, 0x14E00},
147	{0x9FCB, 0x19FCB},
148	{0xA000, 0x5A000},
149	{0xF8FF, 0x5F8FF},
150	{0xF900, 0x1F900},
151	{0xFA23, 0x1FA23},
152	{0xFAD9, 0x1FAD9},
153	{0xFB00, 0x5FB00},
154	{0x20000, 0x40000},
155	{0x2B81C, 0x4B81C},
156	{unicode.MaxRune, 0x15FFFF}, // maximum primary value
157}
158
159func TestImplicit(t *testing.T) {
160	for _, tt := range implicitTests {
161		if p := implicitPrimary(tt.r); p != tt.p {
162			t.Errorf("%U: was %X; want %X", tt.r, p, tt.p)
163		}
164	}
165}
166
167func TestUpdateTertiary(t *testing.T) {
168	tests := []struct {
169		in, out Elem
170		t       uint8
171	}{
172		{0x4000FE20, 0x0000FE8A, 0x0A},
173		{0x4000FE21, 0x0000FEAA, 0x0A},
174		{0x0000FE8B, 0x0000FE83, 0x03},
175		{0x82FF0188, 0x9BFF0188, 0x1B},
176		{0xAFF0CC02, 0xAFF0CC1B, 0x1B},
177	}
178	for i, tt := range tests {
179		if out := tt.in.updateTertiary(tt.t); out != tt.out {
180			t.Errorf("%d: was %X; want %X", i, out, tt.out)
181		}
182	}
183}
184