diff --git a/SaneEconomyCore/src/main/java/org/appledash/saneeconomy/economy/EconomyManager.java b/SaneEconomyCore/src/main/java/org/appledash/saneeconomy/economy/EconomyManager.java
index 268db19..4143dbb 100644
--- a/SaneEconomyCore/src/main/java/org/appledash/saneeconomy/economy/EconomyManager.java
+++ b/SaneEconomyCore/src/main/java/org/appledash/saneeconomy/economy/EconomyManager.java
@@ -29,6 +29,8 @@ public class EconomyManager {
private final Currency currency;
private final EconomyStorageBackend backend;
private final String serverAccountName;
+
+ private static final BigDecimal REQUIRED_BALANCE_ACCURACY = new BigDecimal("0.0001");
public EconomyManager(ISaneEconomy saneEconomy, Currency currency, EconomyStorageBackend backend, String serverAccountName) {
this.saneEconomy = saneEconomy;
@@ -84,8 +86,25 @@ public class EconomyManager {
* @return True if they have requiredBalance or more, false otherwise
*/
public boolean hasBalance(Economable targetPlayer, BigDecimal requiredBalance) {
- return (EconomableConsole.isConsole(targetPlayer)) || (this.getBalance(targetPlayer).compareTo(requiredBalance) >= 0);
-
+ return (EconomableConsole.isConsole(targetPlayer)) || (hasBalance(this.getBalance(targetPlayer), requiredBalance));
+ }
+
+ /**
+ * Compare account balance and required balance to a reasonable degree of accuracy.
+ * Visible for testing
+ *
+ * @param accountBalance account balance
+ * @param requiredBalance required balance
+ * @return true if the account has the required balance to some degree of accuracy, false otherwise
+ */
+ public boolean hasBalance(BigDecimal accountBalance, BigDecimal requiredBalance) {
+ if (accountBalance.compareTo(requiredBalance) >= 0) {
+ return true;
+ }
+ // Must compare to degree of accuracy
+ // See https://github.com/AppleDash/SaneEconomy/issues/100
+ BigDecimal difference = requiredBalance.subtract(accountBalance);
+ return difference.compareTo(REQUIRED_BALANCE_ACCURACY) < 0; // difference < PRECISION
}
/**
diff --git a/SaneEconomyCore/src/test/java/org/appledash/saneeconomy/test/EconomyManagerTest.java b/SaneEconomyCore/src/test/java/org/appledash/saneeconomy/test/EconomyManagerTest.java
index feb2a75..ceffa34 100644
--- a/SaneEconomyCore/src/test/java/org/appledash/saneeconomy/test/EconomyManagerTest.java
+++ b/SaneEconomyCore/src/test/java/org/appledash/saneeconomy/test/EconomyManagerTest.java
@@ -18,6 +18,7 @@ import org.junit.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
/**
@@ -117,4 +118,25 @@ public class EconomyManagerTest {
return true;
}
+
+ @Test
+ public void testHasRequiredBalance() {
+ for (int n = 0; n < 20; n++) { // in the absence of Junit 5's @RepeatedTest
+
+ BigDecimal bigDecimal = randomBigDecimal();
+ // We MUST modify the BigDecimal in some way otherwise the test will always succeed
+ // See https://github.com/AppleDash/SaneEconomy/issues/100
+ for (int m = 0; m < 20; m++) {
+ bigDecimal = bigDecimal.add(randomBigDecimal()).subtract(randomBigDecimal());
+ }
+ //
+
+ Assert.assertTrue("Account must have required balance despite loss of precision (repeat " + n + ")",
+ economyManager.hasBalance(bigDecimal, new BigDecimal(bigDecimal.doubleValue())));
+ }
+ }
+
+ private static BigDecimal randomBigDecimal() {
+ return new BigDecimal(ThreadLocalRandom.current().nextDouble());
+ }
}