Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.skyblockexp.ezeconomy.feature;

import com.skyblockexp.ezeconomy.core.EzEconomyPlugin;
import com.skyblockexp.ezeconomy.feature.support.TestSupport;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockbukkit.mockbukkit.MockBukkit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class BankTransferBalanceFeatureTest {
private Object server;
private EzEconomyPlugin plugin;
private TestSupport.MockStorage storage;

@BeforeEach
void setup() throws Exception {
server = MockBukkit.mock();
plugin = MockBukkit.load(EzEconomyPlugin.class);
storage = new TestSupport.MockStorage();
TestSupport.injectField(plugin, "storage", storage);
plugin.loadMessageProvider();
}

@AfterEach
void teardown() {
MockBukkit.unmock();
}

@Test
void bankDepositAndWithdrawMovePlayerWalletBalance() throws Exception {
Object ownerObj = server.getClass().getMethod("addPlayer", String.class).invoke(server, "owner_wallet");
org.bukkit.entity.Player owner = (org.bukkit.entity.Player) ownerObj;
owner.setOp(true);

Object memberObj = server.getClass().getMethod("addPlayer", String.class).invoke(server, "member_wallet");
org.bukkit.entity.Player member = (org.bukkit.entity.Player) memberObj;
member.setOp(true);

String currency = plugin.getDefaultCurrency();
storage.setBalance(owner.getUniqueId(), currency, 200.0);
storage.setBalance(member.getUniqueId(), currency, 0.0);

assertTrue(owner.performCommand("bank create teamwallet"));
assertTrue(owner.performCommand("bank deposit teamwallet 100"));
assertEquals(100.0, storage.getBankBalance("teamwallet", currency), 0.0001);
assertEquals(100.0, storage.getBalance(owner.getUniqueId(), currency), 0.0001);

assertTrue(owner.performCommand("bank addmember teamwallet member_wallet"));
assertTrue(member.performCommand("bank withdraw teamwallet 25"));
assertEquals(75.0, storage.getBankBalance("teamwallet", currency), 0.0001);
assertEquals(25.0, storage.getBalance(member.getUniqueId(), currency), 0.0001);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ public void onEnable() {
getServer().getPluginManager().disablePlugin(this);
return;
}
org.bukkit.plugin.Plugin ezEconomy = Bukkit.getPluginManager().getPlugin("EzEconomy");
if (ezEconomy == null || !ezEconomy.isEnabled()) {
getLogger().warning("EzEconomy is not enabled; disabling EzEconomy-PAPI expansion.");
getServer().getPluginManager().disablePlugin(this);
return;
}

// Register the expansion
new EzEconomyPAPIExpansion(this).register();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ServiceLoader;
import java.util.Iterator;
import java.io.IOException;
import java.util.function.Supplier;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
Expand Down Expand Up @@ -54,10 +55,8 @@ public void start() {
boolean fallback = bungeeCfg.getBoolean("fallback-to-local", true);
try {
// 1) Try ServiceLoader using current classloader (useful for development/classpath-loaded providers)
ServiceLoader<LockManager> loader = ServiceLoader.load(LockManager.class);
Iterator<LockManager> it = loader.iterator();
if (it.hasNext()) {
this.manager = it.next();
this.manager = safeLoadFirstLockManager(() -> ServiceLoader.load(LockManager.class).iterator(), "current classloader");
if (this.manager != null) {
plugin.getLogger().info("Loaded LockManager via ServiceLoader: " + this.manager.getClass().getName());
}

Expand All @@ -69,10 +68,8 @@ public void start() {
if (jars != null) {
for (File jar : jars) {
try (URLClassLoader cl = new URLClassLoader(new URL[]{jar.toURI().toURL()}, this.getClass().getClassLoader())) {
ServiceLoader<LockManager> sl = ServiceLoader.load(LockManager.class, cl);
Iterator<LockManager> sit = sl.iterator();
if (sit.hasNext()) {
this.manager = sit.next();
this.manager = safeLoadFirstLockManager(() -> ServiceLoader.load(LockManager.class, cl).iterator(), "jar " + jar.getName());
if (this.manager != null) {
plugin.getLogger().info("Loaded LockManager from " + jar.getName() + ": " + this.manager.getClass().getName());
break;
}
Expand Down Expand Up @@ -137,10 +134,8 @@ public void start() {
boolean fallback = redisCfg.getBoolean("fallback-to-local", true);
try {
// 1) Try ServiceLoader using current classloader (useful for development/classpath-loaded providers)
ServiceLoader<LockManager> loader = ServiceLoader.load(LockManager.class);
Iterator<LockManager> it = loader.iterator();
if (it.hasNext()) {
this.manager = it.next();
this.manager = safeLoadFirstLockManager(() -> ServiceLoader.load(LockManager.class).iterator(), "current classloader");
if (this.manager != null) {
plugin.getLogger().info("Loaded LockManager via ServiceLoader: " + this.manager.getClass().getName());
}

Expand All @@ -152,10 +147,8 @@ public void start() {
if (jars != null) {
for (File jar : jars) {
try (URLClassLoader cl = new URLClassLoader(new URL[]{jar.toURI().toURL()}, this.getClass().getClassLoader())) {
ServiceLoader<LockManager> sl = ServiceLoader.load(LockManager.class, cl);
Iterator<LockManager> sit = sl.iterator();
if (sit.hasNext()) {
this.manager = sit.next();
this.manager = safeLoadFirstLockManager(() -> ServiceLoader.load(LockManager.class, cl).iterator(), "jar " + jar.getName());
if (this.manager != null) {
plugin.getLogger().info("Loaded LockManager from " + jar.getName() + ": " + this.manager.getClass().getName());
break;
}
Expand Down Expand Up @@ -197,6 +190,18 @@ public void start() {
plugin.setLockManager(this.manager);
}

private LockManager safeLoadFirstLockManager(Supplier<Iterator<LockManager>> iteratorSupplier, String source) {
try {
Iterator<LockManager> it = iteratorSupplier.get();
if (it != null && it.hasNext()) {
return it.next();
}
} catch (Throwable t) {
plugin.getLogger().warning("Ignoring invalid LockManager provider from " + source + ": " + t.getMessage());
}
return null;
}

@Override
public void stop() {
plugin.setLockManager(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.skyblockexp.ezeconomy.command.bank;

import com.skyblockexp.ezeconomy.command.Subcommand;
import com.skyblockexp.ezeconomy.core.EzEconomyPlugin;
import com.skyblockexp.ezeconomy.util.NumberUtil;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.command.CommandSender;
import com.skyblockexp.ezeconomy.command.Subcommand;
import com.skyblockexp.ezeconomy.core.EzEconomyPlugin;
import com.skyblockexp.ezeconomy.util.NumberUtil;
import com.skyblockexp.ezeconomy.api.storage.StorageProvider;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.command.CommandSender;

/**
* Subcommand for /bank deposit <name> <amount> [currency]
Expand Down Expand Up @@ -33,29 +34,45 @@ public boolean execute(CommandSender sender, String[] args) {
final String bankName;
final String amountStr;
final String currency;
if (args.length == 1) {
if (!(sender instanceof org.bukkit.entity.Player)) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "only_players");
return true;
}
bankName = sender.getName();
amountStr = args[0];
currency = "dollar";
} else {
bankName = args[0];
amountStr = args[1];
currency = args.length >= 3 ? args[2] : "dollar";
}
if (args.length == 1) {
if (!(sender instanceof org.bukkit.entity.Player)) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "only_players");
return true;
}
bankName = sender.getName();
amountStr = args[0];
currency = plugin.getDefaultCurrency();
} else {
bankName = args[0];
amountStr = args[1];
currency = args.length >= 3 ? args[2] : plugin.getDefaultCurrency();
}

Double amount = NumberUtil.parseDouble(amountStr);
if (amount == null || amount <= 0) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "invalid_amount");
return true;
}
EconomyResponse depositResponse = plugin.getEconomy().bankDeposit(bankName, currency, amount);
if (handleEconomyFailure(sender, depositResponse, bankName)) {
return true;
}
StorageProvider storage = plugin.getStorageOrWarn();
if (storage == null) return true;

boolean walletDebited = false;
org.bukkit.entity.Player playerSender = sender instanceof org.bukkit.entity.Player ? (org.bukkit.entity.Player) sender : null;
if (playerSender != null) {
walletDebited = storage.tryWithdraw(playerSender.getUniqueId(), currency, amount);
if (!walletDebited) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "not_enough_money");
return true;
}
}

EconomyResponse depositResponse = plugin.getEconomy().bankDeposit(bankName, currency, amount);
if (handleEconomyFailure(sender, depositResponse, bankName)) {
if (walletDebited && playerSender != null) {
storage.deposit(playerSender.getUniqueId(), currency, amount);
}
return true;
}
String formattedAmount = plugin.getCurrencyFormatter().formatPriceForMessage(amount, currency);
java.util.HashMap<String, String> placeholders = new java.util.HashMap<>();
placeholders.put("name", bankName);
Expand All @@ -79,4 +96,4 @@ private boolean handleEconomyFailure(CommandSender sender, EconomyResponse respo
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.skyblockexp.ezeconomy.command.bank;

import com.skyblockexp.ezeconomy.command.Subcommand;
import com.skyblockexp.ezeconomy.core.EzEconomyPlugin;
import com.skyblockexp.ezeconomy.util.NumberUtil;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.command.CommandSender;
import com.skyblockexp.ezeconomy.command.Subcommand;
import com.skyblockexp.ezeconomy.core.EzEconomyPlugin;
import com.skyblockexp.ezeconomy.util.NumberUtil;
import com.skyblockexp.ezeconomy.api.storage.StorageProvider;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.command.CommandSender;

/**
* Subcommand for /bank withdraw <name> <amount> [currency]
Expand Down Expand Up @@ -33,30 +34,45 @@ public boolean execute(CommandSender sender, String[] args) {
final String bankName;
final String amountStr;
final String currency;
if (args.length == 1) {
if (!(sender instanceof org.bukkit.entity.Player)) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "only_players");
return true;
}
bankName = sender.getName();
amountStr = args[0];
currency = "dollar";
} else {
bankName = args[0];
amountStr = args[1];
currency = args.length >= 3 ? args[2] : "dollar";
}
if (args.length == 1) {
if (!(sender instanceof org.bukkit.entity.Player)) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "only_players");
return true;
}
bankName = sender.getName();
amountStr = args[0];
currency = plugin.getDefaultCurrency();
} else {
bankName = args[0];
amountStr = args[1];
currency = args.length >= 3 ? args[2] : plugin.getDefaultCurrency();
}

Double amount = NumberUtil.parseDouble(amountStr);
if (amount == null || amount <= 0) {
com.skyblockexp.ezeconomy.util.MessageUtils.send(sender, plugin, "invalid_amount");
return true;
}
EconomyResponse withdrawResponse = plugin.getEconomy().bankWithdraw(bankName, currency, amount);
if (handleEconomyFailure(sender, withdrawResponse, bankName)) {
return true;
}
String formattedAmount = plugin.getCurrencyFormatter().formatPriceForMessage(amount, currency);
EconomyResponse withdrawResponse = plugin.getEconomy().bankWithdraw(bankName, currency, amount);
if (handleEconomyFailure(sender, withdrawResponse, bankName)) {
return true;
}

StorageProvider storage = plugin.getStorageOrWarn();
if (storage == null) return true;
org.bukkit.entity.Player playerSender = sender instanceof org.bukkit.entity.Player ? (org.bukkit.entity.Player) sender : null;
if (playerSender != null) {
try {
storage.deposit(playerSender.getUniqueId(), currency, amount);
} catch (Exception ex) {
// Roll back the bank withdrawal if wallet credit fails unexpectedly.
storage.depositBank(bankName, currency, amount);
sender.sendMessage(com.skyblockexp.ezeconomy.util.MessageUtils.color(plugin, "Bank operation failed."));
return true;
}
}

String formattedAmount = plugin.getCurrencyFormatter().formatPriceForMessage(amount, currency);
java.util.HashMap<String, String> placeholders = new java.util.HashMap<>();
placeholders.put("name", bankName);
placeholders.put("amount", formattedAmount);
Expand All @@ -81,4 +97,4 @@ private boolean handleEconomyFailure(CommandSender sender, EconomyResponse respo
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public void testBankDepositWithdraw_ownerAndMemberFlow() throws Exception {
// use shared MockStorage to back bank operations
MockStorage storage = new MockStorage();
TestSupport.injectField(plugin, "storage", storage);
storage.setBalance(owner.getUniqueId(), plugin.getDefaultCurrency(), 200.0);
storage.setBalance(member.getUniqueId(), plugin.getDefaultCurrency(), 0.0);

// owner creates bank
boolean create = owner.performCommand("bank create mybank");
Expand All @@ -64,6 +66,7 @@ public void testBankDepositWithdraw_ownerAndMemberFlow() throws Exception {
// check bank balance via storage
double bal = storage.getBankBalance("mybank", plugin.getDefaultCurrency());
assertEquals(100.0, bal, 0.001);
assertEquals(100.0, storage.getBalance(owner.getUniqueId(), plugin.getDefaultCurrency()), 0.001);

// add member and withdraw
boolean added = owner.performCommand("bank addmember mybank member");
Expand All @@ -75,6 +78,7 @@ public void testBankDepositWithdraw_ownerAndMemberFlow() throws Exception {

double bal2 = storage.getBankBalance("mybank", plugin.getDefaultCurrency());
assertEquals(75.0, bal2, 0.001);
assertEquals(25.0, storage.getBalance(member.getUniqueId(), plugin.getDefaultCurrency()), 0.001);
}

@Test
Expand All @@ -89,6 +93,7 @@ public void testBank_withYMLStorage_persistsBankBalances() throws Exception {

com.skyblockexp.ezeconomy.storage.YMLStorageProvider yml = new com.skyblockexp.ezeconomy.storage.YMLStorageProvider(plugin, cfg);
TestSupport.injectField(plugin, "storage", yml);
yml.setBalance(owner.getUniqueId(), plugin.getDefaultCurrency(), 400.0);

boolean create = owner.performCommand("bank create ybank");
assertTrue(create);
Expand All @@ -98,6 +103,7 @@ public void testBank_withYMLStorage_persistsBankBalances() throws Exception {

double bal = yml.getBankBalance("ybank", plugin.getDefaultCurrency());
org.junit.jupiter.api.Assertions.assertEquals(200.0, bal, 0.001);
org.junit.jupiter.api.Assertions.assertEquals(200.0, yml.getBalance(owner.getUniqueId(), plugin.getDefaultCurrency()), 0.001);

TestSupport.cleanupTestDataFolder(plugin, "test-bank-yml");
}
Expand Down
Loading