diff --git a/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java index a979b7bf23..65f8c83f60 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java @@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; +import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -55,4 +56,40 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { assertEquals("UNKNOWN: An error occurred at task: ValidateOffer", exception.getMessage()); } + + @Test + @Order(2) + public void testNoMatchingEURPaymentAccountShouldThrowException() { + PaymentAccount chfAccount = createDummyF2FAccount(aliceClient, "ch"); + @SuppressWarnings("ResultOfMethodCallIgnored") + Throwable exception = assertThrows(StatusRuntimeException.class, () -> + aliceClient.createFixedPricedOffer("buy", + "eur", + 10000000L, + 10000000L, + "40000.0000", + getDefaultBuyerSecurityDepositAsPercent(), + chfAccount.getId(), + "btc")); + String expectedError = format("UNKNOWN: cannot create EUR offer with payment account %s", chfAccount.getId()); + assertEquals(expectedError, exception.getMessage()); + } + + @Test + @Order(2) + public void testNoMatchingCADPaymentAccountShouldThrowException() { + PaymentAccount audAccount = createDummyF2FAccount(aliceClient, "au"); + @SuppressWarnings("ResultOfMethodCallIgnored") + Throwable exception = assertThrows(StatusRuntimeException.class, () -> + aliceClient.createFixedPricedOffer("buy", + "cad", + 10000000L, + 10000000L, + "63000.0000", + getDefaultBuyerSecurityDepositAsPercent(), + audAccount.getId(), + "btc")); + String expectedError = format("UNKNOWN: cannot create CAD offer with payment account %s", audAccount.getId()); + assertEquals(expectedError, exception.getMessage()); + } } diff --git a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java index 44c56f08a0..034bc3aeb0 100644 --- a/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/method/payment/AbstractPaymentAccountTest.java @@ -85,6 +85,7 @@ public class AbstractPaymentAccountTest extends MethodTest { static final String PROPERTY_NAME_SALT = "salt"; static final String PROPERTY_NAME_SORT_CODE = "sortCode"; static final String PROPERTY_NAME_STATE = "state"; + static final String PROPERTY_NAME_TRADE_CURRENCIES = "tradeCurrencies"; static final String PROPERTY_NAME_USERNAME = "userName"; static final Gson GSON = new GsonBuilder() diff --git a/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java index a194c4aa1f..3caef6ee39 100644 --- a/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/method/payment/CreatePaymentAccountTest.java @@ -17,6 +17,7 @@ package bisq.apitest.method.payment; +import bisq.core.locale.TradeCurrency; import bisq.core.payment.AdvancedCashAccount; import bisq.core.payment.AliPayAccount; import bisq.core.payment.AustraliaPayid; @@ -31,6 +32,7 @@ import bisq.core.payment.JapanBankAccount; import bisq.core.payment.MoneyBeamAccount; import bisq.core.payment.MoneyGramAccount; import bisq.core.payment.NationalBankAccount; +import bisq.core.payment.PaymentAccount; import bisq.core.payment.PerfectMoneyAccount; import bisq.core.payment.PopmoneyAccount; import bisq.core.payment.PromptPayAccount; @@ -50,8 +52,12 @@ import bisq.core.payment.payload.CashDepositAccountPayload; import bisq.core.payment.payload.SameBankAccountPayload; import bisq.core.payment.payload.SpecificBanksAccountPayload; +import io.grpc.StatusRuntimeException; + import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import lombok.extern.slf4j.Slf4j; @@ -65,15 +71,16 @@ import org.junit.jupiter.api.TestMethodOrder; import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; import static bisq.apitest.config.BisqAppConfig.alicedaemon; -import static bisq.core.locale.CurrencyUtil.getAllAdvancedCashCurrencies; -import static bisq.core.locale.CurrencyUtil.getAllMoneyGramCurrencies; -import static bisq.core.locale.CurrencyUtil.getAllRevolutCurrencies; -import static bisq.core.locale.CurrencyUtil.getAllUpholdCurrencies; +import static bisq.cli.TableFormat.formatPaymentAcctTbl; +import static bisq.core.locale.CurrencyUtil.*; import static bisq.core.payment.payload.PaymentMethod.*; +import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +@SuppressWarnings({"OptionalGetWithoutIsPresent", "ConstantConditions"}) @Disabled @Slf4j @TestMethodOrder(OrderAnnotation.class) @@ -105,7 +112,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -124,7 +131,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyAccountSingleTradeCurrency("CNY", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -146,7 +153,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_PAY_ID), paymentAccount.getPayid()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BANK_ACCOUNT_NAME), paymentAccount.getBankAccountName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -198,7 +205,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_REQUIREMENTS), payload.getRequirements()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -243,7 +250,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -265,7 +272,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -288,7 +295,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL_OR_MOBILE_NR), paymentAccount.getEmailOrMobileNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -317,7 +324,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_CITY), paymentAccount.getCity()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_CONTACT), paymentAccount.getContact()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EXTRA_INFO), paymentAccount.getExtraInfo()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -340,7 +347,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SORT_CODE), paymentAccount.getSortCode()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -359,7 +366,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyAccountSingleTradeCurrency("EUR", paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_MOBILE_NR), paymentAccount.getMobileNr()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -388,7 +395,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_QUESTION), paymentAccount.getQuestion()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ANSWER), paymentAccount.getAnswer()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -425,7 +432,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BANK_ACCOUNT_NAME), paymentAccount.getBankAccountName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BANK_ACCOUNT_TYPE), paymentAccount.getBankAccountType()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BANK_ACCOUNT_NUMBER), paymentAccount.getBankAccountNumber()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -445,7 +452,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_ID), paymentAccount.getAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -474,7 +481,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_COUNTRY), Objects.requireNonNull(paymentAccount.getCountry()).code); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_STATE), paymentAccount.getState()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -494,7 +501,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -516,7 +523,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_ID), paymentAccount.getAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -536,7 +543,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_PROMPT_PAY_ID), paymentAccount.getPromptPayId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -555,7 +562,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyAccountTradeCurrencies(getAllRevolutCurrencies(), paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_USERNAME), paymentAccount.getUserName()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -600,7 +607,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -631,7 +638,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BIC), paymentAccount.getBic()); // bankId == bic assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BIC), paymentAccount.getBankId()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -663,7 +670,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { // bankId == bic assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_BIC), paymentAccount.getBankId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -710,7 +717,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), payload.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -733,29 +740,104 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_MOBILE_NR), paymentAccount.getMobileNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test - public void testCreateTransferwiseAccount(TestInfo testInfo) { + public void testCreateTransferwiseAccountWith1TradeCurrency(TestInfo testInfo) { File emptyForm = getEmptyForm(testInfo, TRANSFERWISE_ID); verifyEmptyForm(emptyForm, TRANSFERWISE_ID, PROPERTY_NAME_EMAIL); COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, TRANSFERWISE_ID); COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Transferwise Acct"); - COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jan@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_TRADE_CURRENCIES, "eur"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jane@doe.info"); COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); String jsonString = getCompletedFormAsJsonString(); TransferwiseAccount paymentAccount = (TransferwiseAccount) createPaymentAccount(aliceClient, jsonString); verifyUserPayloadHasPaymentAccountWithId(aliceClient, paymentAccount.getId()); - // As per commit 88f26f93241af698ae689bf081205d0f9dc929fa - // Do not autofill all currencies by default but keep all unselected. - // verifyAccountTradeCurrencies(getAllTransferwiseCurrencies(), paymentAccount); - assertEquals(0, paymentAccount.getTradeCurrencies().size()); + assertEquals(1, paymentAccount.getTradeCurrencies().size()); + TradeCurrency expectedCurrency = getTradeCurrency("EUR").get(); + assertEquals(expectedCurrency, paymentAccount.getSelectedTradeCurrency()); + List expectedTradeCurrencies = singletonList(expectedCurrency); + verifyAccountTradeCurrencies(expectedTradeCurrencies, paymentAccount); verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); + } + + @Test + public void testCreateTransferwiseAccountWith10TradeCurrencies(TestInfo testInfo) { + File emptyForm = getEmptyForm(testInfo, TRANSFERWISE_ID); + verifyEmptyForm(emptyForm, + TRANSFERWISE_ID, + PROPERTY_NAME_EMAIL); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, TRANSFERWISE_ID); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Transferwise Acct"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_TRADE_CURRENCIES, "ars, cad, hrk, czk, eur, hkd, idr, jpy, chf, nzd"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jane@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); + String jsonString = getCompletedFormAsJsonString(); + TransferwiseAccount paymentAccount = (TransferwiseAccount) createPaymentAccount(aliceClient, jsonString); + verifyUserPayloadHasPaymentAccountWithId(aliceClient, paymentAccount.getId()); + assertEquals(10, paymentAccount.getTradeCurrencies().size()); + List expectedTradeCurrencies = new ArrayList<>() {{ + add(getTradeCurrency("ARS").get()); // 1st in list = selected ccy + add(getTradeCurrency("CAD").get()); + add(getTradeCurrency("HRK").get()); + add(getTradeCurrency("CZK").get()); + add(getTradeCurrency("EUR").get()); + add(getTradeCurrency("HKD").get()); + add(getTradeCurrency("IDR").get()); + add(getTradeCurrency("JPY").get()); + add(getTradeCurrency("CHF").get()); + add(getTradeCurrency("NZD").get()); + }}; + verifyAccountTradeCurrencies(expectedTradeCurrencies, paymentAccount); + TradeCurrency expectedSelectedCurrency = expectedTradeCurrencies.get(0); + assertEquals(expectedSelectedCurrency, paymentAccount.getSelectedTradeCurrency()); + verifyCommonFormEntries(paymentAccount); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail()); + print(paymentAccount); + } + + @Test + public void testCreateTransferwiseAccountWithInvalidBrlTradeCurrencyShouldThrowException(TestInfo testInfo) { + File emptyForm = getEmptyForm(testInfo, TRANSFERWISE_ID); + verifyEmptyForm(emptyForm, + TRANSFERWISE_ID, + PROPERTY_NAME_EMAIL); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, TRANSFERWISE_ID); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Transferwise Acct"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_TRADE_CURRENCIES, "eur, hkd, idr, jpy, chf, nzd, brl, gbp"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jane@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); + String jsonString = getCompletedFormAsJsonString(); + + Throwable exception = assertThrows(StatusRuntimeException.class, () -> + createPaymentAccount(aliceClient, jsonString)); + assertEquals("INVALID_ARGUMENT: BRL is not a member of valid currencies list", + exception.getMessage()); + } + + @Test + public void testCreateTransferwiseAccountWithoutTradeCurrenciesShouldThrowException(TestInfo testInfo) { + File emptyForm = getEmptyForm(testInfo, TRANSFERWISE_ID); + verifyEmptyForm(emptyForm, + TRANSFERWISE_ID, + PROPERTY_NAME_EMAIL); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_PAYMENT_METHOD_ID, TRANSFERWISE_ID); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_ACCOUNT_NAME, "Transferwise Acct"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_TRADE_CURRENCIES, ""); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_EMAIL, "jane@doe.info"); + COMPLETED_FORM_MAP.put(PROPERTY_NAME_SALT, ""); + String jsonString = getCompletedFormAsJsonString(); + + Throwable exception = assertThrows(StatusRuntimeException.class, () -> + createPaymentAccount(aliceClient, jsonString)); + assertEquals("INVALID_ARGUMENT: no trade currencies defined for transferwise payment account", + exception.getMessage()); } @Test @@ -775,7 +857,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_ID), paymentAccount.getAccountId()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -797,7 +879,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_POSTAL_ADDRESS), paymentAccount.getPostalAddress()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -817,7 +899,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { verifyCommonFormEntries(paymentAccount); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_ACCOUNT_NR), paymentAccount.getAccountNr()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SALT), paymentAccount.getSaltAsHex()); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @Test @@ -849,11 +931,18 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail()); assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_COUNTRY), Objects.requireNonNull(paymentAccount.getCountry()).code); - log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + print(paymentAccount); } @AfterAll public static void tearDown() { tearDownScaffold(); } + + private void print(PaymentAccount paymentAccount) { + if (log.isDebugEnabled()) { + log.debug("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount); + log.debug("\n{}", formatPaymentAcctTbl(singletonList(paymentAccount.toProtoMessage()))); + } + } } diff --git a/apitest/src/test/java/bisq/apitest/scenario/OfferTest.java b/apitest/src/test/java/bisq/apitest/scenario/OfferTest.java index b01a9486ea..c82cbaef90 100644 --- a/apitest/src/test/java/bisq/apitest/scenario/OfferTest.java +++ b/apitest/src/test/java/bisq/apitest/scenario/OfferTest.java @@ -42,6 +42,8 @@ public class OfferTest extends AbstractOfferTest { public void testAmtTooLargeShouldThrowException() { ValidateCreateOfferTest test = new ValidateCreateOfferTest(); test.testAmtTooLargeShouldThrowException(); + test.testNoMatchingEURPaymentAccountShouldThrowException(); + test.testNoMatchingCADPaymentAccountShouldThrowException(); } @Test diff --git a/apitest/src/test/java/bisq/apitest/scenario/PaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/scenario/PaymentAccountTest.java index e3ce0a0806..c3eb41343a 100644 --- a/apitest/src/test/java/bisq/apitest/scenario/PaymentAccountTest.java +++ b/apitest/src/test/java/bisq/apitest/scenario/PaymentAccountTest.java @@ -13,8 +13,6 @@ import org.junit.jupiter.api.TestMethodOrder; import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; import static bisq.apitest.config.BisqAppConfig.alicedaemon; import static bisq.apitest.config.BisqAppConfig.seednode; -import static java.util.Objects.requireNonNull; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @@ -27,10 +25,6 @@ import bisq.apitest.method.payment.GetPaymentMethodsTest; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class PaymentAccountTest extends AbstractPaymentAccountTest { - // Two dummy (usd +eth) accounts are set up as defaults in regtest / dao mode, - // then we add 28 more payment accounts in testCreatePaymentAccount(). - private static final int EXPECTED_NUM_PAYMENT_ACCOUNTS = 2 + 28; - @BeforeAll public static void setUp() { try { @@ -75,14 +69,18 @@ public class PaymentAccountTest extends AbstractPaymentAccountTest { test.testCreateSepaAccount(testInfo); test.testCreateSpecificBanksAccount(testInfo); test.testCreateSwishAccount(testInfo); - test.testCreateTransferwiseAccount(testInfo); + + // TransferwiseAccount is only PaymentAccount with a + // tradeCurrencies field in the json form. + test.testCreateTransferwiseAccountWith1TradeCurrency(testInfo); + test.testCreateTransferwiseAccountWith10TradeCurrencies(testInfo); + test.testCreateTransferwiseAccountWithInvalidBrlTradeCurrencyShouldThrowException(testInfo); + test.testCreateTransferwiseAccountWithoutTradeCurrenciesShouldThrowException(testInfo); + test.testCreateUpholdAccount(testInfo); test.testCreateUSPostalMoneyOrderAccount(testInfo); test.testCreateWeChatPayAccount(testInfo); test.testCreateWesternUnionAccount(testInfo); - - var paymentAccounts = requireNonNull(aliceClient).getPaymentAccounts(); - assertEquals(EXPECTED_NUM_PAYMENT_ACCOUNTS, paymentAccounts.size()); } @AfterAll diff --git a/build.gradle b/build.gradle index 85930680d7..be93145fc5 100644 --- a/build.gradle +++ b/build.gradle @@ -378,6 +378,17 @@ configure(project(':cli')) { implementation "ch.qos.logback:logback-classic:$logbackVersion" compileOnly "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion" + + testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiterVersion" + testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiterVersion" + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion") + testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" + testCompileOnly "org.projectlombok:lombok:$lombokVersion" + testRuntime "javax.annotation:javax.annotation-api:$javaxAnnotationVersion" + } + + test { + useJUnitPlatform() } } diff --git a/cli/src/main/java/bisq/cli/TableFormat.java b/cli/src/main/java/bisq/cli/TableFormat.java index 8064e9f696..dca4aa0699 100644 --- a/cli/src/main/java/bisq/cli/TableFormat.java +++ b/cli/src/main/java/bisq/cli/TableFormat.java @@ -163,7 +163,7 @@ public class TableFormat { + padEnd(COL_HEADER_PAYMENT_METHOD, paymentMethodColWidth, ' ') + COL_HEADER_DELIMITER + COL_HEADER_UUID + COL_HEADER_DELIMITER + "\n"; String colDataFormat = "%-" + nameColWidth + "s" // left justify - + " %" + COL_HEADER_CURRENCY.length() + "s" // right justify + + " %-" + COL_HEADER_CURRENCY.length() + "s" // left justify + " %-" + paymentMethodColWidth + "s" // left justify + " %-" + COL_HEADER_UUID.length() + "s"; // left justify return headerLine diff --git a/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java b/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java index 4c495c06e5..25256eb6a9 100644 --- a/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/AbstractMethodOptionParser.java @@ -17,11 +17,13 @@ package bisq.cli.opts; +import joptsimple.OptionException; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; import java.util.List; +import java.util.function.Function; import lombok.Getter; @@ -48,12 +50,29 @@ abstract class AbstractMethodOptionParser implements MethodOpts { } public AbstractMethodOptionParser parse() { - options = parser.parse(new ArgumentList(args).getMethodArguments()); - nonOptionArguments = (List) options.nonOptionArguments(); - return this; + try { + options = parser.parse(new ArgumentList(args).getMethodArguments()); + //noinspection unchecked + nonOptionArguments = (List) options.nonOptionArguments(); + return this; + } catch (OptionException ex) { + throw new IllegalArgumentException(cliExceptionMessageStyle.apply(ex), ex); + } } public boolean isForHelp() { return options.has(helpOpt); } + + private final Function cliExceptionMessageStyle = (ex) -> { + if (ex.getMessage() == null) + return null; + + var optionToken = "option "; + var cliMessage = ex.getMessage().toLowerCase(); + if (cliMessage.startsWith(optionToken) && cliMessage.length() > optionToken.length()) { + cliMessage = cliMessage.substring(cliMessage.indexOf(" ") + 1); + } + return cliMessage; + }; } diff --git a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java index 24ebc74421..c35ffc7bfb 100644 --- a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; -import static joptsimple.internal.Strings.EMPTY; public class CancelOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public CancelOfferOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class CancelOfferOptionParser extends AbstractMethodOptionParser implemen if (options.has(helpOpt)) return this; - if (!options.has(offerIdOpt)) + if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) throw new IllegalArgumentException("no offer id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java index d4d7c05c7a..42cf8ad155 100644 --- a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java @@ -33,20 +33,16 @@ public class CreateOfferOptionParser extends AbstractMethodOptionParser implemen .defaultsTo(EMPTY); final OptionSpec directionOpt = parser.accepts(OPT_DIRECTION, "offer direction (buy|sell)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec currencyCodeOpt = parser.accepts(OPT_CURRENCY_CODE, "currency code (eur|usd|...)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec amountOpt = parser.accepts(OPT_AMOUNT, "amount of btc to buy or sell") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec minAmountOpt = parser.accepts(OPT_MIN_AMOUNT, "minimum amount of btc to buy or sell") - .withOptionalArg() - .defaultsTo(EMPTY); + .withOptionalArg(); final OptionSpec mktPriceMarginOpt = parser.accepts(OPT_MKT_PRICE_MARGIN, "market btc price margin (%)") .withOptionalArg() @@ -54,11 +50,10 @@ public class CreateOfferOptionParser extends AbstractMethodOptionParser implemen final OptionSpec fixedPriceOpt = parser.accepts(OPT_FIXED_PRICE, "fixed btc price") .withOptionalArg() - .defaultsTo(EMPTY); + .defaultsTo("0"); final OptionSpec securityDepositOpt = parser.accepts(OPT_SECURITY_DEPOSIT, "maker security deposit (%)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec makerFeeCurrencyCodeOpt = parser.accepts(OPT_FEE_CURRENCY, "maker fee currency code (bsq|btc)") .withOptionalArg() @@ -75,19 +70,28 @@ public class CreateOfferOptionParser extends AbstractMethodOptionParser implemen if (options.has(helpOpt)) return this; - if (!options.has(paymentAccountIdOpt)) + if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty()) throw new IllegalArgumentException("no payment account id specified"); - if (!options.has(directionOpt)) + if (!options.has(directionOpt) || options.valueOf(directionOpt).isEmpty()) throw new IllegalArgumentException("no direction (buy|sell) specified"); - if (!options.has(amountOpt)) + if (!options.has(currencyCodeOpt) || options.valueOf(currencyCodeOpt).isEmpty()) + throw new IllegalArgumentException("no currency code specified"); + + if (!options.has(amountOpt) || options.valueOf(amountOpt).isEmpty()) throw new IllegalArgumentException("no btc amount specified"); if (!options.has(mktPriceMarginOpt) && !options.has(fixedPriceOpt)) throw new IllegalArgumentException("no market price margin or fixed price specified"); - if (!options.has(securityDepositOpt)) + if (options.has(mktPriceMarginOpt) && options.valueOf(mktPriceMarginOpt).isEmpty()) + throw new IllegalArgumentException("no market price margin specified"); + + if (options.has(fixedPriceOpt) && options.valueOf(fixedPriceOpt).isEmpty()) + throw new IllegalArgumentException("no fixed price specified"); + + if (!options.has(securityDepositOpt) || options.valueOf(securityDepositOpt).isEmpty()) throw new IllegalArgumentException("no security deposit specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java index 21fb01bcec..907f7ca0ed 100644 --- a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java @@ -25,14 +25,12 @@ import java.nio.file.Paths; import static bisq.cli.opts.OptLabel.OPT_PAYMENT_ACCOUNT_FORM; import static java.lang.String.format; -import static joptsimple.internal.Strings.EMPTY; public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec paymentAcctFormPathOpt = parser.accepts(OPT_PAYMENT_ACCOUNT_FORM, "path to json payment account form") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public CreatePaymentAcctOptionParser(String[] args) { super(args); @@ -45,7 +43,7 @@ public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser im if (options.has(helpOpt)) return this; - if (!options.has(paymentAcctFormPathOpt)) + if (!options.has(paymentAcctFormPathOpt) || options.valueOf(paymentAcctFormPathOpt).isEmpty()) throw new IllegalArgumentException("no path to json payment account form specified"); Path path = Paths.get(options.valueOf(paymentAcctFormPathOpt)); diff --git a/cli/src/main/java/bisq/cli/opts/GetAddressBalanceOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetAddressBalanceOptionParser.java index 80537ffc89..4ad693ca4c 100644 --- a/cli/src/main/java/bisq/cli/opts/GetAddressBalanceOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetAddressBalanceOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_ADDRESS; -import static joptsimple.internal.Strings.EMPTY; public class GetAddressBalanceOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec addressOpt = parser.accepts(OPT_ADDRESS, "wallet btc address") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetAddressBalanceOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class GetAddressBalanceOptionParser extends AbstractMethodOptionParser im if (options.has(helpOpt)) return this; - if (!options.has(addressOpt)) + if (!options.has(addressOpt) || options.valueOf(addressOpt).isEmpty()) throw new IllegalArgumentException("no address specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetBTCMarketPriceOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetBTCMarketPriceOptionParser.java index c54f65f42e..8d6585631b 100644 --- a/cli/src/main/java/bisq/cli/opts/GetBTCMarketPriceOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetBTCMarketPriceOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_CURRENCY_CODE; -import static joptsimple.internal.Strings.EMPTY; public class GetBTCMarketPriceOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec currencyCodeOpt = parser.accepts(OPT_CURRENCY_CODE, "currency-code") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetBTCMarketPriceOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class GetBTCMarketPriceOptionParser extends AbstractMethodOptionParser im if (options.has(helpOpt)) return this; - if (!options.has(currencyCodeOpt)) + if (!options.has(currencyCodeOpt) || options.valueOf(currencyCodeOpt).isEmpty()) throw new IllegalArgumentException("no currency code specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java index 600e7672c4..1a849654cf 100644 --- a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; -import static joptsimple.internal.Strings.EMPTY; public class GetOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to get") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetOfferOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class GetOfferOptionParser extends AbstractMethodOptionParser implements if (options.has(helpOpt)) return this; - if (!options.has(offerIdOpt)) + if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) throw new IllegalArgumentException("no offer id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetOffersOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetOffersOptionParser.java index 29360886f8..f8a4dee839 100644 --- a/cli/src/main/java/bisq/cli/opts/GetOffersOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetOffersOptionParser.java @@ -22,17 +22,14 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_CURRENCY_CODE; import static bisq.cli.opts.OptLabel.OPT_DIRECTION; -import static joptsimple.internal.Strings.EMPTY; public class GetOffersOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec directionOpt = parser.accepts(OPT_DIRECTION, "offer direction (buy|sell)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec currencyCodeOpt = parser.accepts(OPT_CURRENCY_CODE, "currency code (eur|usd|...)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetOffersOptionParser(String[] args) { super(args); @@ -45,10 +42,10 @@ public class GetOffersOptionParser extends AbstractMethodOptionParser implements if (options.has(helpOpt)) return this; - if (!options.has(directionOpt)) + if (!options.has(directionOpt) || options.valueOf(directionOpt).isEmpty()) throw new IllegalArgumentException("no direction (buy|sell) specified"); - if (!options.has(currencyCodeOpt)) + if (!options.has(currencyCodeOpt) || options.valueOf(currencyCodeOpt).isEmpty()) throw new IllegalArgumentException("no currency code specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java index ef5bd5b454..508069c2f3 100644 --- a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java @@ -21,14 +21,12 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_PAYMENT_METHOD_ID; -import static joptsimple.internal.Strings.EMPTY; public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec paymentMethodIdOpt = parser.accepts(OPT_PAYMENT_METHOD_ID, "id of payment method type used by a payment account") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetPaymentAcctFormOptionParser(String[] args) { super(args); @@ -41,7 +39,7 @@ public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser i if (options.has(helpOpt)) return this; - if (!options.has(paymentMethodIdOpt)) + if (!options.has(paymentMethodIdOpt) || options.valueOf(paymentMethodIdOpt).isEmpty()) throw new IllegalArgumentException("no payment method id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetTradeOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetTradeOptionParser.java index 2b7681f3c6..1419f3ed6a 100644 --- a/cli/src/main/java/bisq/cli/opts/GetTradeOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetTradeOptionParser.java @@ -22,13 +22,11 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_SHOW_CONTRACT; import static bisq.cli.opts.OptLabel.OPT_TRADE_ID; -import static joptsimple.internal.Strings.EMPTY; public class GetTradeOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec tradeIdOpt = parser.accepts(OPT_TRADE_ID, "id of trade") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec showContractOpt = parser.accepts(OPT_SHOW_CONTRACT, "show trade's json contract") .withOptionalArg() @@ -46,7 +44,7 @@ public class GetTradeOptionParser extends AbstractMethodOptionParser implements if (options.has(helpOpt)) return this; - if (!options.has(tradeIdOpt)) + if (!options.has(tradeIdOpt) || options.valueOf(tradeIdOpt).isEmpty()) throw new IllegalArgumentException("no trade id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/GetTransactionOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetTransactionOptionParser.java index d4266eb9ff..0b245cb156 100644 --- a/cli/src/main/java/bisq/cli/opts/GetTransactionOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetTransactionOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_TRANSACTION_ID; -import static joptsimple.internal.Strings.EMPTY; public class GetTransactionOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec txIdOpt = parser.accepts(OPT_TRANSACTION_ID, "id of transaction") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public GetTransactionOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class GetTransactionOptionParser extends AbstractMethodOptionParser imple if (options.has(helpOpt)) return this; - if (!options.has(txIdOpt)) + if (!options.has(txIdOpt) || options.valueOf(txIdOpt).isEmpty()) throw new IllegalArgumentException("no tx id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/RegisterDisputeAgentOptionParser.java b/cli/src/main/java/bisq/cli/opts/RegisterDisputeAgentOptionParser.java index 428555a349..b1c8f0bba8 100644 --- a/cli/src/main/java/bisq/cli/opts/RegisterDisputeAgentOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/RegisterDisputeAgentOptionParser.java @@ -22,17 +22,14 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_DISPUTE_AGENT_TYPE; import static bisq.cli.opts.OptLabel.OPT_REGISTRATION_KEY; -import static joptsimple.internal.Strings.EMPTY; public class RegisterDisputeAgentOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec disputeAgentTypeOpt = parser.accepts(OPT_DISPUTE_AGENT_TYPE, "dispute agent type") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec registrationKeyOpt = parser.accepts(OPT_REGISTRATION_KEY, "registration key") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public RegisterDisputeAgentOptionParser(String[] args) { super(args); @@ -45,10 +42,10 @@ public class RegisterDisputeAgentOptionParser extends AbstractMethodOptionParser if (options.has(helpOpt)) return this; - if (!options.has(disputeAgentTypeOpt)) + if (!options.has(disputeAgentTypeOpt) || options.valueOf(disputeAgentTypeOpt).isEmpty()) throw new IllegalArgumentException("no dispute agent type specified"); - if (!options.has(registrationKeyOpt)) + if (!options.has(registrationKeyOpt) || options.valueOf(registrationKeyOpt).isEmpty()) throw new IllegalArgumentException("no registration key specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/RemoveWalletPasswordOptionParser.java b/cli/src/main/java/bisq/cli/opts/RemoveWalletPasswordOptionParser.java index 5b9a391594..db556a0fd8 100644 --- a/cli/src/main/java/bisq/cli/opts/RemoveWalletPasswordOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/RemoveWalletPasswordOptionParser.java @@ -21,13 +21,11 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_WALLET_PASSWORD; -import static joptsimple.internal.Strings.EMPTY; public class RemoveWalletPasswordOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec passwordOpt = parser.accepts(OPT_WALLET_PASSWORD, "bisq wallet password") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public RemoveWalletPasswordOptionParser(String[] args) { super(args); @@ -40,7 +38,7 @@ public class RemoveWalletPasswordOptionParser extends AbstractMethodOptionParser if (options.has(helpOpt)) return this; - if (!options.has(passwordOpt)) + if (!options.has(passwordOpt) || options.valueOf(passwordOpt).isEmpty()) throw new IllegalArgumentException("no password specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/SendBsqOptionParser.java b/cli/src/main/java/bisq/cli/opts/SendBsqOptionParser.java index 3bffce785c..ad9ab87cbb 100644 --- a/cli/src/main/java/bisq/cli/opts/SendBsqOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/SendBsqOptionParser.java @@ -28,12 +28,10 @@ import static joptsimple.internal.Strings.EMPTY; public class SendBsqOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec addressOpt = parser.accepts(OPT_ADDRESS, "destination bsq address") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec amountOpt = parser.accepts(OPT_AMOUNT, "amount of bsq to send") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec feeRateOpt = parser.accepts(OPT_TX_FEE_RATE, "optional tx fee rate (sats/byte)") .withOptionalArg() @@ -50,10 +48,10 @@ public class SendBsqOptionParser extends AbstractMethodOptionParser implements M if (options.has(helpOpt)) return this; - if (!options.has(addressOpt)) + if (!options.has(addressOpt) || options.valueOf(addressOpt).isEmpty()) throw new IllegalArgumentException("no bsq address specified"); - if (!options.has(amountOpt)) + if (!options.has(amountOpt) || options.valueOf(amountOpt).isEmpty()) throw new IllegalArgumentException("no bsq amount specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/SendBtcOptionParser.java b/cli/src/main/java/bisq/cli/opts/SendBtcOptionParser.java index 8c3f976201..f7d8fd5683 100644 --- a/cli/src/main/java/bisq/cli/opts/SendBtcOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/SendBtcOptionParser.java @@ -29,12 +29,10 @@ import static joptsimple.internal.Strings.EMPTY; public class SendBtcOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec addressOpt = parser.accepts(OPT_ADDRESS, "destination btc address") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec amountOpt = parser.accepts(OPT_AMOUNT, "amount of btc to send") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec feeRateOpt = parser.accepts(OPT_TX_FEE_RATE, "optional tx fee rate (sats/byte)") .withOptionalArg() @@ -55,10 +53,10 @@ public class SendBtcOptionParser extends AbstractMethodOptionParser implements M if (options.has(helpOpt)) return this; - if (!options.has(addressOpt)) + if (!options.has(addressOpt) || options.valueOf(addressOpt).isEmpty()) throw new IllegalArgumentException("no btc address specified"); - if (!options.has(amountOpt)) + if (!options.has(amountOpt) || options.valueOf(amountOpt).isEmpty()) throw new IllegalArgumentException("no btc amount specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java index 9d4b5e71b3..f7ed113cb3 100644 --- a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java @@ -21,14 +21,12 @@ package bisq.cli.opts; import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_TX_FEE_RATE; -import static joptsimple.internal.Strings.EMPTY; public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec feeRateOpt = parser.accepts(OPT_TX_FEE_RATE, "tx fee rate preference (sats/byte)") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); public SetTxFeeRateOptionParser(String[] args) { super(args); @@ -41,7 +39,7 @@ public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser impleme if (options.has(helpOpt)) return this; - if (!options.has(feeRateOpt)) + if (!options.has(feeRateOpt) || options.valueOf(feeRateOpt).isEmpty()) throw new IllegalArgumentException("no tx fee rate specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/SetWalletPasswordOptionParser.java b/cli/src/main/java/bisq/cli/opts/SetWalletPasswordOptionParser.java index d55b1bf33b..1caa09232c 100644 --- a/cli/src/main/java/bisq/cli/opts/SetWalletPasswordOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/SetWalletPasswordOptionParser.java @@ -27,8 +27,7 @@ import static joptsimple.internal.Strings.EMPTY; public class SetWalletPasswordOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec passwordOpt = parser.accepts(OPT_WALLET_PASSWORD, "bisq wallet password") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec newPasswordOpt = parser.accepts(OPT_NEW_WALLET_PASSWORD, "new bisq wallet password") .withOptionalArg() @@ -45,7 +44,7 @@ public class SetWalletPasswordOptionParser extends AbstractMethodOptionParser im if (options.has(helpOpt)) return this; - if (!options.has(passwordOpt)) + if (!options.has(passwordOpt) || options.valueOf(passwordOpt).isEmpty()) throw new IllegalArgumentException("no password specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java index 75ef2885b0..67fbdd8c86 100644 --- a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java @@ -23,17 +23,14 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_FEE_CURRENCY; import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; import static bisq.cli.opts.OptLabel.OPT_PAYMENT_ACCOUNT; -import static joptsimple.internal.Strings.EMPTY; public class TakeOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to take") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, "id of payment account used for trade") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec takerFeeCurrencyCodeOpt = parser.accepts(OPT_FEE_CURRENCY, "taker fee currency code (bsq|btc)") .withOptionalArg() @@ -50,10 +47,10 @@ public class TakeOfferOptionParser extends AbstractMethodOptionParser implements if (options.has(helpOpt)) return this; - if (!options.has(offerIdOpt)) + if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) throw new IllegalArgumentException("no offer id specified"); - if (!options.has(paymentAccountIdOpt)) + if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty()) throw new IllegalArgumentException("no payment account id specified"); return this; diff --git a/cli/src/main/java/bisq/cli/opts/UnlockWalletOptionParser.java b/cli/src/main/java/bisq/cli/opts/UnlockWalletOptionParser.java index 4446138dd3..2908be42bf 100644 --- a/cli/src/main/java/bisq/cli/opts/UnlockWalletOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/UnlockWalletOptionParser.java @@ -22,13 +22,11 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_TIMEOUT; import static bisq.cli.opts.OptLabel.OPT_WALLET_PASSWORD; -import static joptsimple.internal.Strings.EMPTY; public class UnlockWalletOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec passwordOpt = parser.accepts(OPT_WALLET_PASSWORD, "bisq wallet password") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec unlockTimeoutOpt = parser.accepts(OPT_TIMEOUT, "wallet unlock timeout (s)") .withRequiredArg() @@ -46,7 +44,7 @@ public class UnlockWalletOptionParser extends AbstractMethodOptionParser impleme if (options.has(helpOpt)) return this; - if (!options.has(passwordOpt)) + if (!options.has(passwordOpt) || options.valueOf(passwordOpt).isEmpty()) throw new IllegalArgumentException("no password specified"); if (!options.has(unlockTimeoutOpt) || options.valueOf(unlockTimeoutOpt) <= 0) diff --git a/cli/src/main/java/bisq/cli/opts/WithdrawFundsOptionParser.java b/cli/src/main/java/bisq/cli/opts/WithdrawFundsOptionParser.java index f47432fa86..bdba643760 100644 --- a/cli/src/main/java/bisq/cli/opts/WithdrawFundsOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/WithdrawFundsOptionParser.java @@ -28,12 +28,10 @@ import static joptsimple.internal.Strings.EMPTY; public class WithdrawFundsOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec tradeIdOpt = parser.accepts(OPT_TRADE_ID, "id of trade") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec addressOpt = parser.accepts(OPT_ADDRESS, "destination btc address") - .withRequiredArg() - .defaultsTo(EMPTY); + .withRequiredArg(); final OptionSpec memoOpt = parser.accepts(OPT_MEMO, "optional tx memo") .withOptionalArg() @@ -50,9 +48,12 @@ public class WithdrawFundsOptionParser extends AbstractMethodOptionParser implem if (options.has(helpOpt)) return this; - if (!options.has(tradeIdOpt)) + if (!options.has(tradeIdOpt) || options.valueOf(tradeIdOpt).isEmpty()) throw new IllegalArgumentException("no trade id specified"); + if (!options.has(addressOpt) || options.valueOf(addressOpt).isEmpty()) + throw new IllegalArgumentException("no destination address specified"); + return this; } diff --git a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java index 49f849e0cc..f613aea358 100644 --- a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java +++ b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java @@ -16,24 +16,24 @@ public class GetOffersSmokeTest { public static void main(String[] args) { out.println(">>> getoffers buy usd"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "usd"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=usd"}); out.println(">>> getoffers sell usd"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "usd"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=usd"}); out.println(">>> getoffers buy eur"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "eur"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=eur"}); out.println(">>> getoffers sell eur"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "eur"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=eur"}); out.println(">>> getoffers buy gbp"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "gbp"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=gbp"}); out.println(">>> getoffers sell gbp"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "gbp"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=gbp"}); out.println(">>> getoffers buy brl"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "buy", "brl"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=brl"}); out.println(">>> getoffers sell brl"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "sell", "brl"}); + CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=brl"}); } } diff --git a/cli/src/test/java/bisq/cli/opt/OptionParsersTest.java b/cli/src/test/java/bisq/cli/opt/OptionParsersTest.java new file mode 100644 index 0000000000..1f939198d6 --- /dev/null +++ b/cli/src/test/java/bisq/cli/opt/OptionParsersTest.java @@ -0,0 +1,180 @@ +package bisq.cli.opt; + +import org.junit.jupiter.api.Test; + +import static bisq.cli.Method.canceloffer; +import static bisq.cli.Method.createoffer; +import static bisq.cli.Method.createpaymentacct; +import static bisq.cli.opts.OptLabel.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + + + +import bisq.cli.opts.CancelOfferOptionParser; +import bisq.cli.opts.CreateOfferOptionParser; +import bisq.cli.opts.CreatePaymentAcctOptionParser; + + +public class OptionParsersTest { + + private static final String PASSWORD_OPT = "--" + OPT_PASSWORD + "=" + "xyz"; + + // CancelOffer opt parsing tests + + @Test + public void testCancelOfferWithMissingOfferIdOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + canceloffer.name() + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CancelOfferOptionParser(args).parse()); + assertEquals("no offer id specified", exception.getMessage()); + } + + @Test + public void testCancelOfferWithEmptyOfferIdOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + canceloffer.name(), + "--" + OPT_OFFER_ID + "=" // missing opt value + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CancelOfferOptionParser(args).parse()); + assertEquals("no offer id specified", exception.getMessage()); + } + + @Test + public void testCancelOfferWithMissingOfferIdValueShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + canceloffer.name(), + "--" + OPT_OFFER_ID // missing equals sign & opt value + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CancelOfferOptionParser(args).parse()); + assertEquals("offer-id requires an argument", exception.getMessage()); + } + + @Test + public void testValidCancelOfferOpts() { + String[] args = new String[]{ + PASSWORD_OPT, + canceloffer.name(), + "--" + OPT_OFFER_ID + "=" + "ABC-OFFER-ID" + }; + new CancelOfferOptionParser(args).parse(); + } + + // CreateOffer opt parsing tests + + @Test + public void testCreateOfferOptParserWithMissingPaymentAccountIdOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createoffer.name() + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreateOfferOptionParser(args).parse()); + assertEquals("no payment account id specified", exception.getMessage()); + } + + @Test + public void testCreateOfferOptParserWithEmptyPaymentAccountIdOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createoffer.name(), + "--" + OPT_PAYMENT_ACCOUNT + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreateOfferOptionParser(args).parse()); + assertEquals("payment-account requires an argument", exception.getMessage()); + } + + @Test + public void testCreateOfferOptParserWithMissingDirectionOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createoffer.name(), + "--" + OPT_PAYMENT_ACCOUNT + "=" + "abc-payment-acct-id-123" + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreateOfferOptionParser(args).parse()); + assertEquals("no direction (buy|sell) specified", exception.getMessage()); + } + + + @Test + public void testCreateOfferOptParserWithMissingDirectionOptValueShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createoffer.name(), + "--" + OPT_PAYMENT_ACCOUNT + "=" + "abc-payment-acct-id-123", + "--" + OPT_DIRECTION + "=" + "" + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreateOfferOptionParser(args).parse()); + assertEquals("no direction (buy|sell) specified", exception.getMessage()); + } + + @Test + public void testValidCreateOfferOpts() { + String[] args = new String[]{ + PASSWORD_OPT, + createoffer.name(), + "--" + OPT_PAYMENT_ACCOUNT + "=" + "abc-payment-acct-id-123", + "--" + OPT_DIRECTION + "=" + "BUY", + "--" + OPT_CURRENCY_CODE + "=" + "EUR", + "--" + OPT_AMOUNT + "=" + "0.125", + "--" + OPT_MKT_PRICE_MARGIN + "=" + "0.0", + "--" + OPT_SECURITY_DEPOSIT + "=" + "25.0" + }; + CreateOfferOptionParser parser = new CreateOfferOptionParser(args).parse(); + assertEquals("abc-payment-acct-id-123", parser.getPaymentAccountId()); + assertEquals("BUY", parser.getDirection()); + assertEquals("EUR", parser.getCurrencyCode()); + assertEquals("0.125", parser.getAmount()); + assertEquals("0.0", parser.getMktPriceMargin()); + assertEquals("25.0", parser.getSecurityDeposit()); + } + + // CreatePaymentAcct opt parser tests + + @Test + public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createpaymentacct.name() + // OPT_PAYMENT_ACCOUNT_FORM + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreatePaymentAcctOptionParser(args).parse()); + assertEquals("no path to json payment account form specified", exception.getMessage()); + } + + @Test + public void testCreatePaymentAcctOptParserWithMissingPaymentFormOptValueShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createpaymentacct.name(), + "--" + OPT_PAYMENT_ACCOUNT_FORM + "=" + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreatePaymentAcctOptionParser(args).parse()); + assertEquals("no path to json payment account form specified", exception.getMessage()); + } + + @Test + public void testCreatePaymentAcctOptParserWithInvalidPaymentFormOptValueShouldThrowException() { + String[] args = new String[]{ + PASSWORD_OPT, + createpaymentacct.name(), + "--" + OPT_PAYMENT_ACCOUNT_FORM + "=" + "/tmp/milkyway/solarsystem/mars" + }; + Throwable exception = assertThrows(RuntimeException.class, () -> + new CreatePaymentAcctOptionParser(args).parse()); + assertEquals("json payment account form '/tmp/milkyway/solarsystem/mars' could not be found", + exception.getMessage()); + } +} diff --git a/common/src/main/java/bisq/common/util/ReflectionUtils.java b/common/src/main/java/bisq/common/util/ReflectionUtils.java index e70162ecb2..c9f83a8f41 100644 --- a/common/src/main/java/bisq/common/util/ReflectionUtils.java +++ b/common/src/main/java/bisq/common/util/ReflectionUtils.java @@ -28,9 +28,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import lombok.extern.slf4j.Slf4j; + +import static java.lang.String.format; import static java.util.Arrays.stream; import static org.apache.commons.lang3.StringUtils.capitalize; +@Slf4j public class ReflectionUtils { /** @@ -105,4 +109,32 @@ public class ReflectionUtils { else return ""; } + + public static Field getField(String name, Class clazz) { + Optional field = stream(clazz.getDeclaredFields()) + .filter(f -> f.getName().equals(name)).findFirst(); + return field.orElseThrow(() -> + new IllegalArgumentException(format("field %s not found in class %s", + name, + clazz.getSimpleName()))); + } + + public static Method getMethod(String name, Class clazz) { + Optional method = stream(clazz.getDeclaredMethods()) + .filter(m -> m.getName().equals(name)).findFirst(); + return method.orElseThrow(() -> + new IllegalArgumentException(format("method %s not found in class %s", + name, + clazz.getSimpleName()))); + } + + public static void handleSetFieldValueError(Object object, + Field field, + ReflectiveOperationException ex) { + String errMsg = format("cannot set value of field %s, on class %s", + field.getName(), + object.getClass().getSimpleName()); + log.error(capitalize(errMsg) + ".", ex); + throw new IllegalStateException("programmer error: " + errMsg); + } } diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index 63420e0bbb..9942380abc 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -54,6 +54,7 @@ import static bisq.common.util.MathUtils.scaleUpByPowerOf10; import static bisq.core.locale.CurrencyUtil.isCryptoCurrency; import static bisq.core.offer.OfferPayload.Direction; import static bisq.core.offer.OfferPayload.Direction.BUY; +import static bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer; import static java.lang.String.format; import static java.util.Comparator.comparing; @@ -101,6 +102,7 @@ class CoreOffersService { Offer getOffer(String id) { return offerBookService.getOffers().stream() .filter(o -> o.getId().equals(id)) + .filter(o -> !o.isMyOffer(keyRing)) .filter(o -> offerFilter.canTakeOffer(o, isApiUser).isValid()) .findAny().orElseThrow(() -> new IllegalStateException(format("offer with id '%s' not found", id))); @@ -116,6 +118,7 @@ class CoreOffersService { List getOffers(String direction, String currencyCode) { return offerBookService.getOffers().stream() + .filter(o -> !o.isMyOffer(keyRing)) .filter(o -> offerMatchesDirectionAndCurrency(o, direction, currencyCode)) .filter(o -> offerFilter.canTakeOffer(o, isApiUser).isValid()) .sorted(priceComparator(direction)) @@ -174,6 +177,8 @@ class CoreOffersService { buyerSecurityDeposit, paymentAccount); + verifyPaymentAccountIsValidForNewOffer(offer, paymentAccount); + // We don't support atm funding from external wallet to keep it simple. boolean useSavingsWallet = true; //noinspection ConstantConditions @@ -210,7 +215,7 @@ class CoreOffersService { } void cancelOffer(String id) { - Offer offer = getOffer(id); + Offer offer = getMyOffer(id); openOfferManager.removeOffer(offer, () -> { }, @@ -219,6 +224,15 @@ class CoreOffersService { }); } + private void verifyPaymentAccountIsValidForNewOffer(Offer offer, PaymentAccount paymentAccount) { + if (!isPaymentAccountValidForOffer(offer, paymentAccount)) { + String error = format("cannot create %s offer with payment account %s", + offer.getOfferPayload().getCounterCurrencyCode(), + paymentAccount.getId()); + throw new IllegalStateException(error); + } + } + private void placeOffer(Offer offer, double buyerSecurityDeposit, long triggerPrice, diff --git a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java index 095bf2d1f2..b915b3ab4b 100644 --- a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java +++ b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java @@ -35,6 +35,8 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import static java.lang.String.format; + @Singleton @Slf4j class CorePaymentAccountsService { @@ -54,6 +56,7 @@ class CorePaymentAccountsService { PaymentAccount createPaymentAccount(String jsonString) { PaymentAccount paymentAccount = paymentAccountForm.toPaymentAccount(jsonString); + verifyPaymentAccountHasRequiredFields(paymentAccount); user.addPaymentAccountIfNotExists(paymentAccount); accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); log.info("Saved payment account with id {} and payment method {}.", @@ -82,4 +85,11 @@ class CorePaymentAccountsService { File getPaymentAccountForm(String paymentMethodId) { return paymentAccountForm.getPaymentAccountForm(paymentMethodId); } + + private void verifyPaymentAccountHasRequiredFields(PaymentAccount paymentAccount) { + // Do checks here to make sure required fields are populated. + if (paymentAccount.isTransferwiseAccount() && paymentAccount.getTradeCurrencies().isEmpty()) + throw new IllegalArgumentException(format("no trade currencies defined for %s payment account", + paymentAccount.getPaymentMethod().getDisplayString().toLowerCase())); + } } diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java index dae437d265..777e48987d 100644 --- a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java +++ b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java @@ -136,7 +136,7 @@ public class PaymentAccountForm { "paymentMethod", "paymentMethodId", // This field will be included, but handled differently. "selectedTradeCurrency", - "tradeCurrencies", + "tradeCurrencies", // This field may be included, but handled differently. "HOLDER_NAME", "SALT" // This field will be included, but handled differently. }; diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java index f49809a50c..b566ac10b0 100644 --- a/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java +++ b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java @@ -20,6 +20,7 @@ package bisq.core.api.model; import bisq.core.locale.Country; import bisq.core.locale.FiatCurrency; +import bisq.core.locale.TradeCurrency; import bisq.core.payment.CountryBasedPaymentAccount; import bisq.core.payment.MoneyGramAccount; import bisq.core.payment.PaymentAccount; @@ -35,12 +36,11 @@ import org.apache.commons.lang3.StringUtils; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.function.Predicate; import java.lang.reflect.Constructor; @@ -50,16 +50,20 @@ import java.lang.reflect.Method; import lombok.extern.slf4j.Slf4j; -import static bisq.common.util.ReflectionUtils.getSetterMethodForFieldInClassHierarchy; -import static bisq.common.util.ReflectionUtils.getVisibilityModifierAsString; -import static bisq.common.util.ReflectionUtils.isSetterOnClass; -import static bisq.common.util.ReflectionUtils.loadFieldListForClassHierarchy; +import static bisq.common.util.ReflectionUtils.*; import static bisq.common.util.Utilities.decodeFromHex; import static bisq.core.locale.CountryUtil.findCountryByCode; +import static bisq.core.locale.CurrencyUtil.getAllTransferwiseCurrencies; import static bisq.core.locale.CurrencyUtil.getCurrencyByCountryCode; +import static bisq.core.locale.CurrencyUtil.getTradeCurrencies; +import static bisq.core.locale.CurrencyUtil.getTradeCurrenciesInList; import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; +import static java.util.Arrays.stream; +import static java.util.Collections.singletonList; +import static java.util.Collections.unmodifiableMap; import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.toList; @Slf4j class PaymentAccountTypeAdapter extends TypeAdapter { @@ -96,7 +100,7 @@ class PaymentAccountTypeAdapter extends TypeAdapter { public PaymentAccountTypeAdapter(Class paymentAccountType, String[] excludedFields) { this.paymentAccountType = paymentAccountType; this.paymentAccountPayloadType = getPaymentAccountPayloadType(); - this.isExcludedField = (f) -> Arrays.stream(excludedFields).anyMatch(e -> e.equals(f.getName())); + this.isExcludedField = (f) -> stream(excludedFields).anyMatch(e -> e.equals(f.getName())); this.fieldSettersMap = getFieldSetterMap(); } @@ -128,6 +132,9 @@ class PaymentAccountTypeAdapter extends TypeAdapter { } private void writeInnerMutableFields(JsonWriter out, PaymentAccount account) { + if (account.isTransferwiseAccount()) + writeTradeCurrenciesField(out, account); + fieldSettersMap.forEach((field, value) -> { try { // Write out a json element if there is a @Setter for this field. @@ -151,6 +158,25 @@ class PaymentAccountTypeAdapter extends TypeAdapter { }); } + // In some cases (TransferwiseAccount), we need to include a 'tradeCurrencies' + // field in the json form, though the 'tradeCurrencies' field has no setter method in + // the PaymentAccount class hierarchy. At of time of this change, TransferwiseAccount + // is the only known exception to the rule. + private void writeTradeCurrenciesField(JsonWriter out, PaymentAccount account) { + try { + String fieldName = "tradeCurrencies"; + log.debug("Append form with non-settable field: {}", fieldName); + out.name(fieldName); + out.value("comma delimited currency code list, e.g., gbp,eur"); + } catch (Exception ex) { + String errMsg = format("cannot create a new %s json form", + account.getClass().getSimpleName()); + log.error(StringUtils.capitalize(errMsg) + ".", ex); + throw new IllegalStateException("programmer error: " + errMsg); + } + } + + @Override public PaymentAccount read(JsonReader in) throws IOException { PaymentAccount account = initNewPaymentAccount(); @@ -158,6 +184,11 @@ class PaymentAccountTypeAdapter extends TypeAdapter { while (in.hasNext()) { String currentFieldName = in.nextName(); + // The tradeCurrency field is common to all payment account types, + // but has no setter. + if (didReadTradeCurrenciesField(in, account, currentFieldName)) + continue; + // Some of the fields are common to all payment account types. if (didReadCommonField(in, account, currentFieldName)) continue; @@ -199,17 +230,13 @@ class PaymentAccountTypeAdapter extends TypeAdapter { account.getClass().getSimpleName()); throw new IllegalStateException(errMsg); } - } catch (IllegalAccessException | InvocationTargetException ex) { - String errMsg = format("cannot set field value for %s on %s", - field.getName(), - account.getClass().getSimpleName()); - log.error(StringUtils.capitalize(errMsg) + ".", ex); - throw new IllegalStateException("programmer error: " + errMsg); + } catch (ReflectiveOperationException ex) { + handleSetFieldValueError(account, field, ex); } } else { throw new IllegalStateException( format("programmer error: cannot de-serialize json to a '%s' " - + " because there is no setter method for field %s.", + + " because field value cannot be set %s.", account.getClass().getSimpleName(), field.getName())); } @@ -232,7 +259,7 @@ class PaymentAccountTypeAdapter extends TypeAdapter { .or(() -> getSetterMethodForFieldInClassHierarchy(field, paymentAccountPayloadType)); map.put(field, setter); } - return Collections.unmodifiableMap(map); + return unmodifiableMap(map); } private List getOrderedFields() { @@ -274,6 +301,52 @@ class PaymentAccountTypeAdapter extends TypeAdapter { } } + private final Predicate isCommaDelimitedCurrencyList = (s) -> s != null && s.contains(","); + private final Function> commaDelimitedCodesToList = (s) -> { + if (isCommaDelimitedCurrencyList.test(s)) + return stream(s.split(",")).map(a -> a.trim().toUpperCase()).collect(toList()); + else if (s != null && !s.isEmpty()) + return singletonList(s.trim().toUpperCase()); + else + return new ArrayList<>(); + }; + + private boolean didReadTradeCurrenciesField(JsonReader in, + PaymentAccount account, + String fieldName) { + // The PaymentAccount.tradeCurrencies field is a special case because it has + // no setter, and we add currencies to the List here. Normally, it is an + // excluded field, TransferwiseAccount excepted. + if (fieldName.equals("tradeCurrencies")) { + String fieldValue = nextStringOrNull(in); + List currencyCodes = commaDelimitedCodesToList.apply(fieldValue); + + Optional> tradeCurrencies; + if (account.isTransferwiseAccount()) + tradeCurrencies = getTradeCurrenciesInList(currencyCodes, getAllTransferwiseCurrencies()); + else + tradeCurrencies = getTradeCurrencies(currencyCodes); + + if (tradeCurrencies.isPresent()) { + for (TradeCurrency tradeCurrency : tradeCurrencies.get()) { + account.addCurrency(tradeCurrency); + } + // For api users, define a selected currency. + account.setSelectedTradeCurrency(account.getTradeCurrency().orElse(null)); + } else { + // Log a warning. We should not throw an exception here because the + // gson library will not pass it up to the calling Bisq class as it + // would be defined here. Do a check in a calling class to make sure + // the tradeCurrencies field is populated in the PaymentAccount + // object, if it is required for the payment account method. + log.warn("No trade currencies were found in the {} account form.", + account.getPaymentMethod().getDisplayString()); + } + return true; + } + return false; + } + private boolean didReadCommonField(JsonReader in, PaymentAccount account, String fieldName) throws IOException { diff --git a/core/src/main/java/bisq/core/locale/CurrencyUtil.java b/core/src/main/java/bisq/core/locale/CurrencyUtil.java index e94127cef1..9ed9bb1a96 100644 --- a/core/src/main/java/bisq/core/locale/CurrencyUtil.java +++ b/core/src/main/java/bisq/core/locale/CurrencyUtil.java @@ -43,6 +43,7 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -51,6 +52,7 @@ import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; @Slf4j public class CurrencyUtil { @@ -486,6 +488,32 @@ public class CurrencyUtil { return Optional.empty(); } + public static Optional> getTradeCurrencies(List currencyCodes) { + List tradeCurrencies = new ArrayList<>(); + currencyCodes.stream().forEachOrdered(c -> + tradeCurrencies.add(getTradeCurrency(c).orElseThrow(() -> + new IllegalArgumentException(format("%s is not a valid trade currency code", c))))); + return tradeCurrencies.isEmpty() + ? Optional.empty() + : Optional.of(tradeCurrencies); + } + + public static Optional> getTradeCurrenciesInList(List currencyCodes, + List validCurrencies) { + Optional> tradeCurrencies = getTradeCurrencies(currencyCodes); + Consumer> validateCandidateCurrencies = (list) -> { + for (TradeCurrency tradeCurrency : list) { + if (!validCurrencies.contains(tradeCurrency)) { + throw new IllegalArgumentException( + format("%s is not a member of valid currencies list", + tradeCurrency.getCode())); + } + } + }; + tradeCurrencies.ifPresent(validateCandidateCurrencies); + return tradeCurrencies; + } + public static FiatCurrency getCurrencyByCountryCode(String countryCode) { if (countryCode.equals("XK")) return new FiatCurrency("EUR"); diff --git a/core/src/main/java/bisq/core/offer/OfferFilter.java b/core/src/main/java/bisq/core/offer/OfferFilter.java index c22231de5b..bfd37f2af1 100644 --- a/core/src/main/java/bisq/core/offer/OfferFilter.java +++ b/core/src/main/java/bisq/core/offer/OfferFilter.java @@ -134,7 +134,7 @@ public class OfferFilter { public boolean isAnyPaymentAccountValidForOffer(Offer offer) { return user.getPaymentAccounts() != null && - PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer(offer, user.getPaymentAccounts()); + PaymentAccountUtil.isAnyPaymentAccountValidForOffer(offer, user.getPaymentAccounts()); } public boolean hasSameProtocolVersion(Offer offer) { diff --git a/core/src/main/java/bisq/core/payment/PaymentAccount.java b/core/src/main/java/bisq/core/payment/PaymentAccount.java index a540641319..1e481e4458 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccount.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccount.java @@ -198,6 +198,10 @@ public abstract class PaymentAccount implements PersistablePayload { return this instanceof MoneyGramAccount; } + public boolean isTransferwiseAccount() { + return this instanceof TransferwiseAccount; + } + /** * Return an Optional of the trade currency for this payment account, or * Optional.empty() if none is found. If this payment account has a selected diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java b/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java index 08a96db151..fc810b017d 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountUtil.java @@ -41,10 +41,10 @@ import javax.annotation.Nullable; @Slf4j public class PaymentAccountUtil { - public static boolean isAnyTakerPaymentAccountValidForOffer(Offer offer, - Collection takerPaymentAccounts) { - for (PaymentAccount takerPaymentAccount : takerPaymentAccounts) { - if (isTakerPaymentAccountValidForOffer(offer, takerPaymentAccount)) + public static boolean isAnyPaymentAccountValidForOffer(Offer offer, + Collection paymentAccounts) { + for (PaymentAccount paymentAccount : paymentAccounts) { + if (isPaymentAccountValidForOffer(offer, paymentAccount)) return true; } return false; @@ -55,7 +55,7 @@ public class PaymentAccountUtil { AccountAgeWitnessService accountAgeWitnessService) { ObservableList result = FXCollections.observableArrayList(); result.addAll(paymentAccounts.stream() - .filter(paymentAccount -> isTakerPaymentAccountValidForOffer(offer, paymentAccount)) + .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) .filter(paymentAccount -> isAmountValidForOffer(offer, paymentAccount, accountAgeWitnessService)) .collect(Collectors.toList())); return result; @@ -79,7 +79,7 @@ public class PaymentAccountUtil { "Payment method from offer: " + offer.getPaymentMethod().toString(); } - public static boolean isTakerPaymentAccountValidForOffer(Offer offer, PaymentAccount paymentAccount) { + public static boolean isPaymentAccountValidForOffer(Offer offer, PaymentAccount paymentAccount) { return new ReceiptValidator(offer, paymentAccount).isValid(); } @@ -144,23 +144,4 @@ public class PaymentAccountUtil { filter(e -> e.getPaymentAccountPayload().equals(paymentAccountPayload)) .findAny(); } - - // TODO no code duplication found in UI code (added for API) - // That is optional and set to null if not supported (AltCoins,...) - /* public static String getCountryCode(PaymentAccount paymentAccount) { - if (paymentAccount instanceof CountryBasedPaymentAccount) { - Country country = ((CountryBasedPaymentAccount) paymentAccount).getCountry(); - return country != null ? country.code : null; - } else { - return null; - } - }*/ - - // TODO no code duplication found in UI code (added for API) - /*public static long getMaxTradeLimit(AccountAgeWitnessService accountAgeWitnessService, PaymentAccount paymentAccount, String currencyCode) { - if (paymentAccount != null) - return accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode); - else - return 0; - }*/ } diff --git a/core/src/main/java/bisq/core/payment/PaymentAccounts.java b/core/src/main/java/bisq/core/payment/PaymentAccounts.java index c27c883449..6f871ce20f 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccounts.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccounts.java @@ -41,7 +41,7 @@ class PaymentAccounts { private final BiFunction validator; PaymentAccounts(Set accounts, AccountAgeWitnessService accountAgeWitnessService) { - this(accounts, accountAgeWitnessService, PaymentAccountUtil::isTakerPaymentAccountValidForOffer); + this(accounts, accountAgeWitnessService, PaymentAccountUtil::isPaymentAccountValidForOffer); } PaymentAccounts(Set accounts, AccountAgeWitnessService accountAgeWitnessService, diff --git a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java index dc48c8c545..68b8718e35 100644 --- a/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java +++ b/desktop/src/test/java/bisq/desktop/main/offer/offerbook/OfferBookViewModelTest.java @@ -105,46 +105,46 @@ public class OfferBookViewModelTest { Collection paymentAccounts; paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSepaAccount("EUR", "DE", "1212324", new ArrayList<>(Arrays.asList("AT", "DE"))))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // empty paymentAccounts paymentAccounts = new ArrayList<>(); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer(getSEPAPaymentMethod("EUR", "AT", + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer(getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // simple cases: same payment methods // offer: alipay paymentAccount: alipay - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getAliPayAccount("CNY"))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getAliPayPaymentMethod("EUR"), paymentAccounts)); // offer: ether paymentAccount: ether - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getCryptoAccount("ETH"))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getBlockChainsPaymentMethod("ETH"), paymentAccounts)); // offer: sepa paymentAccount: sepa - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSepaAccount("EUR", "AT", "1212324", new ArrayList<>(Arrays.asList("AT", "DE"))))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // offer: nationalBank paymentAccount: nationalBank - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("EUR", "AT", "PSK"))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // offer: SameBank paymentAccount: SameBank - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSameBankAccount("EUR", "AT", "PSK"))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSameBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // offer: sepa paymentAccount: sepa - diff. country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSepaAccount("EUR", "DE", "1212324", new ArrayList<>(Arrays.asList("AT", "DE"))))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); @@ -152,79 +152,79 @@ public class OfferBookViewModelTest { // offer: sepa paymentAccount: sepa - same country, same currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSepaAccount("EUR", "AT", "1212324", new ArrayList<>(Arrays.asList("AT", "DE"))))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // offer: sepa paymentAccount: nationalBank - same country, same currency // wrong method paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("EUR", "AT", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // wrong currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("USD", "US", "XXX"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // wrong country paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("EUR", "FR", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // sepa wrong country paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("EUR", "CH", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // sepa wrong currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getNationalBankAccount("CHF", "DE", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getSEPAPaymentMethod("EUR", "AT", new ArrayList<>(Arrays.asList("AT", "DE")), "PSK"), paymentAccounts)); // same bank paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSameBankAccount("EUR", "AT", "PSK"))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // not same bank paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSameBankAccount("EUR", "AT", "Raika"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // same bank, wrong country paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSameBankAccount("EUR", "DE", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // same bank, wrong currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSameBankAccount("USD", "AT", "PSK"))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // spec. bank paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSpecificBanksAccount("EUR", "AT", "PSK", new ArrayList<>(Arrays.asList("PSK", "Raika"))))); - assertTrue(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertTrue(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // spec. bank, missing bank paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSpecificBanksAccount("EUR", "AT", "PSK", new ArrayList<>(FXCollections.singletonObservableList("Raika"))))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // spec. bank, wrong country paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSpecificBanksAccount("EUR", "FR", "PSK", new ArrayList<>(Arrays.asList("PSK", "Raika"))))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); // spec. bank, wrong currency paymentAccounts = new ArrayList<>(FXCollections.singletonObservableList(getSpecificBanksAccount("USD", "AT", "PSK", new ArrayList<>(Arrays.asList("PSK", "Raika"))))); - assertFalse(PaymentAccountUtil.isAnyTakerPaymentAccountValidForOffer( + assertFalse(PaymentAccountUtil.isAnyPaymentAccountValidForOffer( getNationalBankPaymentMethod("EUR", "AT", "PSK"), paymentAccounts)); //TODO add more tests