diff --git a/baseline.xml b/baseline.xml
index 7566107..c4d9ac8 100644
--- a/baseline.xml
+++ b/baseline.xml
@@ -2,6 +2,7 @@
- ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String
+ ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$ @JvmStatic @JvmOverloads @Throws(CryptoException::class, IOException::class) fun apiCall(paths: List<String>, params: Map<String, String> = emptyMap()): String
+ ThrowsCount:CryptoPrice.kt$CryptoPrice.Companion$@JvmStatic @Throws(CryptoException::class) fun String.toPrice(): CryptoPrice
diff --git a/examples/src/main/java/com/example/CryptoPriceSample.java b/examples/src/main/java/com/example/CryptoPriceSample.java
index 68b897b..9ff5423 100644
--- a/examples/src/main/java/com/example/CryptoPriceSample.java
+++ b/examples/src/main/java/com/example/CryptoPriceSample.java
@@ -3,6 +3,7 @@ package com.example;
import net.thauvin.erik.crypto.CryptoPrice;
import net.thauvin.erik.crypto.CryptoException;
+import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -35,7 +36,7 @@ public class CryptoPriceSample {
final CryptoPrice gbpPrice = CryptoPrice.marketPrice("ETH", "GBP");
System.out.println("The current Ethereum price is " + gbpPrice.getAmount() + " in Pound sterling");
- } catch (CryptoException e) {
+ } catch (CryptoException | IOException e) {
System.err.println(e.getMessage());
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt b/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt
index 20af110..332851d 100644
--- a/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt
+++ b/src/main/kotlin/net/thauvin/erik/crypto/CryptoPrice.kt
@@ -35,7 +35,9 @@ package net.thauvin.erik.crypto
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
+import org.json.JSONException
import org.json.JSONObject
+import java.io.IOException
import java.time.LocalDate
/**
@@ -49,15 +51,21 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
@JvmStatic
@Throws(CryptoException::class)
fun String.toPrice(): CryptoPrice {
- val json = JSONObject(this)
- if (json.has("data")) {
- with(json.getJSONObject("data")) {
- return CryptoPrice(
- getString("base"), getString("currency"), getString("amount").toDouble()
- )
+ try {
+ val json = JSONObject(this)
+ if (json.has("data")) {
+ with(json.getJSONObject("data")) {
+ return CryptoPrice(
+ getString("base"), getString("currency"), getString("amount").toDouble()
+ )
+ }
+ } else {
+ throw CryptoException(message = "Missing price data.")
}
- } else {
- throw CryptoException(message = "Missing JSON data.")
+ } catch (e: NumberFormatException) {
+ throw CryptoException(message = "Could not convert price data to number.", cause = e)
+ } catch (e: JSONException) {
+ throw CryptoException(message = "Could not parse price data.", cause = e)
}
}
@@ -66,10 +74,11 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
*/
@JvmStatic
@JvmOverloads
- @Throws(CryptoException::class)
+ @Throws(CryptoException::class, IOException::class)
fun apiCall(paths: List, params: Map = emptyMap()): String {
val client = OkHttpClient()
val url = COINBASE_API_URL.toHttpUrl().newBuilder()
+
paths.forEach {
url.addPathSegment(it)
}
@@ -81,19 +90,19 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
val response = client.newCall(request).execute()
val body = response.body?.string()
if (body != null) {
- val json = JSONObject(body)
- if (!response.isSuccessful) {
- if (json.has("errors")) {
+ try {
+ val json = JSONObject(body)
+ if (response.isSuccessful) {
+ return body
+ } else {
val data = json.getJSONArray("errors")
throw CryptoException(response.code, data.getJSONObject(0).getString("message"))
- } else {
- throw CryptoException(response.code, "Invalid API response.")
}
- } else {
- return body
+ } catch (e: JSONException) {
+ throw CryptoException(response.code, "Could not parse data.", e)
}
} else {
- throw CryptoException(response.code, "Empty API response.")
+ throw CryptoException(response.code, "Empty response.")
}
}
@@ -104,11 +113,11 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
}
/**
- * Retrieves the current market price.
+ * Retrieve the current market price.
*/
@JvmStatic
@JvmOverloads
- @Throws(CryptoException::class)
+ @Throws(CryptoException::class, IOException::class)
fun marketPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice {
val params = if (date != null) mapOf("date" to "$date") else emptyMap()
val body = apiCall(listOf("prices", "$base-$currency", "spot"), params)
diff --git a/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt b/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt
index b8f3a61..4df7fd0 100644
--- a/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/crypto/CryptoPriceTest.kt
@@ -74,9 +74,16 @@ class CryptoPriceTest {
@Throws(CryptoException::class)
fun testToPrice() {
val d = 57515.69
- val price = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}".toPrice()
+ val json = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}"
+ val price = json.toPrice()
assertEquals(price.base, "BTC", "base is BTC")
assertEquals(price.currency, "USD", "currency is USD")
assertEquals(price.amount, d, "amount is 57515.69")
+
+ assertFailsWith(
+ message = "double convertion did not fail",
+ exceptionClass = CryptoException::class,
+ block = { json.replace("5", "a").toPrice() }
+ )
}
}