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 currency
6
7import (
8	"fmt"
9	"testing"
10
11	"golang.org/x/text/internal/testtext"
12	"golang.org/x/text/language"
13)
14
15var (
16	cup = MustParseISO("CUP")
17	czk = MustParseISO("CZK")
18	xcd = MustParseISO("XCD")
19	zwr = MustParseISO("ZWR")
20)
21
22func TestParseISO(t *testing.T) {
23	testCases := []struct {
24		in  string
25		out Unit
26		ok  bool
27	}{
28		{"USD", USD, true},
29		{"xxx", XXX, true},
30		{"xts", XTS, true},
31		{"XX", XXX, false},
32		{"XXXX", XXX, false},
33		{"", XXX, false},       // not well-formed
34		{"UUU", XXX, false},    // unknown
35		{"\u22A9", XXX, false}, // non-ASCII, printable
36
37		{"aaa", XXX, false},
38		{"zzz", XXX, false},
39		{"000", XXX, false},
40		{"999", XXX, false},
41		{"---", XXX, false},
42		{"\x00\x00\x00", XXX, false},
43		{"\xff\xff\xff", XXX, false},
44	}
45	for i, tc := range testCases {
46		if x, err := ParseISO(tc.in); x != tc.out || err == nil != tc.ok {
47			t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tc.in, x, err == nil, tc.out, tc.ok)
48		}
49	}
50}
51
52func TestFromRegion(t *testing.T) {
53	testCases := []struct {
54		region   string
55		currency Unit
56		ok       bool
57	}{
58		{"NL", EUR, true},
59		{"BE", EUR, true},
60		{"AG", xcd, true},
61		{"CH", CHF, true},
62		{"CU", cup, true},   // first of multiple
63		{"DG", USD, true},   // does not have M49 code
64		{"150", XXX, false}, // implicit false
65		{"CP", XXX, false},  // explicit false in CLDR
66		{"CS", XXX, false},  // all expired
67		{"ZZ", XXX, false},  // none match
68	}
69	for _, tc := range testCases {
70		cur, ok := FromRegion(language.MustParseRegion(tc.region))
71		if cur != tc.currency || ok != tc.ok {
72			t.Errorf("%s: got %v, %v; want %v, %v", tc.region, cur, ok, tc.currency, tc.ok)
73		}
74	}
75}
76
77func TestFromTag(t *testing.T) {
78	testCases := []struct {
79		tag      string
80		currency Unit
81		conf     language.Confidence
82	}{
83		{"nl", EUR, language.Low},      // nl also spoken outside Euro land.
84		{"nl-BE", EUR, language.Exact}, // region is known
85		{"pt", BRL, language.Low},
86		{"en", USD, language.Low},
87		{"en-u-cu-eur", EUR, language.Exact},
88		{"tlh", XXX, language.No}, // Klingon has no country.
89		{"es-419", XXX, language.No},
90		{"und", USD, language.Low},
91	}
92	for _, tc := range testCases {
93		cur, conf := FromTag(language.MustParse(tc.tag))
94		if cur != tc.currency || conf != tc.conf {
95			t.Errorf("%s: got %v, %v; want %v, %v", tc.tag, cur, conf, tc.currency, tc.conf)
96		}
97	}
98}
99
100func TestTable(t *testing.T) {
101	for i := 4; i < len(currency); i += 4 {
102		if a, b := currency[i-4:i-1], currency[i:i+3]; a >= b {
103			t.Errorf("currency unordered at element %d: %s >= %s", i, a, b)
104		}
105	}
106	// First currency has index 1, last is numCurrencies.
107	if c := currency.Elem(1)[:3]; c != "ADP" {
108		t.Errorf("first was %q; want ADP", c)
109	}
110	if c := currency.Elem(numCurrencies)[:3]; c != "ZWR" {
111		t.Errorf("last was %q; want ZWR", c)
112	}
113}
114
115func TestKindRounding(t *testing.T) {
116	testCases := []struct {
117		kind  Kind
118		cur   Unit
119		scale int
120		inc   int
121	}{
122		{Standard, USD, 2, 1},
123		{Standard, CHF, 2, 1},
124		{Cash, CHF, 2, 5},
125		{Standard, TWD, 2, 1},
126		{Cash, TWD, 0, 1},
127		{Standard, czk, 2, 1},
128		{Cash, czk, 0, 1},
129		{Standard, zwr, 2, 1},
130		{Cash, zwr, 0, 1},
131		{Standard, KRW, 0, 1},
132		{Cash, KRW, 0, 1}, // Cash defaults to standard.
133	}
134	for i, tc := range testCases {
135		if scale, inc := tc.kind.Rounding(tc.cur); scale != tc.scale && inc != tc.inc {
136			t.Errorf("%d: got %d, %d; want %d, %d", i, scale, inc, tc.scale, tc.inc)
137		}
138	}
139}
140
141const body = `package main
142import (
143	"fmt"
144	"golang.org/x/text/currency"
145)
146func main() {
147	%s
148}
149`
150
151func TestLinking(t *testing.T) {
152	base := getSize(t, `fmt.Print(currency.CLDRVersion)`)
153	symbols := getSize(t, `fmt.Print(currency.Symbol(currency.USD))`)
154	if d := symbols - base; d < 2*1024 {
155		t.Errorf("size(symbols)-size(base) was %d; want > 2K", d)
156	}
157}
158
159func getSize(t *testing.T, main string) int {
160	size, err := testtext.CodeSize(fmt.Sprintf(body, main))
161	if err != nil {
162		t.Skipf("skipping link size test; binary size could not be determined: %v", err)
163	}
164	return size
165}
166
167func BenchmarkString(b *testing.B) {
168	for i := 0; i < b.N; i++ {
169		USD.String()
170	}
171}
172