task4/solution07/test/org/apidesign/apifest08/test/Task4Test.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 17 Oct 2008 17:33:32 +0200
changeset 65 8482e36a7ad2
parent 62 f711ecd374f3
permissions -rw-r--r--
solution 7, task4
     1 package org.apidesign.apifest08.test;
     2 
     3 import org.apidesign.apifest08.currency.TimeRangeSpecificConvertor;
     4 import java.text.DateFormat;
     5 import java.text.ParseException;
     6 import java.text.SimpleDateFormat;
     7 import java.util.Currency;
     8 import java.util.Date;
     9 import junit.framework.TestCase;
    10 import org.apidesign.apifest08.currency.ConversionRate;
    11 import org.apidesign.apifest08.currency.Convertor;
    12 import org.apidesign.apifest08.currency.Convertor.ConversionResult;
    13 import org.apidesign.apifest08.currency.MonetaryAmount;
    14 import org.apidesign.apifest08.currency.TableConvertor;
    15 import org.apidesign.apifest08.currency.TimeRangeSpecificConvertor.TimeSpecificConversionRequest;
    16 
    17 /** The exchange rates are not always the same. They are changing. However
    18  * as in order to predict the future, one needs to understand own past. That is
    19  * why it is important to know the exchange rate as it was at any time during
    20  * the past.
    21  * <p>
    22  * Today's quest is to enhance the convertor API to deal with dates.
    23  * One shall be able to convert a currency at any date. Each currencies rate shall
    24  * be associated with a range between two Date objects. In order
    25  * to keep compatibility with old API that knew nothing about dates, the
    26  * rates associated then are applicable "for eternity". Any use of existing
    27  * convert methods that do not accept a Date argument, uses the current
    28  * System.currentTimeMillis() as default date.
    29  */
    30 public class Task4Test extends TestCase {
    31     public Task4Test(String testName) {
    32         super(testName);
    33     }
    34 
    35     @Override
    36     protected void setUp() throws Exception {
    37     }
    38 
    39     @Override
    40     protected void tearDown() throws Exception {
    41     }
    42 
    43     protected static final Currency CZK = Currency.getInstance( "CZK" );
    44     protected static final Currency SKK = Currency.getInstance( "SKK" );
    45     protected static final Currency USD = Currency.getInstance( "USD" );
    46 
    47     // Backward compatibly enhance your existing API to support following
    48     // usecases:
    49     //
    50 
    51     /** Takes a convertor with any rates associated and creates new convertor
    52      * that returns the same values as the old one for time between from to till.
    53      * Otherwise it returns no results. This is just a helper method that
    54      * shall call some real one in the API.
    55      * 
    56      * @param old existing convertor
    57      * @param from initial date (inclusive); null means since the Big Bang
    58      * @param till final date (exclusive); null means until the End of Universe
    59      * @return new convertor
    60      */
    61     public static Convertor limitTo( final Convertor old, final Date from, final Date till ) {
    62         return new TimeRangeSpecificConvertor( old, from, till );
    63     }
    64         
    65     private static final DateFormat DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd HH:mm Z" );
    66     
    67     protected static Date parseGmtDate( final String string ) {
    68         final String zonedString = string + " GMT+0:00";
    69         try {
    70             return DATE_FORMAT.parse( zonedString );
    71         } catch ( final ParseException ex ) {
    72             throw new IllegalArgumentException( "Cannot parse " + zonedString, ex );
    73         }
    74     }
    75 
    76     public void testCompositionOfLimitedConvertors() throws Exception {
    77         final Date d1 = parseGmtDate( "2008-10-01 0:00" );
    78         final Date d2 = parseGmtDate( "2008-10-02 0:00" );
    79         final Date d3 = parseGmtDate( "2008-10-03 0:00" );
    80         
    81         final Convertor c = Task2Test.merge(
    82             limitTo(Task1Test.createCZKtoUSD(), d1, d2),
    83             limitTo(Task1Test.createSKKtoCZK(), d2, d3)
    84         );
    85 
    86         // convert $5 to CZK using c:
    87         final ConversionResult r1 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
    88         final MonetaryAmount a1 = r1.getNetAmount();
    89         // cannot convert as no rate is applicable to current date
    90         assertNull( a1 );
    91 
    92         // convert $8 to CZK using c:
    93         final ConversionResult r2 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
    94         final MonetaryAmount a2 = r2.getNetAmount();
    95         // cannot convert as no rate is applicable to current date
    96         assertNull( a2 );
    97 
    98         // convert 1003CZK to USD using c:
    99         final ConversionResult r3 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 1003, CZK ), USD ) );
   100         final MonetaryAmount a3 = r3.getNetAmount();
   101         // cannot convert as no rate is applicable to current date
   102         assertNull( a3 );
   103 
   104         // convert 16CZK using c:
   105         final ConversionResult r4 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 16, CZK ), USD ) );
   106         final MonetaryAmount a4 = r4.getNetAmount();
   107         // cannot convert as no rate is applicable to current date
   108         assertNull( a4 );
   109 
   110         // convert 500SKK to CZK using c:
   111         final ConversionResult r5 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
   112         final MonetaryAmount a5 = r5.getNetAmount();
   113         // cannot convert as no rate is applicable to current date
   114         assertNull( a5 );
   115 
   116         // convert $5 to CZK using c at 2008-10-01 6:00 GMT:
   117         final ConversionResult r6 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 5, USD ), CZK, parseGmtDate( "2008-10-01 6:00" ) ) );
   118         final MonetaryAmount a6 = r6.getNetAmount();
   119         // assertEquals("Result is 85 CZK");
   120         assertNotNull( a6 );
   121         assertEquals( 85.0, a6.getAmount().doubleValue() );
   122         assertEquals( CZK, a6.getCurrency() );
   123 
   124         // convert $8 to CZK using c at 2008-10-01 6:00 GMT:
   125         final ConversionResult r7 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 8, USD ), CZK, parseGmtDate( "2008-10-01 6:00" ) ) );
   126         final MonetaryAmount a7 = r7.getNetAmount();
   127         // assertEquals("Result is 136 CZK");
   128         assertNotNull( a7 );
   129         assertEquals( 136.0, a7.getAmount().doubleValue() );
   130         assertEquals( CZK, a7.getCurrency() );
   131 
   132         // convert 1003CZK to USD using c at 2008-10-01 6:00 GMT:
   133         final ConversionResult r8 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 1003, CZK ), USD, parseGmtDate( "2008-10-01 6:00" ) ) );
   134         final MonetaryAmount a8 = r8.getNetAmount();
   135         // assertEquals("Result is 59 USD");
   136         assertNotNull( a8 );
   137         assertEquals( 59.0, a8.getAmount().doubleValue() );
   138         assertEquals( USD, a8.getCurrency() );
   139 
   140         // convert 16CZK using c at 2008-10-02 9:00 GMT:
   141         final ConversionResult r9 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 16, CZK ), SKK, parseGmtDate( "2008-10-02 9:00" ) ) );
   142         final MonetaryAmount a9 = r9.getNetAmount();
   143         // assertEquals("Result is 20 SKK");
   144         assertNotNull( a9 );
   145         assertEquals( 20.0, a9.getAmount().doubleValue() );
   146         assertEquals( SKK, a9.getCurrency() );
   147 
   148         // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT:
   149         final ConversionResult r10 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 500, SKK ), CZK, parseGmtDate( "2008-10-02 9:00" ) ) );
   150         final MonetaryAmount a10 = r10.getNetAmount();
   151         // assertEquals("Result is 400 CZK");
   152         assertNotNull( a10 );
   153         assertEquals( 400.0, a10.getAmount().doubleValue() );
   154         assertEquals( CZK, a10.getCurrency() );
   155 
   156         // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT:
   157         final ConversionResult r11 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 500, SKK ), CZK, parseGmtDate( "2008-10-01 6:00" ) ) );
   158         final MonetaryAmount a11 = r11.getNetAmount();
   159         // cannot convert as no rate is applicable to current date
   160         assertNull( a11 );
   161     }
   162 
   163     /** Create convertor that understands two currencies, CZK and
   164      *  SKK. Make 100 SKK == 90 CZK.
   165      *
   166      * @return prepared convertor ready for converting SKK to CZK and CZK to SKK
   167      */
   168     public static Convertor createSKKtoCZK2() {
   169         final TableConvertor convertor = new TableConvertor();
   170         final MonetaryAmount amountInSKK = new MonetaryAmount( 100, SKK );
   171         final MonetaryAmount amountInCZK = new MonetaryAmount( 90, CZK );
   172         convertor.putIntoTable( new ConversionRate( amountInSKK, amountInCZK ) );
   173         convertor.putIntoTable( new ConversionRate( amountInCZK, amountInSKK ) );
   174         return new ContractImposingDelegatingConvertor( convertor ).test();
   175     }
   176 
   177     public void testDateConvetorWithTwoDifferentRates() throws Exception {
   178         final Date d1 = parseGmtDate( "2008-10-01 0:00" );
   179         final Date d2 = parseGmtDate( "2008-10-02 0:00" );
   180         final Date d3 = parseGmtDate( "2008-10-03 0:00" );
   181 
   182         final Convertor c = Task2Test.merge(
   183             limitTo(createSKKtoCZK2(), d1, d2),
   184             limitTo(Task1Test.createSKKtoCZK(), d2, d3)
   185         );
   186 
   187         // convert 500SKK to CZK using c at 2008-10-02 9:00 GMT:
   188         final ConversionResult r1 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 500, SKK ), CZK, parseGmtDate( "2008-10-02 9:00" ) ) );
   189         final MonetaryAmount a1 = r1.getNetAmount();
   190         // assertEquals("Result is 400 CZK");
   191         assertNotNull( a1 );
   192         assertEquals( 400.0, a1.getAmount().doubleValue() );
   193         assertEquals( CZK, a1.getCurrency() );
   194 
   195         // convert 500SKK to CZK using c at 2008-10-01 6:00 GMT:
   196         final ConversionResult r2 = c.convert( new TimeSpecificConversionRequest( new MonetaryAmount( 500, SKK ), CZK, parseGmtDate( "2008-10-01 6:00" ) ) );
   197         final MonetaryAmount a2 = r2.getNetAmount();
   198         // assertEquals("Result is 450 CZK");
   199         assertNotNull( a2 );
   200         assertEquals( 450.0, a2.getAmount().doubleValue() );
   201         assertEquals( CZK, a2.getCurrency() );        
   202     }
   203 
   204 }