001/*
002 * Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch). Licensed under the Apache
003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
005 * Unless required by applicable law or agreed to in writing, software distributed under the License
006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
007 * or implied. See the License for the specific language governing permissions and limitations under
008 * the License. Contributors: Anatole Tresch - initial version.
009 */
010package org.javamoney.tck.tests.format;
011
012import org.javamoney.tck.tests.internal.TestAmount;
013import org.javamoney.tck.tests.internal.TestMonetaryAmountBuilder;
014import org.jboss.test.audit.annotations.SpecAssertion;
015import org.jboss.test.audit.annotations.SpecVersion;
016import org.testng.AssertJUnit;
017import org.testng.annotations.Test;
018
019import javax.money.CurrencyUnit;
020import javax.money.MonetaryAmount;
021import javax.money.MonetaryAmountFactory;
022import javax.money.Monetary;
023import javax.money.MonetaryException;
024import javax.money.format.AmountFormatQuery;
025import javax.money.format.AmountFormatQueryBuilder;
026import javax.money.format.MonetaryAmountFormat;
027import javax.money.format.MonetaryFormats;
028import java.text.DecimalFormat;
029import java.util.HashSet;
030import java.util.Locale;
031import java.util.Set;
032
033import static org.testng.Assert.*;
034import static org.testng.AssertJUnit.fail;
035
036@SpecVersion(spec = "JSR 354", version = "1.0.0")
037public class FormattingMonetaryAmountsTest {
038
039    /**
040     * Format several amounts, created using the default factory,
041     * but
042     * also a test instance, provided by the TCK, to ensure no
043     * implementation
044     * dependencies on the implementation.
045     */
046    @SpecAssertion(section = "4.4.1", id = "441-A1")
047    @Test(description = "4.4.1 Ensures the system.s default locale is supported for MonetaryAmountFormat.")
048    public void testNoDepOnAmountImplementation() {
049        final Locale defaultLocale = Locale.getDefault();
050        MonetaryAmountFormat amountFormat = MonetaryFormats.getAmountFormat(defaultLocale);
051        final Number[] values = new Number[]{100, 10000000000000L};
052
053        for (CurrencyUnit currency : Monetary.getCurrencies()) {
054            for (Number value : values) {
055                MonetaryAmount amount =
056                        Monetary.getDefaultAmountFactory().setCurrency(currency.getCurrencyCode())
057                                .setNumber(value).create();
058                String formattedAmount = amountFormat.format(amount);
059                MonetaryAmount amountMock = TestMonetaryAmountBuilder.getAmount(value, currency);
060                String formattedAmountMock = amountFormat.format(amountMock);
061                AssertJUnit.assertNotNull(formattedAmountMock);
062                assertEquals(formattedAmountMock, formattedAmount);
063            }
064        }
065    }
066
067    /**
068     * Print several amounts, created using the default factory, but
069     * also a test instance, provided by the TCK, to ensure no
070     * implementation
071     * dependencies on the implementation.
072     */
073    @SpecAssertion(section = "4.4.1", id = "441-A2")
074    @Test(description = "4.4.1 Formats amounts using all available locales.")
075    public void testFormattingIsIndependentOfImplementation() {
076        for (Locale locale : MonetaryFormats.getAvailableLocales()) {
077            MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(locale);
078            Set<String> formatsProcuced = new HashSet<>();
079            for (MonetaryAmountFactory fact : Monetary.getAmountFactories()) {
080                if (fact.getAmountType().equals(TestAmount.class)) {
081                    continue;
082                }
083                MonetaryAmount amt = fact.setCurrency("USD").setNumber(10.5).create();
084                String formatProduced = format.format(amt);
085                assertNotNull(formatProduced, "No MonetaryAmountFormat returned from MonetaryFormats." +
086                        "getMonetaryFormat(Locale,String...) with supported Locale: " + locale);
087                assertFalse(formatProduced.isEmpty(), "MonetaryAmountFormat returned empty String for " + amt);
088                formatsProcuced.add(formatProduced);
089            }
090            assertFalse(formatsProcuced.isEmpty(), "No formatted amount available. Are there no amount?");
091            assertFalse(formatsProcuced.size() > 1,
092                    "Formatter produces different output for different amount classes(+" +
093                            format.getClass() + "): " + formatsProcuced);
094        }
095    }
096
097    /**
098     * Parse back several amounts, input created using the
099     * formatting
100     * from 'Format_formatAmounts'.
101     */
102    @SpecAssertion(section = "4.4.1", id = "441-A3")
103    @Test(description = "4.4.1 Test formats and parses (round-trip) any supported amount type for each supported " +
104            "Locale.")
105    public void testParseIsIndependentOfImplementation() {
106        for (Locale locale : MonetaryFormats.getAvailableLocales()) {
107            MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(locale);
108            for (MonetaryAmountFactory fact : Monetary.getAmountFactories()) {
109                if (fact.getAmountType().equals(TestAmount.class)) {
110                    continue;
111                }
112                MonetaryAmount amt = fact.setCurrency("USD").setNumber(10.5).create();
113                String formatProduced = format.format(amt);
114                assertNotNull(formatProduced, "No MonetaryAmountFormat returned from MonetaryFormats." +
115                        "getMonetaryFormat(Locale,String...) with supported Locale: " + locale);
116                assertFalse(formatProduced.isEmpty(), "MonetaryAmountFormat returned empty String for " + amt);
117                try {
118                    MonetaryAmount amtParsed = format.parse(formatProduced);
119                    assertNotNull(amtParsed, "Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
120                            "' using MonetaryAmountFormat: " + format);
121                } catch (MonetaryException e) {
122                    fail("Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
123                            "' using MonetaryAmountFormat: " + format.getClass().getName() + " for Locale: " + locale);
124                }
125            }
126        }
127    }
128
129    /**
130     * Get/set different amount styles (especially patterns, group
131     * sizes, group characters) and compare results with results as from
132     * RI.
133     * Also apply patterns without currency invovled.
134     */
135    @SpecAssertion(section = "4.4.2", id = "442-A1")
136    @Test(description =
137            "4.4.2 Test formats and parses (round-trip) any supported amount type for each supported Locale, " +
138                    "using different format queries.")
139    public void testParseDifferentStyles() {
140        for (Locale locale : MonetaryFormats.getAvailableLocales()) {
141            for (Class clazz : Monetary.getAmountTypes()) {
142                if (clazz.equals(TestAmount.class)) {
143                    continue;
144                }
145                MonetaryAmountFactory fact = Monetary.getAmountFactory(clazz);
146                AmountFormatQuery query = AmountFormatQueryBuilder.of(locale).setMonetaryAmountFactory(fact).build();
147                if (fact.getAmountType().equals(TestAmount.class)) {
148                    continue;
149                }
150                MonetaryAmount amt = fact.setCurrency("USD").setNumber(10.5).create();
151                MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(query);
152                String formatProduced = format.format(amt);
153                assertNotNull(formatProduced, "No MonetaryAmountFormat returned from MonetaryFormats." +
154                        "getMonetaryFormat(Locale,String...) with supported Locale: " + locale);
155                assertFalse(formatProduced.isEmpty(), "MonetaryAmountFormat returned empty String for " + amt);
156                try {
157                    MonetaryAmount amtParsed = format.parse(formatProduced);
158                    assertNotNull(amtParsed, "Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
159                            "' using MonetaryAmountFormat: " + format);
160                    assertEquals(amtParsed.getClass(), clazz,
161                            "Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
162                                    "' using MonetaryAmountFormat(invalid type " +
163                                    amtParsed.getClass().getName() + ") for format: " + format);
164                } catch (MonetaryException e) {
165                    fail("Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
166                            "' using MonetaryAmountFormat: " + format.getClass().getName() + " for Locale: " + locale);
167                }
168            }
169        }
170    }
171
172
173    /**
174     * Get/set default currency, try to parse patterns without
175     * currency information.
176     */
177    @SpecAssertion(section = "4.4.1", id = "441-A4")
178    @Test(description =
179            "4.4.1 Test formats and parses (round-trip) any supported amount type for each supported Locale," +
180                    " checks results for different currencies")
181    public void testParseWithDifferentCurrencies() {
182        for (Locale locale : MonetaryFormats.getAvailableLocales()) {
183            MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(locale);
184            for (MonetaryAmountFactory fact : Monetary.getAmountFactories()) {
185                if (fact.getAmountType().equals(TestAmount.class)) {
186                    continue;
187                }
188                for (String currency : new String[]{"CHF", "USD", "GBP", "EUR"}) {
189                    MonetaryAmount amt = fact.setCurrency(currency).setNumber(10.5).create();
190                    String formatProduced = format.format(amt);
191                    assertNotNull(formatProduced, "No MonetaryAmountFormat returned from MonetaryFormats." +
192                            "getMonetaryFormat(Locale,String...) with supported Locale: " + locale);
193                    assertFalse(formatProduced.isEmpty(), "MonetaryAmountFormat returned empty String for " + amt);
194                    try {
195                        MonetaryAmount amtParsed = format.parse(formatProduced);
196                        assertNotNull(amtParsed, "Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
197                                "' using MonetaryAmountFormat: " + format);
198                        assertEquals(amtParsed.getCurrency().getCurrencyCode(), currency,
199                                "Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
200                                        "' using MonetaryAmountFormat(invalid currency " +
201                                        amtParsed.getCurrency().getCurrencyCode() + "): " + format);
202                    } catch (MonetaryException e) {
203                        fail("Reverse-parsing of MonetaryAmount failed for '" + formatProduced +
204                                "' using MonetaryAmountFormat: " + format.getClass().getName() + " for Locale: " + locale);
205                    }
206                }
207            }
208        }
209    }
210
211
212    /**
213     * AccessingMonetaryAmountFormat using
214     * MonetaryFormats.getAmountFormat(Locale locale), all locales
215     * available also from java.text.DecimalFormat must be supported.
216     */
217    @SpecAssertion(section = "4.4.3", id = "443-A1")
218    @Test(description = "4.4.3 Ensures all Locales defined by DecimalFormat.getAvailableLocales() are available for " +
219            "monetary formatting.")
220    public void testLocalesSupported() {
221        Locale[] jdkDecimalFormatLocales = DecimalFormat.getAvailableLocales();
222        for (Locale jdkDecimalFormatLocale : jdkDecimalFormatLocales) {
223            MonetaryAmountFormat amountFormat = MonetaryFormats.getAmountFormat(jdkDecimalFormatLocale);
224            AssertJUnit.assertNotNull(amountFormat);
225            assertEquals(jdkDecimalFormatLocale, amountFormat.getContext().getLocale());
226        }
227    }
228
229    /**
230     * AccessingMonetaryAmountFormat using
231     * MonetaryFormats.getAmountFormat(AmountFormatContext style), all locales
232     * available also from java.text.DecimalFormat must be supported
233     * (using AmountFormatContext.of(Locale)).
234     */
235    @Test(description = "4.4.3 Ensures for each locale defined by DecimalFormat.getAvailableLocales() a " +
236            "MonetaryAmountFormat instance is provided.")
237    @SpecAssertion(section = "4.4.3", id = "443-A2")
238    public void testGetAmountFormat() {
239        for (Locale locale : DecimalFormat.getAvailableLocales()) {
240            AssertJUnit.assertNotNull(MonetaryFormats.getAmountFormat(AmountFormatQuery.of(locale)));
241        }
242    }
243
244    /**
245     * Test MonetaryFormats.getAvailableLocales, all locales available also from java.text.DecimalFormat must be
246     * supported (using AmountFormatContext.of(Locale)), more locales are possible.
247     */
248    @Test(description = "4.4.3 Ensures for each locale defined by DecimalFormat.getAvailableLocales() a " +
249            "MonetaryFormats.isAvailable(Locale) is true.")
250    @SpecAssertion(section = "4.4.3", id = "443-A3")
251    public void testGetAvailableLocales() {
252        Set<Locale> locales = MonetaryFormats.getAvailableLocales();
253        for (Locale locale : DecimalFormat.getAvailableLocales()) {
254            if (Locale.ROOT.equals(locale)) {
255                continue;
256            }
257            AssertJUnit.assertTrue(
258                    "MonetaryFormats.getAvailableLocales(); Locale supported by JDKs DecimalFormat is not available: " +
259                            locale, locales.contains(locale));
260        }
261    }
262
263    /**
264     * Test MonetaryFormats.getAvailableLocales, all locales available also from java.text.DecimalFormat must be
265     * supported (using AmountFormatContext.of(Locale)), more locales are possible.
266     */
267    @Test(description = "4.4.3 Ensures for each locale defined by DecimalFormat.getAvailableLocales() a " +
268            "MonetaryFormats.getAmountFormat(AmountFormatQuery) returns a formatter.")
269    @SpecAssertion(section = "4.4.3", id = "443-A3")
270    public void testAmountStyleOf() {
271        for (Locale locale : DecimalFormat.getAvailableLocales()) {
272            AssertJUnit.assertNotNull(MonetaryFormats.getAmountFormat(AmountFormatQuery.of(locale)));
273        }
274    }
275}