1// Copyright 2015 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 number
6
7import (
8	"reflect"
9	"testing"
10	"unsafe"
11)
12
13var testCases = []struct {
14	pat  string
15	want *Pattern
16}{{
17	"#",
18	&Pattern{
19		FormatWidth: 1,
20		// TODO: Should MinIntegerDigits be 1?
21	},
22}, {
23	"0",
24	&Pattern{
25		FormatWidth:      1,
26		MinIntegerDigits: 1,
27	},
28}, {
29	"+0",
30	&Pattern{
31		Affix:            "\x01+\x00",
32		FormatWidth:      2,
33		MinIntegerDigits: 1,
34	},
35}, {
36	"0+",
37	&Pattern{
38		Affix:            "\x00\x01+",
39		FormatWidth:      2,
40		MinIntegerDigits: 1,
41	},
42}, {
43	"0000",
44	&Pattern{
45		FormatWidth:      4,
46		MinIntegerDigits: 4,
47	},
48}, {
49	".#",
50	&Pattern{
51		FormatWidth:       2,
52		MaxFractionDigits: 1,
53	},
54}, {
55	"#0.###",
56	&Pattern{
57		FormatWidth:       6,
58		MinIntegerDigits:  1,
59		MaxFractionDigits: 3,
60	},
61}, {
62	"#0.######",
63	&Pattern{
64		FormatWidth:       9,
65		MinIntegerDigits:  1,
66		MaxFractionDigits: 6,
67	},
68}, {
69	"#,0",
70	&Pattern{
71		FormatWidth:      3,
72		GroupingSize:     [2]uint8{1, 0},
73		MinIntegerDigits: 1,
74	},
75}, {
76	"#,0.00",
77	&Pattern{
78		FormatWidth:       6,
79		GroupingSize:      [2]uint8{1, 0},
80		MinIntegerDigits:  1,
81		MinFractionDigits: 2,
82		MaxFractionDigits: 2,
83	},
84}, {
85	"#,##0.###",
86	&Pattern{
87		FormatWidth:       9,
88		GroupingSize:      [2]uint8{3, 0},
89		MinIntegerDigits:  1,
90		MaxFractionDigits: 3,
91	},
92}, {
93	"#,##,##0.###",
94	&Pattern{
95		FormatWidth:       12,
96		GroupingSize:      [2]uint8{3, 2},
97		MinIntegerDigits:  1,
98		MaxFractionDigits: 3,
99	},
100}, {
101	// Ignore additional separators.
102	"#,####,##,##0.###",
103	&Pattern{
104		FormatWidth:       17,
105		GroupingSize:      [2]uint8{3, 2},
106		MinIntegerDigits:  1,
107		MaxFractionDigits: 3,
108	},
109}, {
110	"#E0",
111	&Pattern{
112		FormatWidth:       3,
113		MaxIntegerDigits:  1,
114		MinExponentDigits: 1,
115	},
116}, {
117	// At least one exponent digit is required. As long as this is true, one can
118	// determine that scientific rendering is needed if MinExponentDigits > 0.
119	"#E#",
120	nil,
121}, {
122	"0E0",
123	&Pattern{
124		FormatWidth:       3,
125		MinIntegerDigits:  1,
126		MinExponentDigits: 1,
127	},
128}, {
129	"##00.0#E0",
130	&Pattern{
131		FormatWidth:       9,
132		MinIntegerDigits:  2,
133		MaxIntegerDigits:  4,
134		MinFractionDigits: 1,
135		MaxFractionDigits: 2,
136		MinExponentDigits: 1,
137	},
138}, {
139	"#00.0E+0",
140	&Pattern{
141		FormatWidth:       8,
142		Flags:             AlwaysExpSign,
143		MinIntegerDigits:  2,
144		MaxIntegerDigits:  3,
145		MinFractionDigits: 1,
146		MaxFractionDigits: 1,
147		MinExponentDigits: 1,
148	},
149}, {
150	"0.0E++0",
151	nil,
152}, {
153	"#0E+",
154	nil,
155}, {
156	// significant digits
157	"@",
158	&Pattern{
159		FormatWidth:          1,
160		MinSignificantDigits: 1,
161		MaxSignificantDigits: 1,
162	},
163}, {
164	// significant digits
165	"@@@@",
166	&Pattern{
167		FormatWidth:          4,
168		MinSignificantDigits: 4,
169		MaxSignificantDigits: 4,
170	},
171}, {
172	"@###",
173	&Pattern{
174		FormatWidth:          4,
175		MinSignificantDigits: 1,
176		MaxSignificantDigits: 4,
177	},
178}, {
179	// Exponents in significant digits mode gets normalized.
180	"@@E0",
181	&Pattern{
182		FormatWidth:       4,
183		MinIntegerDigits:  1,
184		MaxIntegerDigits:  1,
185		MinFractionDigits: 1,
186		MaxFractionDigits: 1,
187		MinExponentDigits: 1,
188	},
189}, {
190	"@###E00",
191	&Pattern{
192		FormatWidth:       7,
193		MinIntegerDigits:  1,
194		MaxIntegerDigits:  1,
195		MinFractionDigits: 0,
196		MaxFractionDigits: 3,
197		MinExponentDigits: 2,
198	},
199}, {
200	// The significant digits mode does not allow fractions.
201	"@###.#E0",
202	nil,
203}, {
204	//alternative negative pattern
205	"#0.###;(#0.###)",
206	&Pattern{
207		Affix:             "\x00\x00\x01(\x01)",
208		NegOffset:         2,
209		FormatWidth:       6,
210		MinIntegerDigits:  1,
211		MaxFractionDigits: 3,
212	},
213}, {
214	// Rounding increment
215	"1.05",
216	&Pattern{
217		RoundIncrement:    105,
218		FormatWidth:       4,
219		MinIntegerDigits:  1,
220		MinFractionDigits: 2,
221		MaxFractionDigits: 2,
222	},
223}, {
224	// Rounding increment with grouping
225	"1,05",
226	&Pattern{
227		RoundIncrement:    105,
228		FormatWidth:       4,
229		GroupingSize:      [2]uint8{2, 0},
230		MinIntegerDigits:  3,
231		MinFractionDigits: 0,
232		MaxFractionDigits: 0,
233	},
234}, {
235	"0.0%",
236	&Pattern{
237		Affix:             "\x00\x01%",
238		DigitShift:        2,
239		FormatWidth:       4,
240		MinIntegerDigits:  1,
241		MinFractionDigits: 1,
242		MaxFractionDigits: 1,
243	},
244}, {
245	"0.0‰",
246	&Pattern{
247		Affix:             "\x00\x03‰",
248		DigitShift:        3,
249		FormatWidth:       4,
250		MinIntegerDigits:  1,
251		MinFractionDigits: 1,
252		MaxFractionDigits: 1,
253	},
254}, {
255	"#,##0.00¤",
256	&Pattern{
257		Affix:             "\x00\x02¤",
258		FormatWidth:       9,
259		GroupingSize:      [2]uint8{3, 0},
260		MinIntegerDigits:  1,
261		MinFractionDigits: 2,
262		MaxFractionDigits: 2,
263	},
264}, {
265	"#,##0.00 ¤;(#,##0.00 ¤)",
266	&Pattern{Affix: "\x00\x04\u00a0¤\x01(\x05\u00a0¤)",
267		NegOffset:         6,
268		DigitShift:        0,
269		FormatWidth:       10,
270		GroupingSize:      [2]uint8{3, 0},
271		MinIntegerDigits:  1,
272		MinFractionDigits: 2,
273		MaxFractionDigits: 2,
274	},
275}, {
276	// padding
277	"*x#",
278	&Pattern{
279		PadRune:     'x',
280		FormatWidth: 1,
281	},
282}, {
283	// padding
284	"#*x",
285	&Pattern{
286		PadRune:     'x',
287		FormatWidth: 1,
288		Flags:       PadBeforeSuffix,
289	},
290}, {
291	"*xpre#suf",
292	&Pattern{
293		Affix:       "\x03pre\x03suf",
294		PadRune:     'x',
295		FormatWidth: 7,
296	},
297}, {
298	"pre*x#suf",
299	&Pattern{
300		Affix:       "\x03pre\x03suf",
301		PadRune:     'x',
302		FormatWidth: 7,
303		Flags:       PadAfterPrefix,
304	},
305}, {
306	"pre#*xsuf",
307	&Pattern{
308		Affix:       "\x03pre\x03suf",
309		PadRune:     'x',
310		FormatWidth: 7,
311		Flags:       PadBeforeSuffix,
312	},
313}, {
314	"pre#suf*x",
315	&Pattern{
316		Affix:       "\x03pre\x03suf",
317		PadRune:     'x',
318		FormatWidth: 7,
319		Flags:       PadAfterSuffix,
320	},
321}, {
322	`* #0 o''clock`,
323	&Pattern{Affix: "\x00\x09 o\\'clock",
324		FormatWidth:      10,
325		PadRune:          32,
326		MinIntegerDigits: 0x1},
327}, {
328	`'123'* #0'456'`,
329	&Pattern{Affix: "\x05'123'\x05'456'",
330		FormatWidth:      8,
331		PadRune:          32,
332		MinIntegerDigits: 0x1,
333		Flags:            PadAfterPrefix},
334}, {
335	// no duplicate padding
336	"*xpre#suf*x", nil,
337}, {
338	// no duplicate padding
339	"*xpre#suf*x", nil,
340}}
341
342func TestParsePattern(t *testing.T) {
343	for i, tc := range testCases {
344		t.Run(tc.pat, func(t *testing.T) {
345			f, err := ParsePattern(tc.pat)
346			if !reflect.DeepEqual(f, tc.want) {
347				t.Errorf("%d:%s:\ngot %#v;\nwant %#v", i, tc.pat, f, tc.want)
348			}
349			if got, want := err != nil, tc.want == nil; got != want {
350				t.Errorf("%d:%s:error: got %v; want %v", i, tc.pat, err, want)
351			}
352		})
353	}
354}
355
356func TestPatternSize(t *testing.T) {
357	if sz := unsafe.Sizeof(Pattern{}); sz > 48 {
358		t.Errorf("got %d; want <= 48", sz)
359	}
360
361}
362