# HG changeset patch # User japod@localhost # Date 1223331862 -7200 # Node ID 6102a569c7fa2623cca1e3949a7bd693775140ea # Parent 8898c620fe964142a70cdbc5f4c760df0c79f0ed adding solution07 for task 2 diff -r 8898c620fe96 -r 6102a569c7fa task2/solution07/test/org/apidesign/apifest08/test/Task2Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task2/solution07/test/org/apidesign/apifest08/test/Task2Test.java Tue Oct 07 00:24:22 2008 +0200 @@ -0,0 +1,192 @@ +package org.apidesign.apifest08.test; + +import java.util.Currency; +import junit.framework.TestCase; +import org.apidesign.apifest08.currency.ConversionRate; +import org.apidesign.apifest08.currency.Convertor; +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException; +import org.apidesign.apifest08.currency.MonetaryAmount; +import org.apidesign.apifest08.currency.TableConvertor; + +/** There are many currencies around the world and many banks manipulate + * with more than one or two at the same time. As banks are usually the + * best paying clients, which is true even in case of your Convertor API, + * it is reasonable to listen to their requests. + *

+ * The quest for today is to enhance your existing convertor API to hold + * information about many currencies and allow conversions between any of them. + * Also, as conversion rates for diferent currencies usually arise from various + * bank departments, there is another important need. There is a need to + * compose two convertors into one by merging all the information about + * currencies they know about. + */ +public class Task2Test extends TestCase { + public Task2Test(String testName) { + super(testName); + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } + + protected static final Currency CZK = Currency.getInstance( "CZK" ); + protected static final Currency SKK = Currency.getInstance( "SKK" ); + protected static final Currency USD = Currency.getInstance( "USD" ); + + // As in Task1Test, keep in mind, that there are three parts + // of the whole system: + // 1. there is someone who knows the current exchange rate + // 2. there is someone who wants to do the conversion + // 3. there is the API between 1. and 2. which allows them to communicate + // + // Please backward compatibly enhance your existing API to support following + // usecases: + // + + /** Create convertor that understands two currencies, CZK and + * SKK. Make 100 SKK == 75 CZK. This is method for the group of users that + * knows the exchange rate, and needs to use the API to create objects + * with the exchange rate. Anyone shall be ready to call this method without + * any other method being called previously. The API itself shall know + * nothing about any rates, before this method is called. + */ + public static Convertor createTripleConvertor() { + // Rates: 1USD = 15CZK + // Rates: 1USD = 20SKK + // Rates: 75CZK = 100SKK + final TableConvertor convertor = new TableConvertor(); + final MonetaryAmount amountInUSD = new MonetaryAmount( 1, USD ); + final MonetaryAmount amountInCZK = new MonetaryAmount( 15, CZK ); + final MonetaryAmount amountInSKK = new MonetaryAmount( 20, SKK ); + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInUSD ) ); + convertor.putIntoTable( new ConversionRate( amountInUSD, amountInCZK ) ); + convertor.putIntoTable( new ConversionRate( amountInSKK, amountInUSD ) ); + convertor.putIntoTable( new ConversionRate( amountInUSD, amountInSKK ) ); + convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) ); + convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) ); + return new ContractImposingDelegatingConvertor( convertor ).test(); + } + + /** Define convertor that understands three currencies. Use it. + */ + public void testConvertorForUSDandCZKandSKK() throws Exception { + final Convertor c = createTripleConvertor(); + + // convert $5 to CZK using c: + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) ); + final MonetaryAmount a1 = r1.getNetAmount(); + // assertEquals("Result is 75 CZK"); + assertNotNull( a1 ); + assertEquals( 75.0, a1.getAmount().doubleValue() ); + assertEquals( CZK, a1.getCurrency() ); + + // convert $5 to SKK using c: + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), SKK ) ); + final MonetaryAmount a2 = r2.getNetAmount(); + // assertEquals("Result is 100 SKK"); + assertNotNull( a2 ); + assertEquals( 100.0, a2.getAmount().doubleValue() ); + assertEquals( SKK, a2.getCurrency() ); + + // convert 200SKK to CZK using c: + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), CZK ) ); + final MonetaryAmount a3 = r3.getNetAmount(); + // assertEquals("Result is 150 CZK"); + assertNotNull( a3 ); + assertEquals( 150.0, a3.getAmount().doubleValue() ); + assertEquals( CZK, a3.getCurrency() ); + + // convert 200SKK to USK using c: + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 200, SKK ), USD ) ); + final MonetaryAmount a4 = r4.getNetAmount(); + // assertEquals("Result is 10 USD"); + assertNotNull( a4 ); + assertEquals( 10.0, a4.getAmount().doubleValue() ); + assertEquals( USD, a4.getCurrency() ); + } + + /** Merge all currency rates of convertor 1 with convertor 2. + * Implement this using your API, preferably this method just delegates + * into some API method which does the actual work, without requiring + * API clients to code anything complex. + */ + public static Convertor merge( final Convertor one, final Convertor two ) { + return new Convertor() { + + public ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException { + final ConversionResult res1 = one.convert( req ); + final ConversionResult res2 = two.convert( req ); + if ( res1.getNetAmount() != null ) { + if ( res2.getNetAmount() != null ) { + // TODO check if they arrive at the same thing + return res1; + } else { + return res1; + } + } else { + if ( res2.getNetAmount() != null ) { + return res2; + } else { + // neither converts + return new ConversionResult( null ); + } + } + } + + }; + } + + /** Join the convertors from previous task, Task1Test and show that it + * can be used to do reasonable conversions. + */ + public void testConvertorComposition() throws Exception { + final Convertor c = merge( + Task1Test.createCZKtoUSD(), + Task1Test.createSKKtoCZK() + ); + + // convert $5 to CZK using c: + final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) ); + final MonetaryAmount a1 = r1.getNetAmount(); + // assertEquals("Result is 85 CZK"); + assertNotNull( a1 ); + assertEquals( 85.0, a1.getAmount().doubleValue() ); + assertEquals( CZK, a1.getCurrency() ); + + // convert $8 to CZK + final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) ); + final MonetaryAmount a2 = r2.getNetAmount(); + // assertEquals("Result is 136 CZK"); + assertNotNull( a2 ); + assertEquals( 136.0, a2.getAmount().doubleValue() ); + assertEquals( CZK, a2.getCurrency() ); + + // convert 1003CZK to USD + final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) ); + final MonetaryAmount a3 = r3.getNetAmount(); + // assertEquals("Result is 59 USD"); + assertNotNull( a3 ); + assertEquals( 59.0, a3.getAmount().doubleValue() ); + assertEquals( USD, a3.getCurrency() ); + + // convert 16CZK using c: + final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) ); + final MonetaryAmount a4 = r4.getNetAmount(); + // assertEquals("Result is 20 SKK"); + assertNotNull( a4 ); + assertEquals( 20.0, a4.getAmount().doubleValue() ); + assertEquals( SKK, a4.getCurrency() ); + + // convert 500SKK to CZK using c: + final Convertor.ConversionResult r5 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) ); + final MonetaryAmount a5 = r5.getNetAmount(); + // assertEquals("Result is 400 CZK"); + assertNotNull( a5 ); + assertEquals( 400.0, a5.getAmount().doubleValue() ); + assertEquals( CZK, a5.getCurrency() ); + } +}