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