Commit fde40c63 by Patryk Czarnik

Przeliczanie Walut - implementacja i testy

parent 27ab5d91
...@@ -19,6 +19,21 @@ ...@@ -19,6 +19,21 @@
<version>4.13.2</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.json</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
package waluty;
public interface Pobieranie {
/** Pobiera tabelę z bieżącymi kursami walut.
* Zwraca null w przypadku błędów.
*/
Tabela pobierzBiezaceKursy();
/** Pobiera tabelę z archiwalnymi kursami walut z określonej daty.
* Zwraca null w przypadku błędów, np. wtedy, gdy dla danej daty nie istnieje tabela.
*/
Tabela pobierzArchiwalneKursy(String data);
// Dzięki temu, że od Javy 8 w interfejsach można definiować metody statyczne,
// sam interfejs może słuzyć jako "fabryka obiektów".
static Pobieranie utworz(String rodzaj) {
switch(rodzaj) {
case "xml" : return new PobieranieXML();
case "json": return new PobieranieJSON();
default: throw new IllegalArgumentException("Nieobsługiwany rodzaj pobierania: " + rodzaj);
}
}
}
\ No newline at end of file
package waluty;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDate;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import jakarta.json.JsonValue;
public class PobieranieJSON implements Pobieranie {
private static final String ADRES = "http://api.nbp.pl/api/exchangerates/tables";
public Tabela pobierzBiezaceKursy() {
return pobierzJsonZAdresu(ADRES + "/a/?format=json");
}
public Tabela pobierzArchiwalneKursy(String data) {
return pobierzJsonZAdresu(ADRES + "/a/" + data + "?format=json");
}
private Tabela pobierzJsonZAdresu(String adres) {
try {
URL url = new URL(adres);
try(InputStream input = url.openStream()) {
return wczytajStream(input);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static Tabela wczytajStream(InputStream input) {
try(JsonReader reader = Json.createReader(input)) {
// dokument zawiera [tablicę], a ta tablica zawiera {obiekt}
JsonArray array = reader.readArray();
JsonObject tabela = array.getJsonObject(0);
String typ = tabela.getString("table");
String numer = tabela.getString("no");
LocalDate data = LocalDate.parse(tabela.getString("effectiveDate"));
JsonArray waluty = tabela.getJsonArray("rates");
Tabela wynikowaTabela = new Tabela(typ, numer, data);
for(JsonValue jsonValue : waluty) {
JsonObject jsonObject = jsonValue.asJsonObject();
Waluta waluta = new Waluta(jsonObject.getString("code"),
jsonObject.getString("currency"),
jsonObject.getJsonNumber("mid").bigDecimalValue());
wynikowaTabela.dodajWalute(waluta);
}
return wynikowaTabela;
}
}
}
package waluty;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDate;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class PobieranieXML implements Pobieranie {
private static final String ADRES = "http://api.nbp.pl/api/exchangerates/tables";
/** Pobiera tabelę z bieżącymi kursami walut.
* Zwraca null w przypadku błędów.
*/
public Tabela pobierzBiezaceKursy() {
Document doc = wczytajXmlZAdresu(ADRES + "/a?format=xml");
return tabelaZXml(doc);
}
public Tabela pobierzArchiwalneKursy(String data) {
Document doc = wczytajXmlZAdresu(ADRES + "/A/" + data + "?format=xml");
return tabelaZXml(doc);
}
private Document wczytajXmlZAdresu(String adres) {
// Document Object Model
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
URL url = new URL(adres);
try (InputStream in = url.openStream()) {
return db.parse(in);
}
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
return null;
}
}
private Tabela tabelaZXml(Document doc) {
if (doc == null)
return null;
try {
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
// String numer = xpath.evaluate(
// "/ArrayOfExchangeRatesTable/ExchangeRatesTable/No", doc);
String nazwaTabeli = xpath.evaluate("//Table", doc);
String numerTabeli = xpath.evaluate("//No", doc);
LocalDate data = LocalDate.parse(xpath.evaluate("//EffectiveDate", doc));
Tabela tabela = new Tabela(nazwaTabeli, numerTabeli, data);
NodeList rates = (NodeList) xpath.evaluate("//Rate", doc, XPathConstants.NODESET);
final int n = rates.getLength();
for (int i = 0; i < n; i++) {
Node rate = rates.item(i);
String kod = xpath.evaluate("Code", rate);
String nazwa = xpath.evaluate("Currency", rate);
BigDecimal kurs = new BigDecimal(xpath.evaluate("Mid", rate));
Waluta waluta = new Waluta(kod, nazwa, kurs);
tabela.dodajWalute(waluta);
}
return tabela;
} catch (XPathExpressionException e) {
e.printStackTrace();
return null;
}
}
}
package waluty;
import java.math.BigDecimal;
import java.util.Scanner;
public class PrzelicznikWalutKonsola_v1 {
public static void main(String[] args) {
PobieranieXML pobieranie = new PobieranieXML();
System.out.println("Pobieram aktualne kursy...");
Tabela tabela = pobieranie.pobierzBiezaceKursy();
System.out.println(tabela);
Scanner sc = new Scanner(System.in);
while(true) {
System.out.print("\nPodaj kod waluty: ");
String kod = sc.nextLine().trim().toUpperCase();
if(kod == null || kod.isEmpty())
break;
Waluta waluta = tabela.wyszukaj(kod);
if(waluta == null) {
System.out.println("Nie ma takiej waluty.");
continue;
}
System.out.println("Wybrana waluta: " + waluta.getNazwa());
System.out.println("Aktualny kurs " + waluta.getKurs());
System.out.println();
System.out.print("Podaj kwotę: ");
if(!sc.hasNextBigDecimal()) {
System.out.println("Nieprawidłowa kwota.");
continue;
}
BigDecimal kwota = sc.nextBigDecimal();
sc.nextLine();
System.out.println(kwota + " " + kod + " = "
+ waluta.przeliczNaZlote(kwota) + " PLN");
System.out.println(kwota + " PLN " + " = "
+ waluta.przeliczNaWalute(kwota) + " " + kod);
}
}
}
package waluty;
import java.math.BigDecimal;
import java.util.Scanner;
import org.apache.commons.lang3.StringUtils;
public class PrzelicznikWalutKonsola_v2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Wybierz format komunikacji: xml | json");
String rodzaj = sc.nextLine();
Pobieranie pobieranie = Pobieranie.utworz(rodzaj);
System.out.println("Podaj datę w formacie YYYY-MM-DD lub naciśnij enter, aby pobrać najświeższe kursy.");
String data = sc.nextLine();
Tabela tabela;
if(StringUtils.isBlank(data)) {
System.out.println("Pobieram aktualne kursy...");
tabela = pobieranie.pobierzBiezaceKursy();
} else {
System.out.println("Pobieram kursy archiwalne...");
tabela = pobieranie.pobierzArchiwalneKursy(data);
}
System.out.println(tabela);
while(true) {
System.out.print("\nPodaj kod waluty: ");
String kod = sc.nextLine().trim().toUpperCase();
if(kod == null || kod.isEmpty())
break;
Waluta waluta = tabela.wyszukaj(kod);
if(waluta == null) {
System.out.println("Nie ma takiej waluty.");
continue;
}
System.out.println("Wybrana waluta: " + waluta.getNazwa());
System.out.println("Aktualny kurs " + waluta.getKurs());
System.out.println();
System.out.print("Podaj kwotę: ");
if(!sc.hasNextBigDecimal()) {
System.out.println("Nieprawidłowa kwota.");
continue;
}
BigDecimal kwota = sc.nextBigDecimal();
sc.nextLine();
System.out.println(kwota + " " + kod + " = "
+ waluta.przeliczNaZlote(kwota) + " PLN");
System.out.println(kwota + " PLN " + " = "
+ waluta.przeliczNaWalute(kwota) + " " + kod);
}
}
}
package waluty;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class Tabela {
private final String typ;
private final String numer;
private final LocalDate data;
private final List<Waluta> waluty = new ArrayList<>();
public Tabela(String typ, String numer, LocalDate data) {
this.typ = typ;
this.numer = numer;
this.data = data;
}
public String getTyp() {
return typ;
}
public String getNumer() {
return numer;
}
public LocalDate getData() {
return data;
}
public Collection<Waluta> getWaluty() {
return Collections.unmodifiableList(waluty);
}
@Override
public String toString() {
return "Tabela nr " + numer + " z dnia " + data + ", " + waluty.size() + " walut";
}
public void dodajWalute(Waluta waluta) {
this.waluty.add(waluta);
}
public Waluta wyszukaj(String kod) {
for(Waluta waluta : waluty) {
if(waluta.getKod().equals(kod)) {
return waluta;
}
}
return null;
}
public String[] getKodyWalut() {
return this.waluty.stream()
.map(Waluta::getKod)
.sorted()
.toArray(String[]::new);
}
}
package waluty;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Waluta {
private final String kod;
private final String nazwa;
private final BigDecimal kurs;
public Waluta(String kod, String nazwa, BigDecimal kurs) {
this.kod = kod;
this.nazwa = nazwa;
this.kurs = kurs;
}
public Waluta(String kod, String nazwa, String kurs) {
this(kod, nazwa, new BigDecimal(kurs));
}
public String getKod() {
return kod;
}
public String getNazwa() {
return nazwa;
}
public BigDecimal getKurs() {
return kurs;
}
@Override
public String toString() {
return "Waluta [kod=" + kod + ", nazwa=" + nazwa + ", kurs=" + kurs + "]";
}
public BigDecimal przeliczNaZlote(BigDecimal kwota) {
return kwota.multiply(kurs).setScale(2, RoundingMode.HALF_EVEN);
}
public BigDecimal przeliczNaWalute(BigDecimal kwota) {
return kwota.divide(kurs, 2, RoundingMode.HALF_EVEN);
}
}
package waluty;
import java.time.LocalDate;
import javax.swing.JOptionPane;
public class WyswietlArchiwalneKursyXML {
public static void main(String[] args) {
PobieranieXML pobieranie = new PobieranieXML();
String data = JOptionPane.showInputDialog(null, "Podaj datę w formacie YYYY-MM-DD", LocalDate.now().toString());
Tabela tabela = pobieranie.pobierzArchiwalneKursy(data);
if(tabela == null) {
System.out.println("Nie udało się pobrać. Niewłaściwa data albo problem z siecią.");
} else {
System.out.println("Pobrana tabela: " + tabela);
for (Waluta waluta : tabela.getWaluty()) {
System.out.println( " * " + waluta);
}
}
}
}
package waluty;
public class WyswietlBiezaceKursyJSON {
public static void main(String[] args) {
PobieranieJSON pobieranie = new PobieranieJSON();
Tabela tabela = pobieranie.pobierzBiezaceKursy();
System.out.println("Pobrana tabela: " + tabela);
for (Waluta waluta : tabela.getWaluty()) {
System.out.println( " * " + waluta);
}
}
}
package waluty;
public class WyswietlWszystkieKursy_XML {
public static void main(String[] args) {
System.out.println("Startujemy...");
PobieranieXML pobieranie = new PobieranieXML();
Tabela tabela = pobieranie.pobierzBiezaceKursy();
System.out.println("Mam tabelę: " + tabela);
for(Waluta waluta : tabela.getWaluty()) {
System.out.println(waluta);
}
}
}
package testowanie; package testowanie;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
public class KontoTest { public class KontoTest {
@Test @Test
......
package waluty;
import static org.assertj.core.api.Assertions.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.junit.Test;
import org.junit.Before;
class TabelaTest {
private static final String PRZYKLADOWY_NUMER = "123/A/NBP/2022";
private static final LocalDate PRZYKLADOWA_DATA = LocalDate.of(2022, 9, 30);
private Tabela tabela;
@Before
void setUp() {
tabela = new Tabela("A", PRZYKLADOWY_NUMER, PRZYKLADOWA_DATA);
}
@Test
void testTabela() {
assertThat(tabela.getNumer()).isEqualTo(PRZYKLADOWY_NUMER);
assertThat(tabela.getData()).isEqualTo(PRZYKLADOWA_DATA);
assertThat(tabela.getWaluty()).isEmpty();
}
@Test
void testToString() {
assertThat(tabela).asString().isEqualTo("Tabela nr 123/A/NBP/2022 z dnia 2022-09-30, 0 walut");
}
@Test
void testDodajWalute() {
Waluta dolar = new Waluta("USD", "dolar", new BigDecimal("5.0000"));
Waluta euro = new Waluta("EUR", "euro", new BigDecimal("3.0000"));
tabela.dodajWalute(dolar);
tabela.dodajWalute(euro);
assertThat(tabela.getWaluty())
.hasSize(2)
.containsExactlyInAnyOrder(dolar, euro);
}
@Test
void testWyszukaj() {
Waluta dolar = new Waluta("USD", "dolar", new BigDecimal("5.0000"));
Waluta euro = new Waluta("EUR", "euro", new BigDecimal("3.0000"));
tabela.dodajWalute(dolar);
tabela.dodajWalute(euro);
Waluta znaleziona = tabela.wyszukaj("EUR");
assertThat(znaleziona).isEqualTo(euro);
}
}
package waluty;
import static org.junit.Assert.*;
import org.junit.Test;
import java.math.BigDecimal;
class WalutaTest {
@Test
void testToString() {
Waluta usd = new Waluta("USD", "dolar", new BigDecimal("4.2020"));
assertEquals("USD (dolar): 4.2020", usd.toString());
}
@Test
void testPrzeliczNaZlote() {
Waluta usd = new Waluta("USD", "dolar", new BigDecimal("4.2020"));
BigDecimal kwota = new BigDecimal("100.00");
BigDecimal oczekiwanyWynik = new BigDecimal("420.20");
BigDecimal wynik = usd.przeliczNaZlote(kwota);
assertEquals(oczekiwanyWynik, wynik);
}
@Test
void testPrzeliczNaZlote_Zero() {
Waluta usd = new Waluta("USD", "dolar", new BigDecimal("4.2020"));
BigDecimal wynik = usd.przeliczNaZlote(BigDecimal.ZERO);
BigDecimal oczekiwanyWynik = new BigDecimal("0.00");
assertEquals(oczekiwanyWynik, wynik);
}
@Test
void testPrzeliczNaZlote_Zaokraglanie() {
Waluta waluta = new Waluta("ABC", "przykładowa waluta", new BigDecimal("2.2222"));
BigDecimal kwota = new BigDecimal("3.00");
BigDecimal oczekiwanyWynik = new BigDecimal("6.67");
BigDecimal wynik = waluta.przeliczNaZlote(kwota);
assertEquals(oczekiwanyWynik, wynik);
}
@Test
void testPrzeliczNaWalute() {
Waluta usd = new Waluta("USD", "dolar", new BigDecimal("4.2020"));
BigDecimal kwota = new BigDecimal("420.20");
BigDecimal oczekiwanyWynik = new BigDecimal("100.00");
BigDecimal wynik = usd.przeliczNaWalute(kwota);
assertEquals(oczekiwanyWynik, wynik);
}
@Test
void testPrzeliczNaWalute_Zaokraglanie() {
Waluta usd = new Waluta("ABC", "przykładowa waluta", new BigDecimal("3.0000"));
BigDecimal kwota = new BigDecimal("200.00");
BigDecimal oczekiwanyWynik = new BigDecimal("66.67");
BigDecimal wynik = usd.przeliczNaWalute(kwota);
assertEquals(oczekiwanyWynik, wynik);
}
}
package waluty;
// import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;
import java.math.BigDecimal;
import org.junit.Test;
import org.junit.Before;
class WalutaTestAssertJ {
private Waluta dolar;
private Waluta euro;
private Waluta peso;
@Before
void setUp() {
dolar = new Waluta("USD", "dolar", new BigDecimal("5.0000"));
euro = new Waluta("EUR", "euro", new BigDecimal("3.0000"));
peso = new Waluta("MXN", "peso", new BigDecimal("0.3333"));
}
@Test
void testWaluta() {
// asercje w stylu JUnit:
// assertEquals("USD", dolar.getKod());
// asersje w stylu AssertJ:
assertThat(dolar.getKod()).isEqualTo("USD");
// tylko prezentacja ciekawych asercji (akurat tutaj dla String)
assertThat(dolar.getKod())
.isNotNull()
.hasSize(3)
.isUpperCase()
.startsWith("U")
.endsWith("D");
}
@Test
void testToString() {
// assertEquals("USD (dolar): 5.0000", dolar.toString());
assertThat(dolar.toString()).isEqualTo("USD (dolar): 5.0000");
assertThat(euro.toString()).isEqualTo("EUR (euro): 3.0000");
}
@Test
void testPrzeliczNaZlote() {
BigDecimal sto = new BigDecimal("100.00");
BigDecimal wynik = dolar.przeliczNaZlote(sto);
assertThat(wynik).isEqualTo("500.00");
}
@Test
void testPrzeliczNaZloteZaokr() {
BigDecimal dwa = new BigDecimal("2.00");
BigDecimal wynik = peso.przeliczNaZlote(dwa);
assertThat(wynik).isEqualTo("0.67");
}
@Test
void testPrzeliczNaWalute() {
BigDecimal piescset = new BigDecimal("500.00");
BigDecimal wynik = dolar.przeliczNaWalute(piescset);
assertThat(wynik).isEqualTo("100.00");
}
@Test
void testPrzeliczNaWaluteZaokr() {
BigDecimal tysiac = new BigDecimal("2000.00");
BigDecimal wynik = euro.przeliczNaWalute(tysiac);
assertThat(wynik).isEqualTo("666.67");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment