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