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.conversion;
011
012import org.javamoney.tck.tests.internal.TestCurrencyUnit;
013import org.jboss.test.audit.annotations.SpecAssertion;
014import org.jboss.test.audit.annotations.SpecVersion;
015import org.testng.Assert;
016import org.testng.AssertJUnit;
017import org.testng.annotations.Test;
018
019import javax.money.CurrencyUnit;
020import javax.money.Monetary;
021import javax.money.UnknownCurrencyException;
022import javax.money.convert.ConversionQuery;
023import javax.money.convert.ConversionQueryBuilder;
024import javax.money.convert.ExchangeRate;
025import javax.money.convert.ExchangeRateProvider;
026import javax.money.convert.MonetaryConversions;
027import java.util.Locale;
028
029/**
030 * Tests for Exchange Rates and Rate Providers.
031 * Created by Anatole on 10.03.14.
032 */
033@SpecVersion(spec = "JSR 354", version = "1.0.0")
034public class ExchangeRatesAndRateProvidersTest {
035
036    // *************************** A. Test Basic MonetaryConversions Accessors *********************************
037
038    private static final CurrencyUnit FOO_UNIT = new TestCurrencyUnit("FOO");
039
040    /**
041     * Test access to conversion rates.<p>
042     * Hint: this assertion will require multiple tests to be written!
043     */
044    @Test(description = "4.3.3 Test access of Conversion Rates, using TCK provided rate provider.")
045    @SpecAssertion(id = "433-A1", section = "4.3.3")
046    public void testAccessKnownRates() {
047        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider("TestRateProvider");
048        // Use test provider
049        for (CurrencyUnit base : Monetary.getCurrencies()) {
050            if (base.equals(FOO_UNIT)) {
051                continue;
052            }
053            ExchangeRate rate = prov.getExchangeRate(base, FOO_UNIT);
054            AssertJUnit.assertNotNull(
055                    "Identity rate, accessed by getExchangeRate(CurrencyUnit, CurrencyUnit), is not defined for " +
056                            base.getCurrencyCode() + " -> " + FOO_UNIT.getCurrencyCode());
057            AssertJUnit.assertEquals(rate.getBaseCurrency().getCurrencyCode(), base.getCurrencyCode());
058            AssertJUnit.assertEquals(rate.getCurrency().getCurrencyCode(), FOO_UNIT.getCurrencyCode());
059            AssertJUnit.assertEquals(rate.getFactor().intValueExact(), 2);
060        }
061    }
062
063    /**
064     * Test access to conversion rates.<p>
065     * Hint: this assertion will require multiple tests to be written!
066     */
067    @Test(description = "4.3.3 Test access to exchange rates from TestRateProvider, using target currency code.")
068    @SpecAssertion(id = "433-A1", section = "4.3.3")
069    public void testAccessKnownRatesWithCodes() {
070        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider("TestRateProvider");
071        // Use test provider
072        for (CurrencyUnit base : Monetary.getCurrencies()) {
073            if (base.equals(FOO_UNIT)) {
074                continue;
075            }
076            ExchangeRate rate = prov.getExchangeRate(base.getCurrencyCode(), "XXX");
077            AssertJUnit
078                    .assertNotNull("Identity rate, accessed by getExchangeRate(String, String), is not defined for " +
079                            base.getCurrencyCode() + " -> " + FOO_UNIT.getCurrencyCode(), rate);
080            AssertJUnit.assertEquals(rate.getBaseCurrency().getCurrencyCode(), base.getCurrencyCode());
081            AssertJUnit.assertEquals(rate.getCurrency().getCurrencyCode(), "FOO");
082            AssertJUnit.assertEquals(rate.getFactor().intValueExact(), 2);
083        }
084    }
085
086    /**
087     * Test access to conversion rates.<p>
088     * Hint: this assertion will require multiple tests to be written!
089     */
090    @Test(description = "4.3.3 Test access to exchange rates from TestRateProvider, using target CUrrencyUnit.")
091    @SpecAssertion(id = "433-A1", section = "4.3.3")
092    public void testAccessKnownRatesAndContext() {
093        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider("TestRateProvider");
094        // Use test provider
095        for (CurrencyUnit base : Monetary.getCurrencies()) {
096            if (base.equals(FOO_UNIT)) {
097                continue;
098            }
099            ExchangeRate rate = prov.getExchangeRate(base, FOO_UNIT);
100            AssertJUnit.assertNotNull(
101                    "Identity rate, accessed by getExchangeRate(CurrencyUnit, CurrencyUnit, ConversionContext), " +
102                            "is not defined for " +
103                            base.getCurrencyCode() + " -> " + FOO_UNIT.getCurrencyCode());
104            AssertJUnit.assertEquals(rate.getBaseCurrency().getCurrencyCode(), base.getCurrencyCode());
105            AssertJUnit.assertEquals(rate.getCurrency().getCurrencyCode(), FOO_UNIT.getCurrencyCode());
106            AssertJUnit.assertEquals(rate.getFactor().intValueExact(), 2);
107        }
108    }
109
110    /**
111     * Test access to conversion rates.<p>
112     * Hint: this assertion will require multiple tests to be written!
113     */
114    @Test(description = "4.3.3  Test access to conversion rates, including known factor, using TestRateProvider.")
115    @SpecAssertion(id = "433-A1", section = "4.3.3")
116    public void testAccessKnownRatesWithCodesAndContext() {
117        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider("TestRateProvider");
118        // Use test provider
119        for (CurrencyUnit base : Monetary.getCurrencies()) {
120            ExchangeRate rate = prov.getExchangeRate(base, FOO_UNIT);
121            AssertJUnit
122                    .assertNotNull("Identity rate, accessed by getExchangeRate(String, String, ConversionContext), " +
123                            "is not defined for " +
124                            base.getCurrencyCode() + " -> " + FOO_UNIT.getCurrencyCode(), rate);
125            AssertJUnit.assertEquals(rate.getBaseCurrency().getCurrencyCode(), base.getCurrencyCode());
126            AssertJUnit.assertEquals(rate.getCurrency().getCurrencyCode(), FOO_UNIT.getCurrencyCode());
127            AssertJUnit.assertEquals(rate.getFactor().intValueExact(), 2);
128        }
129    }
130
131    /**
132     * Test access to conversion rates.<p>
133     * Hint: this assertion will require multiple tests to be written!
134     */
135    @Test(description = "4.3.3 Test access to identity conversion rate for CurrencyUnits, using default provider")
136    @SpecAssertion(id = "433-A1", section = "4.3.3")
137    public void testAccessRates_IdentityRatesWithUnits() {
138        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(); // Use default provider
139        for (CurrencyUnit unit : Monetary.getCurrencies()) {
140            ExchangeRate rate = prov.getExchangeRate(unit, unit);
141            AssertJUnit.assertNotNull(
142                    "Identity rate, accessed by getExchangeRate(CurrencyUnit, CurrencyUnit), is not defined for " +
143                            unit.getCurrencyCode(), rate);
144        }
145    }
146
147    /**
148     * Test access to conversion rates.<p>
149     * Hint: this assertion will require multiple tests to be written!
150     */
151    @Test(description = "4.3.3 Test access to conversion rate for currency codes, using default provider.")
152    @SpecAssertion(id = "433-A1", section = "4.3.3")
153    public void testAccessRates_IdentityRatesWithCodes() {
154        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(); // Use default provider
155        for (CurrencyUnit unit : Monetary.getCurrencies()) {
156            ExchangeRate rate = prov.getExchangeRate(unit.getCurrencyCode(), unit.getCurrencyCode());
157            AssertJUnit.assertNotNull(
158                    "Identity rate, accessed by getExchangeRate(String, String), is not defined for " +
159                            unit.getCurrencyCode(), rate);
160        }
161    }
162
163    /**
164     * Test access to conversion rates.<p>
165     * Hint: this assertion will require multiple tests to be written!
166     */
167    @Test(description = "4.3.3 Test access to conversion rate for CurrencyQuery, using default provider.")
168    @SpecAssertion(id = "433-A1", section = "4.3.3")
169    public void testAccessRates_IdentityRatesWithUnitsAndContext() {
170        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(); // Use default provider
171        for (CurrencyUnit unit : Monetary.getCurrencies()) {
172            ExchangeRate rate = prov.getExchangeRate(
173                    ConversionQueryBuilder.of().setBaseCurrency(unit).setTermCurrency(unit).build());
174            AssertJUnit.assertNotNull("Identity rate, accessed by getExchangeRate(ConversionQuery), " +
175                    "is not defined for " +
176                    unit.getCurrencyCode(), rate);
177        }
178    }
179
180    /**
181     * Ensure additional ConversionContext is passed correctly to SPIs.<p>
182     * Hint: this assertion will require some custom SPIs to be registered and selected for chain inclusion!
183     */
184    @Test(description = "4.3.3 Ensure additional ConversionQuery data is passed correctly to SPIs.")
185    @SpecAssertion(id = "433-A2", section = "4.3.3")
186    public void testPassingOverConversionContextToSPIs() {
187        ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider("TestRateProvider");
188        ConversionQuery ctx = ConversionQueryBuilder.of().set(Locale.CANADA).set("Foo", "bar").setBaseCurrency(FOO_UNIT)
189                .setTermCurrency(Monetary.getCurrency("XXX")).build();
190        ExchangeRate rate = prov.getExchangeRate(ctx);
191        AssertJUnit.assertNotNull("No test rate returned by getExchangeRate(ConversionQuery), " +
192                "probably TestProvider is not correct registered.");
193        AssertJUnit.assertEquals(
194                "Text parameter Locale.class was not correctly passed to ExchangeRateProvider implementation.", "bar",
195                rate.getContext().getText("Foo"));
196        AssertJUnit.assertEquals(
197                "Object parameter Locale.class was not correctly passed to ExchangeRateProvider implementation.",
198                Locale.CANADA, rate.getContext().get(Locale.class));
199    }
200
201
202    /**
203     * Bad case: try accessing rates with inconsistent/invalid data.<p>
204     * Hint: this assertion will require multiple tests to be written!
205     */
206    @Test(description = "4.3.3 Bad case: try accessing exchange rates with invalid base currency code.")
207    @SpecAssertion(id = "433-A3", section = "4.3.3")
208    public void testInvalidUsage_InvalidSourceCurrency() {
209        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
210            if ("TestRateProvider".equals(providerID)) {
211                continue;
212            }
213            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
214            try {
215                prov.getExchangeRate("dhdjbdjd", "CHF");
216                Assert.fail(
217                        "ExchangeRateProvider should throw UnknownCurrencyException when an invalid source currency " +
218                                "is passed to getExchangeRate(String,String), provider: " +
219                                providerID);
220            } catch (UnknownCurrencyException e) {
221                // OK
222            }
223        }
224    }
225
226    /**
227     * Bad case: try accessing rates with inconsistent/invalid data.<p>
228     * Hint: this assertion will require multiple tests to be written!
229     */
230    @Test(description = "4.3.3 Bad case: try accessing exchange rates with null base currency code.")
231    @SpecAssertion(id = "433-A3", section = "4.3.3")
232    public void testInvalidUsage_NullSourceCurrency() {
233        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
234            if ("TestRateProvider".equals(providerID)) {
235                continue;
236            }
237            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
238            try {
239                prov.getExchangeRate(null, "CHF");
240                Assert.fail("ExchangeRateProvider should throw NullPointerException when an null source currency " +
241                        "is passed to getExchangeRate(String,String), provider: " +
242                        providerID);
243            } catch (NullPointerException e) {
244                // OK
245            }
246        }
247    }
248
249    /**
250     * Bad case: try accessing rates with inconsistent/invalid data.<p>
251     * Hint: this assertion will require multiple tests to be written!
252     */
253    @Test(description = "4.3.3 Bad case: try accessing exchange rates with invalid term currency code.")
254    @SpecAssertion(id = "433-A3", section = "4.3.3")
255    public void testInvalidUsage_InvalidTargetCurrency() {
256        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
257            if ("TestRateProvider".equals(providerID)) {
258                continue;
259            }
260            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
261            try {
262                prov.getExchangeRate("CHF", "dhdjbdjd");
263                Assert.fail(
264                        "ExchangeRateProvider should throw UnknownCurrencyException when an invalid target currency " +
265                                "is passed to getExchangeRate(String,String), provider: " +
266                                providerID);
267            } catch (UnknownCurrencyException e) {
268                // OK
269            }
270        }
271    }
272
273    /**
274     * Bad case: try accessing rates with inconsistent/invalid data.<p>
275     * Hint: this assertion will require multiple tests to be written!
276     */
277    @Test(description = "4.3.3 Bad case: try accessing exchange rates with null term currency code.")
278    @SpecAssertion(id = "433-A3", section = "4.3.3")
279    public void testInvalidUsage_NullTargetCurrency() {
280        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
281            if ("TestRateProvider".equals(providerID)) {
282                continue;
283            }
284            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
285            try {
286                prov.getExchangeRate("CHF", null);
287                Assert.fail("ExchangeRateProvider should throw NullPointerException when an null target currency " +
288                        "is passed to getExchangeRate(String,String), provider: " +
289                        providerID);
290            } catch (NullPointerException e) {
291                // OK
292            }
293        }
294    }
295
296    /**
297     * Bad case: try accessing rates with inconsistent/invalid data.<p>
298     * Hint: this assertion will require multiple tests to be written!
299     */
300    @Test(description = "4.3.3 Bad case: try accessing exchange rates with null ConversionQuery.")
301    @SpecAssertion(id = "433-A3", section = "4.3.3")
302    public void testInvalidUsage_InvalidSourceCurrencyAndContext() {
303        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
304            if ("TestRateProvider".equals(providerID)) {
305                continue;
306            }
307            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
308            try {
309                prov.getExchangeRate(null);
310                Assert.fail("ExchangeRateProvider should throw NPE when an null ConversionQuery " +
311                        "is passed to getExchangeRate(ConversionQuery), provider: " +
312                        providerID);
313            } catch (NullPointerException e) {
314                // OK
315            }
316        }
317    }
318
319
320    /**
321     * Bad case: try accessing rates with inconsistent/invalid data.<p>
322     * Hint: this assertion will require multiple tests to be written!
323     */
324    @Test(description = "4.3.3 Bad case: try accessing exchange rates with null base CurrencyUnit.")
325    @SpecAssertion(id = "433-A3", section = "4.3.3")
326    public void testInvalidUsage_NullSourceCurrencyUnit() {
327        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
328            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
329            try {
330                prov.getExchangeRate(null, Monetary.getCurrency("CHF"));
331                Assert.fail("ExchangeRateProvider should throw NullPointerException when an null source currency " +
332                        "is passed to getExchangeRate(CurrencyUnit,CurrencyUnit), provider: " +
333                        providerID);
334            } catch (NullPointerException e) {
335                // OK
336            }
337        }
338    }
339
340    /**
341     * Bad case: try accessing rates with inconsistent/invalid data.<p>
342     * Hint: this assertion will require multiple tests to be written!
343     */
344    @Test(description = "4.3.3 Bad case: try accessing exchange rates with null term CurrencyUnit.")
345    @SpecAssertion(id = "433-A3", section = "4.3.3")
346    public void testInvalidUsage_NullTargetCurrencyUnit() {
347        for (String providerID : MonetaryConversions.getConversionProviderNames()) {
348            ExchangeRateProvider prov = MonetaryConversions.getExchangeRateProvider(providerID);
349            try {
350                prov.getExchangeRate(Monetary.getCurrency("CHF"), null);
351                Assert.fail("ExchangeRateProvider should throw NullPointerException when an invalid target currency " +
352                        "is passed to getExchangeRate(CurrencyUnit,CurrencyUnit), provider: " +
353                        providerID);
354            } catch (NullPointerException e) {
355                // OK
356            }
357        }
358    }
359
360}