Skip to content

Commit

Permalink
Create tests for UrlCsvZipExchangeRateProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
donfiguerres committed Jun 4, 2023
1 parent c0dd488 commit cb46c72
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import com.europeanexchangerates.exchangeapi.util.dataparser.CsvDataParser;
import com.europeanexchangerates.exchangeapi.util.dataparser.DataParser;

/**
* Fetches data from the European Central Bank's URL and parses it into a
* TreeMap.
*/
public class UrlCsvZipExchangeRateProvider implements ExchangeRateProvider {
private DataDownloader downloader;
private DataParser parser;
Expand All @@ -30,6 +34,12 @@ public UrlCsvZipExchangeRateProvider(DataDownloader downloader, DataParser parse
this.parser = parser;
}

/**
* Fetch the data from the URL and parse it into a TreeMap.
*
* Only one CSV file is expected from the ZIP file. If more than one file
* is found then a warning log message is logged.
*/
public TreeMap<LocalDate, ExchangeRate> getExchangeRates() throws Exception {
InputStream data = downloader.downloadData("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.europeanexchangerates.exchangeapi.provider;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.europeanexchangerates.exchangeapi.dto.ExchangeRate;
import com.europeanexchangerates.exchangeapi.exception.NoDataFromSource;
import com.europeanexchangerates.exchangeapi.util.datadownloader.DataDownloader;
import com.europeanexchangerates.exchangeapi.util.dataparser.DataParser;

@ExtendWith(MockitoExtension.class)
public class UrlCsvZipExchangeRateProviderTest {
private ListAppender<ILoggingEvent> listAppender;
private Logger logger;

@Mock
DataDownloader dataDownloader;

@Mock
DataParser dataParser;

@InjectMocks
UrlCsvZipExchangeRateProvider exchangeRateProvider;

@BeforeEach
void setUp() throws Exception {

TreeMap<LocalDate, ExchangeRate> dummyData = new TreeMap<>() {
{
put(LocalDate.of(2023, 5, 30), new ExchangeRate(new HashMap<>() {
{
put("USD", BigDecimal.valueOf(1.0744));
put("JPY", BigDecimal.valueOf(150.01));
put("BGN", BigDecimal.valueOf(1.9558));
put("GBP", BigDecimal.valueOf(0.86365));
}
}));
}
};

// when(dataParser.parseData(any())).thenReturn(dummyData);

// Get the Logger for the class under test.
logger = (Logger) LoggerFactory.getLogger(UrlCsvZipExchangeRateProvider.class);
listAppender = new ListAppender<>();
listAppender.start();
logger.addAppender(listAppender);
}

@Test
void getExchangeRates_withValidData_returnsNonEmptyMap() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
zos.putNextEntry(new ZipEntry("file1.csv"));
zos.closeEntry();
zos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ZipInputStream zis = new ZipInputStream(bais);

TreeMap<LocalDate, ExchangeRate> expectedRates = new TreeMap<>();
expectedRates.put(LocalDate.now(), new ExchangeRate(null));

when(dataDownloader.downloadData(anyString())).thenReturn(zis);
when(dataParser.parseData(any())).thenReturn(expectedRates);

TreeMap<LocalDate, ExchangeRate> resultRates = exchangeRateProvider.getExchangeRates();

assertEquals(expectedRates, resultRates);
}

@Test
void getExchangeRates_withEmptyData_throwsException() throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
BufferedInputStream bis = new BufferedInputStream(bais);
ZipInputStream zis = new ZipInputStream(bis);

when(dataDownloader.downloadData(anyString())).thenReturn(zis);

assertThrows(NoDataFromSource.class, () -> exchangeRateProvider.getExchangeRates());
}

@Test
void getExchangeRates_multipleFilesInZip_logWarning() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
zos.putNextEntry(new ZipEntry("file1.csv"));
zos.closeEntry();
zos.putNextEntry(new ZipEntry("file2.csv"));
zos.closeEntry();
zos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ZipInputStream zis = new ZipInputStream(bais);

TreeMap<LocalDate, ExchangeRate> expectedRates = new TreeMap<>();
expectedRates.put(LocalDate.now(), new ExchangeRate(null));

when(dataDownloader.downloadData(anyString())).thenReturn(zis);
when(dataParser.parseData(any())).thenReturn(expectedRates);

// Data should still be returned.
TreeMap<LocalDate, ExchangeRate> resultRates = exchangeRateProvider.getExchangeRates();
assertEquals(expectedRates, resultRates);

// Ensure that the warning is logged as this is part of the specified
// behavior for the class.
List<ILoggingEvent> logsList = listAppender.list;
assertFalse(logsList.isEmpty());
assertEquals("The contents of the zip archive has changed. Please check the data source.",
logsList.get(0).getFormattedMessage());
}
}

0 comments on commit cb46c72

Please sign in to comment.