japod@35: package org.apidesign.apifest08.test; japod@35: japod@35: import java.math.BigDecimal; japod@35: import java.util.Currency; japod@35: import java.util.Set; japod@35: import junit.framework.TestCase; japod@35: import org.apidesign.apifest08.currency.Convertor; japod@35: import org.apidesign.apifest08.currency.ConvertorFactory; japod@35: import org.apidesign.apifest08.currency.InvalidConversionException; japod@35: japod@35: japod@35: /** There are many currencies around the world and many banks manipulate japod@35: * with more than one or two at the same time. As banks are usually the japod@35: * best paying clients, which is true even in case of your Convertor API, japod@35: * it is reasonable to listen to their requests. japod@35: *

japod@35: * The quest for today is to enhance your existing convertor API to hold japod@35: * information about many currencies and allow conversions between any of them. japod@35: * Also, as conversion rates for diferent currencies usually arise from various japod@35: * bank departments, there is another important need. There is a need to japod@35: * compose two convertors into one by merging all the information about japod@35: * currencies they know about. japod@35: */ japod@35: public class Task2Test extends TestCase japod@35: { japod@35: private final static Currency CZK; japod@35: private final static Currency SKK; japod@35: private final static Currency USD; japod@35: japod@35: static japod@35: { japod@35: CZK = Currency.getInstance("CZK"); japod@35: SKK = Currency.getInstance("SKK"); japod@35: USD = Currency.getInstance("USD"); japod@35: } japod@35: japod@35: public Task2Test(String testName) japod@35: { japod@35: super(testName); japod@35: } japod@35: japod@35: @Override japod@35: protected void setUp() japod@35: throws Exception japod@35: { japod@35: } japod@35: japod@35: @Override japod@35: protected void tearDown() japod@35: throws Exception japod@35: { japod@35: } japod@35: japod@35: // As in Task1Test, keep in mind, that there are three parts japod@35: // of the whole system: japod@35: // 1. there is someone who knows the current exchange rate japod@35: // 2. there is someone who wants to do the conversion japod@35: // 3. there is the API between 1. and 2. which allows them to communicate japod@35: // japod@35: // Please backward compatibly enhance your existing API to support following japod@35: // usecases: japod@35: // japod@35: japod@35: /** Create convertor that understands two currencies, CZK and japod@35: * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that japod@35: * knows the exchange rate, and needs to use the API to create objects japod@35: * with the exchange rate. Anyone shall be ready to call this method without japod@35: * any other method being called previously. The API itself shall know japod@35: * nothing about any rates, before this method is called. japod@35: */ japod@35: public static Convertor createTripleConvertor() { japod@35: // Rates: 1USD = 15CZK japod@35: // Rates: 1USD = 20SKK japod@35: // Rates: 75CZK = 100SKK japod@35: Convertor c = ConvertorFactory.mergeConvertors( japod@35: ConvertorFactory.getConvertor(USD, BigDecimal.ONE, CZK, BigDecimal.valueOf(15.00)), japod@35: ConvertorFactory.getConvertor(USD, BigDecimal.ONE, SKK, BigDecimal.valueOf(20.00)) japod@35: ); japod@35: japod@35: return c; japod@35: } japod@35: japod@35: /** Define convertor that understands three currencies. Use it. japod@35: */ japod@35: public void testConvertorForUSDandCZKandSKK() throws Exception { japod@35: Convertor c = createTripleConvertor(); japod@35: japod@35: // convert $5 to CZK using c: japod@35: // assertEquals("Result is 75 CZK"); japod@35: assertEquals(new BigDecimal("75.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00))); japod@35: japod@35: // convert $5 to SKK using c: japod@35: // assertEquals("Result is 100 SKK"); japod@35: assertEquals(new BigDecimal("100.00"), c.convert(USD, SKK, BigDecimal.valueOf(5.00))); japod@35: japod@35: // convert 200SKK to CZK using c: japod@35: // assertEquals("Result is 150 CZK"); japod@35: assertEquals(new BigDecimal("150.00"), c.convert(SKK, CZK, BigDecimal.valueOf(200.00))); japod@35: japod@35: // convert 200SKK to USK using c: japod@35: // assertEquals("Result is 10 USD"); japod@35: assertEquals(new BigDecimal("10.00"), c.convert(SKK, USD, BigDecimal.valueOf(200.00))); japod@35: } japod@35: japod@35: /** Merge all currency rates of convertor 1 with convertor 2. japod@35: * Implement this using your API, preferably this method just delegates japod@35: * into some API method which does the actual work, without requiring japod@35: * API clients to code anything complex. japod@35: */ japod@35: public static Convertor merge(Convertor one, Convertor two) { japod@35: return ConvertorFactory.mergeConvertors(one, two); japod@35: } japod@35: japod@35: /** Join the convertors from previous task, Task1Test and show that it japod@35: * can be used to do reasonable conversions. japod@35: */ japod@35: public void testConvertorComposition() throws Exception { japod@35: Convertor c = merge( japod@35: Task1Test.createCZKtoUSD(), japod@35: Task1Test.createSKKtoCZK() japod@35: ); japod@35: japod@35: // convert $5 to CZK using c: japod@35: // assertEquals("Result is 85 CZK"); japod@35: assertEquals(new BigDecimal("85.00"), c.convert(USD, CZK, BigDecimal.valueOf(5.00))); japod@35: japod@35: // convert $8 to CZK using c: japod@35: // assertEquals("Result is 136 CZK"); japod@35: assertEquals(new BigDecimal("136.00"), c.convert(USD, CZK, BigDecimal.valueOf(8.00))); japod@35: japod@35: // convert 1003CZK to USD using c: japod@35: // assertEquals("Result is 59 USD"); japod@35: assertEquals(new BigDecimal("59.00"), c.convert(CZK, USD, BigDecimal.valueOf(1003.00))); japod@35: japod@35: // convert 16CZK using c: japod@35: // assertEquals("Result is 20 SKK"); japod@35: assertEquals(new BigDecimal("20.00"), c.convert(CZK, SKK, BigDecimal.valueOf(16.00))); japod@35: japod@35: // convert 500SKK to CZK using c: japod@35: // assertEquals("Result is 400 CZK"); japod@35: assertEquals(new BigDecimal("400.00"), c.convert(SKK, CZK, BigDecimal.valueOf(500.00))); japod@35: } japod@35: japod@35: public void testGetCurrencies() japod@35: { japod@35: Convertor c = merge( japod@35: Task1Test.createCZKtoUSD(), japod@35: Task1Test.createSKKtoCZK() japod@35: ); japod@35: Set currencies; japod@35: japod@35: currencies = c.getCurrencies(); japod@35: assertEquals(3, currencies.size()); japod@35: assertTrue(currencies.contains(Currency.getInstance("SKK"))); japod@35: assertTrue(currencies.contains(Currency.getInstance("CZK"))); japod@35: assertTrue(currencies.contains(Currency.getInstance("USD"))); japod@35: } japod@35: japod@35: public void testGetConverstionRate() japod@35: throws InvalidConversionException japod@35: { japod@35: Convertor c = merge( japod@35: Task1Test.createCZKtoUSD(), japod@35: Task1Test.createSKKtoCZK() japod@35: ); japod@35: japod@35: assertEquals(1.0, c.getConversionRate(USD, USD).doubleValue(), 0.0000000000000001); japod@35: assertEquals(17.0, c.getConversionRate(USD, CZK).doubleValue(), 0.0000000000000001); japod@35: assertEquals(21.25, c.getConversionRate(USD, SKK).doubleValue(), 0.0000000000000001); japod@35: japod@35: assertEquals(1.0 / 17.0, c.getConversionRate(CZK, USD).doubleValue(), 0.0000000000000001); japod@35: assertEquals(1.0, c.getConversionRate(CZK, CZK).doubleValue(), 0.0000000000000001); japod@35: assertEquals(1.25, c.getConversionRate(CZK, SKK).doubleValue(), 0.0000000000000001); japod@35: japod@35: assertEquals(0.04705882352941176, c.getConversionRate(SKK, USD).doubleValue(), 0.0000000000000001); japod@35: assertEquals(0.8, c.getConversionRate(SKK, CZK).doubleValue(), 0.0000000000000001); japod@35: assertEquals(1.0, c.getConversionRate(SKK, SKK).doubleValue(), 0.0000000000000001); japod@35: } japod@35: }