mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-11-02 13:37:24 +00:00
Introduce Fiat as a holder for fiat values. Coin and Fiat share an interface Monetary so that monetary infrastructure can be re-used.
Adapt CoinFormat to be used with Monetary. Add an ExchangeRate value class that can convert from Coin to Fiat and back.
This commit is contained in:
committed by
Mike Hearn
parent
6deba7be92
commit
8e5ab9356c
@@ -27,18 +27,18 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
/**
|
||||
* Represents a monetary Bitcoin value. This class is immutable.
|
||||
*/
|
||||
public final class Coin implements Comparable<Coin>, Serializable {
|
||||
public final class Coin implements Monetary, Comparable<Coin>, Serializable {
|
||||
|
||||
/**
|
||||
* Number of decimals for one Bitcoin. This constant is useful for quick adapting to other coins because a lot of
|
||||
* constants derive from it.
|
||||
*/
|
||||
public static final int NUM_COIN_DECIMALS = 8;
|
||||
public static final int SMALLEST_UNIT_EXPONENT = 8;
|
||||
|
||||
/**
|
||||
* The number of satoshis equal to one bitcoin.
|
||||
*/
|
||||
private static final long COIN_VALUE = LongMath.pow(10, NUM_COIN_DECIMALS);
|
||||
private static final long COIN_VALUE = LongMath.pow(10, SMALLEST_UNIT_EXPONENT);
|
||||
|
||||
/**
|
||||
* Zero Bitcoins.
|
||||
@@ -92,6 +92,19 @@ public final class Coin implements Comparable<Coin>, Serializable {
|
||||
return new Coin(satoshis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int smallestUnitExponent() {
|
||||
return SMALLEST_UNIT_EXPONENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of satoshis of this monetary value.
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an amount expressed in the way humans are used to into satoshis.
|
||||
*/
|
||||
@@ -113,7 +126,7 @@ public final class Coin implements Comparable<Coin>, Serializable {
|
||||
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
|
||||
*/
|
||||
public static Coin parseCoin(final String str) {
|
||||
return Coin.valueOf(new BigDecimal(str).movePointRight(8).toBigIntegerExact().longValue());
|
||||
return Coin.valueOf(new BigDecimal(str).movePointRight(SMALLEST_UNIT_EXPONENT).toBigIntegerExact().longValue());
|
||||
}
|
||||
|
||||
public Coin add(final Coin value) {
|
||||
@@ -188,6 +201,7 @@ public final class Coin implements Comparable<Coin>, Serializable {
|
||||
return new Coin(this.value >> n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int signum() {
|
||||
if (this.value == 0)
|
||||
return 0;
|
||||
|
||||
38
core/src/main/java/com/google/bitcoin/core/Monetary.java
Normal file
38
core/src/main/java/com/google/bitcoin/core/Monetary.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Classes implementing this interface represent a monetary value, such as a Bitcoin or fiat amount.
|
||||
*/
|
||||
public interface Monetary extends Serializable {
|
||||
|
||||
/**
|
||||
* Returns the absolute value of exponent of the value of a "smallest unit" in scientific notation. For Bitcoin, a
|
||||
* satoshi is worth 1E-8 so this would be 8.
|
||||
*/
|
||||
int smallestUnitExponent();
|
||||
|
||||
/**
|
||||
* Returns the number of "smallest units" of this monetary value. For Bitcoin, this would be the number of satoshis.
|
||||
*/
|
||||
long getValue();
|
||||
|
||||
int signum();
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.bitcoin.core.Coin;
|
||||
import com.google.bitcoin.core.Monetary;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -50,6 +51,8 @@ public final class CoinFormat {
|
||||
public static final CoinFormat MBTC = new CoinFormat().shift(3).minDecimals(2).optionalDecimals(2);
|
||||
/** Standard format for the µBTC denomination. */
|
||||
public static final CoinFormat UBTC = new CoinFormat().shift(6).minDecimals(0).optionalDecimals(2);
|
||||
/** Standard format for fiat amounts. */
|
||||
public static final CoinFormat FIAT = new CoinFormat().shift(0).minDecimals(2).repeatOptionalDecimals(2, 1);
|
||||
/** Currency code for base 1 Bitcoin. */
|
||||
public static final String CODE_BTC = "BTC";
|
||||
/** Currency code for base 1/1000 Bitcoin. */
|
||||
@@ -295,26 +298,26 @@ public final class CoinFormat {
|
||||
/**
|
||||
* Format the given value to a human readable form.
|
||||
*/
|
||||
public CharSequence format(Coin coin) {
|
||||
public CharSequence format(Monetary coin) {
|
||||
// preparation
|
||||
int maxDecimals = minDecimals;
|
||||
if (decimalGroups != null)
|
||||
for (int group : decimalGroups)
|
||||
maxDecimals += group;
|
||||
checkState(maxDecimals <= Coin.NUM_COIN_DECIMALS);
|
||||
checkState(maxDecimals <= coin.smallestUnitExponent());
|
||||
|
||||
// rounding
|
||||
long satoshis = Math.abs(coin.value);
|
||||
long precisionDivisor = checkedPow(10, Coin.NUM_COIN_DECIMALS - shift - maxDecimals);
|
||||
long satoshis = Math.abs(coin.getValue());
|
||||
long precisionDivisor = checkedPow(10, coin.smallestUnitExponent() - shift - maxDecimals);
|
||||
satoshis = checkedMultiply(divide(satoshis, precisionDivisor, roundingMode), precisionDivisor);
|
||||
|
||||
// shifting
|
||||
long shiftDivisor = checkedPow(10, Coin.NUM_COIN_DECIMALS - shift);
|
||||
long shiftDivisor = checkedPow(10, coin.smallestUnitExponent() - shift);
|
||||
long numbers = satoshis / shiftDivisor;
|
||||
long decimals = satoshis % shiftDivisor;
|
||||
|
||||
// formatting
|
||||
String decimalsStr = String.format(Locale.US, "%0" + (Coin.NUM_COIN_DECIMALS - shift) + "d", decimals);
|
||||
String decimalsStr = String.format(Locale.US, "%0" + (coin.smallestUnitExponent() - shift) + "d", decimals);
|
||||
StringBuilder str = new StringBuilder(decimalsStr);
|
||||
while (str.length() > minDecimals && str.charAt(str.length() - 1) == '0')
|
||||
str.setLength(str.length() - 1); // trim trailing zero
|
||||
@@ -332,7 +335,7 @@ public final class CoinFormat {
|
||||
if (str.length() > 0)
|
||||
str.insert(0, decimalMark);
|
||||
str.insert(0, numbers);
|
||||
if (coin.value < 0)
|
||||
if (coin.getValue() < 0)
|
||||
str.insert(0, negativeSign);
|
||||
else if (positiveSign != 0)
|
||||
str.insert(0, positiveSign);
|
||||
@@ -355,7 +358,21 @@ public final class CoinFormat {
|
||||
* if the string cannot be parsed for some reason
|
||||
*/
|
||||
public Coin parse(String str) throws NumberFormatException {
|
||||
checkState(DECIMALS_PADDING.length() >= Coin.NUM_COIN_DECIMALS);
|
||||
return Coin.valueOf(parseValue(str, Coin.SMALLEST_UNIT_EXPONENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a human readable fiat value to a {@link com.google.bitcoin.core.Fiat} instance.
|
||||
*
|
||||
* @throws NumberFormatException
|
||||
* if the string cannot be parsed for some reason
|
||||
*/
|
||||
public Fiat parseFiat(String currencyCode, String str) throws NumberFormatException {
|
||||
return Fiat.valueOf(currencyCode, parseValue(str, Fiat.SMALLEST_UNIT_EXPONENT));
|
||||
}
|
||||
|
||||
private long parseValue(String str, int smallestUnitExponent) {
|
||||
checkState(DECIMALS_PADDING.length() >= smallestUnitExponent);
|
||||
if (str.isEmpty())
|
||||
throw new NumberFormatException("empty string");
|
||||
char first = str.charAt(0);
|
||||
@@ -373,14 +390,14 @@ public final class CoinFormat {
|
||||
numbers = str;
|
||||
decimals = DECIMALS_PADDING;
|
||||
}
|
||||
String satoshis = numbers + decimals.substring(0, Coin.NUM_COIN_DECIMALS - shift);
|
||||
String satoshis = numbers + decimals.substring(0, smallestUnitExponent - shift);
|
||||
for (char c : satoshis.toCharArray())
|
||||
if (!Character.isDigit(c))
|
||||
throw new NumberFormatException("illegal character: " + c);
|
||||
Coin coin = Coin.valueOf(Long.parseLong(satoshis));
|
||||
long value = Long.parseLong(satoshis);
|
||||
if (first == negativeSign)
|
||||
coin = coin.negate();
|
||||
return coin;
|
||||
value = -value;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.utils;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import com.google.bitcoin.core.Coin;
|
||||
|
||||
/**
|
||||
* An exchange rate is expressed as a ratio of a {@link Coin} and a {@link Fiat} amount.
|
||||
*/
|
||||
public class ExchangeRate implements Serializable {
|
||||
|
||||
public final Coin coin;
|
||||
public final Fiat fiat;
|
||||
|
||||
public ExchangeRate(Coin coin, Fiat fiat) {
|
||||
this.coin = coin;
|
||||
this.fiat = fiat;
|
||||
}
|
||||
|
||||
public ExchangeRate(Fiat fiat) {
|
||||
this.coin = Coin.COIN;
|
||||
this.fiat = fiat;
|
||||
}
|
||||
|
||||
public Fiat coinToFiat(Coin convertCoin) {
|
||||
// Use BigInteger because it's much easier to maintain full precision without overflowing.
|
||||
final BigInteger converted = BigInteger.valueOf(convertCoin.value).multiply(BigInteger.valueOf(fiat.value))
|
||||
.divide(BigInteger.valueOf(coin.value));
|
||||
if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
|
||||
|| converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0)
|
||||
throw new ArithmeticException("Overflow");
|
||||
return Fiat.valueOf(fiat.currencyCode, converted.longValue());
|
||||
}
|
||||
|
||||
public Coin fiatToCoin(Fiat convertFiat) {
|
||||
checkArgument(convertFiat.currencyCode.equals(fiat.currencyCode), "Currency mismatch: %s vs %s",
|
||||
convertFiat.currencyCode, fiat.currencyCode);
|
||||
// Use BigInteger because it's much easier to maintain full precision without overflowing.
|
||||
final BigInteger converted = BigInteger.valueOf(convertFiat.value).multiply(BigInteger.valueOf(coin.value))
|
||||
.divide(BigInteger.valueOf(fiat.value));
|
||||
if (converted.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
|
||||
|| converted.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0)
|
||||
throw new ArithmeticException("Overflow");
|
||||
return Coin.valueOf(converted.longValue());
|
||||
}
|
||||
}
|
||||
225
core/src/main/java/com/google/bitcoin/utils/Fiat.java
Normal file
225
core/src/main/java/com/google/bitcoin/utils/Fiat.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.utils;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.google.bitcoin.core.Monetary;
|
||||
import com.google.common.math.LongMath;
|
||||
|
||||
/**
|
||||
* Represents a monetary fiat value. It was decided to not fold this into {@link Coin} because of type safety. Fiat
|
||||
* values always come with an attached currency code.
|
||||
*
|
||||
* This class is immutable.
|
||||
*/
|
||||
public final class Fiat implements Monetary, Comparable<Fiat>, Serializable {
|
||||
|
||||
/**
|
||||
* The absolute value of exponent of the value of a "smallest unit" in scientific notation. We picked 4 rather than
|
||||
* 2, because in financial applications it's common to use sub-cent precision.
|
||||
*/
|
||||
public static final int SMALLEST_UNIT_EXPONENT = 4;
|
||||
|
||||
/**
|
||||
* The number of smallest units of this monetary value.
|
||||
*/
|
||||
public final long value;
|
||||
public final String currencyCode;
|
||||
|
||||
private Fiat(final String currencyCode, final long value) {
|
||||
this.value = value;
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
public static Fiat valueOf(final String currencyCode, final long value) {
|
||||
return new Fiat(currencyCode, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int smallestUnitExponent() {
|
||||
return SMALLEST_UNIT_EXPONENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of "smallest units" of this monetary value.
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return currencyCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an amount expressed in the way humans are used to.
|
||||
* <p>
|
||||
* <p/>
|
||||
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)}, for example "0", "1", "0.10",
|
||||
* "1.23E3", "1234.5E-5".
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if you try to specify fractional satoshis, or a value out of range.
|
||||
*/
|
||||
public static Fiat parseFiat(final String currencyCode, final String str) {
|
||||
return Fiat.valueOf(currencyCode, new BigDecimal(str).movePointRight(SMALLEST_UNIT_EXPONENT)
|
||||
.toBigIntegerExact().longValue());
|
||||
}
|
||||
|
||||
public Fiat add(final Fiat value) {
|
||||
checkArgument(value.currencyCode.equals(currencyCode));
|
||||
return new Fiat(currencyCode, LongMath.checkedAdd(this.value, value.value));
|
||||
}
|
||||
|
||||
public Fiat subtract(final Fiat value) {
|
||||
checkArgument(value.currencyCode.equals(currencyCode));
|
||||
return new Fiat(currencyCode, LongMath.checkedSubtract(this.value, value.value));
|
||||
}
|
||||
|
||||
public Fiat multiply(final long factor) {
|
||||
return new Fiat(currencyCode, LongMath.checkedMultiply(this.value, factor));
|
||||
}
|
||||
|
||||
public Fiat divide(final long divisor) {
|
||||
return new Fiat(currencyCode, this.value / divisor);
|
||||
}
|
||||
|
||||
public Fiat[] divideAndRemainder(final long divisor) {
|
||||
return new Fiat[] { new Fiat(currencyCode, this.value / divisor), new Fiat(currencyCode, this.value % divisor) };
|
||||
}
|
||||
|
||||
public long divide(final Fiat divisor) {
|
||||
checkArgument(divisor.currencyCode.equals(currencyCode));
|
||||
return this.value / divisor.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if and only if this instance represents a monetary value greater than zero, otherwise false.
|
||||
*/
|
||||
public boolean isPositive() {
|
||||
return signum() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if and only if this instance represents a monetary value less than zero, otherwise false.
|
||||
*/
|
||||
public boolean isNegative() {
|
||||
return signum() == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if and only if this instance represents zero monetary value, otherwise false.
|
||||
*/
|
||||
public boolean isZero() {
|
||||
return signum() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the monetary value represented by this instance is greater than that of the given other Coin,
|
||||
* otherwise false.
|
||||
*/
|
||||
public boolean isGreaterThan(Fiat other) {
|
||||
return compareTo(other) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the monetary value represented by this instance is less than that of the given other Coin,
|
||||
* otherwise false.
|
||||
*/
|
||||
public boolean isLessThan(Fiat other) {
|
||||
return compareTo(other) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int signum() {
|
||||
if (this.value == 0)
|
||||
return 0;
|
||||
return this.value < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
public Fiat negate() {
|
||||
return new Fiat(currencyCode, -this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of satoshis of this monetary value. It's deprecated in favour of accessing {@link #value}
|
||||
* directly.
|
||||
*/
|
||||
public long longValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
private static final CoinFormat FRIENDLY_FORMAT = CoinFormat.FIAT.postfixCode();
|
||||
|
||||
/**
|
||||
* Returns the value as a 0.12 type string. More digits after the decimal place will be used if necessary, but two
|
||||
* will always be present.
|
||||
*/
|
||||
public String toFriendlyString() {
|
||||
return FRIENDLY_FORMAT.code(0, currencyCode).format(this).toString();
|
||||
}
|
||||
|
||||
private static final CoinFormat PLAIN_FORMAT = CoinFormat.FIAT.minDecimals(0).repeatOptionalDecimals(1, 4).noCode();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the value as a plain string denominated in BTC. The result is unformatted with no trailing zeroes. For
|
||||
* instance, a value of 150000 satoshis gives an output string of "0.0015" BTC
|
||||
* </p>
|
||||
*/
|
||||
public String toPlainString() {
|
||||
return PLAIN_FORMAT.format(this).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Long.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o == this)
|
||||
return true;
|
||||
if (o == null || o.getClass() != getClass())
|
||||
return false;
|
||||
final Fiat other = (Fiat) o;
|
||||
if (this.value != other.value)
|
||||
return false;
|
||||
if (!this.currencyCode.equals(other.currencyCode))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) this.value + 37 * this.currencyCode.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Fiat other) {
|
||||
if (!this.currencyCode.equals(other.currencyCode))
|
||||
return this.currencyCode.compareTo(other.currencyCode);
|
||||
if (this.value != other.value)
|
||||
return this.value > other.value ? 1 : -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -306,4 +306,11 @@ public class CoinFormatTest {
|
||||
public void parseInvalidHugeNegativeNumber() throws Exception {
|
||||
NO_CODE.parse("-99999999999999999999");
|
||||
}
|
||||
|
||||
private static final Fiat ONE_EURO = Fiat.parseFiat("EUR", "1");
|
||||
|
||||
@Test
|
||||
public void fiat() throws Exception {
|
||||
assertEquals(ONE_EURO, NO_CODE.parseFiat("EUR", "1"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.utils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.bitcoin.core.Coin;
|
||||
|
||||
public class ExchangeRateTest {
|
||||
|
||||
@Test
|
||||
public void normalRate() throws Exception {
|
||||
ExchangeRate rate = new ExchangeRate(Fiat.parseFiat("EUR", "500"));
|
||||
assertEquals("0.5", rate.coinToFiat(Coin.MILLICOIN).toPlainString());
|
||||
assertEquals("0.002", rate.fiatToCoin(Fiat.parseFiat("EUR", "1")).toPlainString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bigRate() throws Exception {
|
||||
ExchangeRate rate = new ExchangeRate(Coin.parseCoin("0.0001"), Fiat.parseFiat("BYR", "5320387.3"));
|
||||
assertEquals("53203873000", rate.coinToFiat(Coin.COIN).toPlainString());
|
||||
assertEquals("0", rate.fiatToCoin(Fiat.parseFiat("BYR", "1")).toPlainString()); // Tiny value!
|
||||
}
|
||||
|
||||
@Test
|
||||
public void smallRate() throws Exception {
|
||||
ExchangeRate rate = new ExchangeRate(Coin.parseCoin("1000"), Fiat.parseFiat("XXX", "0.0001"));
|
||||
assertEquals("0", rate.coinToFiat(Coin.COIN).toPlainString()); // Tiny value!
|
||||
assertEquals("10000000", rate.fiatToCoin(Fiat.parseFiat("XXX", "1")).toPlainString());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void currencyCodeMismatch() throws Exception {
|
||||
ExchangeRate rate = new ExchangeRate(Fiat.parseFiat("EUR", "500"));
|
||||
rate.fiatToCoin(Fiat.parseFiat("USD", "1"));
|
||||
}
|
||||
}
|
||||
59
core/src/test/java/com/google/bitcoin/utils/FiatTest.java
Normal file
59
core/src/test/java/com/google/bitcoin/utils/FiatTest.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright 2014 Andreas Schildbach
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.utils;
|
||||
|
||||
import static com.google.bitcoin.utils.Fiat.parseFiat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class FiatTest {
|
||||
|
||||
@Test
|
||||
public void testParseAndValueOf() {
|
||||
assertEquals(Fiat.valueOf("EUR", 10000), parseFiat("EUR", "1"));
|
||||
assertEquals(Fiat.valueOf("EUR", 100), parseFiat("EUR", "0.01"));
|
||||
assertEquals(Fiat.valueOf("EUR", 1), parseFiat("EUR", "0.0001"));
|
||||
assertEquals(Fiat.valueOf("EUR", -10000), parseFiat("EUR", "-1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToFriendlyString() {
|
||||
assertEquals("1.00 EUR", parseFiat("EUR", "1").toFriendlyString());
|
||||
assertEquals("1.23 EUR", parseFiat("EUR", "1.23").toFriendlyString());
|
||||
assertEquals("0.0010 EUR", parseFiat("EUR", "0.001").toFriendlyString());
|
||||
assertEquals("-1.23 EUR", parseFiat("EUR", "-1.23").toFriendlyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToPlainString() {
|
||||
assertEquals("0.0015", Fiat.valueOf("EUR", 15).toPlainString());
|
||||
assertEquals("1.23", parseFiat("EUR", "1.23").toPlainString());
|
||||
|
||||
assertEquals("0.1", parseFiat("EUR", "0.1").toPlainString());
|
||||
assertEquals("1.1", parseFiat("EUR", "1.1").toPlainString());
|
||||
assertEquals("21.12", parseFiat("EUR", "21.12").toPlainString());
|
||||
assertEquals("321.123", parseFiat("EUR", "321.123").toPlainString());
|
||||
assertEquals("4321.1234", parseFiat("EUR", "4321.1234").toPlainString());
|
||||
|
||||
// check there are no trailing zeros
|
||||
assertEquals("1", parseFiat("EUR", "1.0").toPlainString());
|
||||
assertEquals("2", parseFiat("EUR", "2.00").toPlainString());
|
||||
assertEquals("3", parseFiat("EUR", "3.000").toPlainString());
|
||||
assertEquals("4", parseFiat("EUR", "4.0000").toPlainString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user