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