@Test
public void basicFeeSolverTests() throws Exception {

    sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, Coin.COIN);
    // Simple test to make sure if we have an ouput < 0.01 we get a fee
    SendRequest request1 = SendRequest.to(OTHER_ADDRESS, CENT.subtract(SATOSHI));
    request1.ensureMinRequiredFee = true;
    wallet.completeTx(request1);
    Transaction spend1 = request1.tx;
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee());
    assertEquals(2, spend1.getOutputs().size());
    // ...but not more fee than what we request
    SendRequest request3 = SendRequest.to(OTHER_ADDRESS, CENT.subtract(SATOSHI));
    request3.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI);
    request3.ensureMinRequiredFee = true;
    wallet.completeTx(request3);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request3.tx.getFee());
    assertEquals(2, request3.tx.getOutputs().size());
    // ...unless we need it
    SendRequest request4 = SendRequest.to(OTHER_ADDRESS, CENT.subtract(SATOSHI));
    request4.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.subtract(SATOSHI);
    request4.ensureMinRequiredFee = true;
    wallet.completeTx(request4);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request4.tx.getFee());
    assertEquals(2, request4.tx.getOutputs().size());
    // If we would have a change output < 0.01, it should add the fee
    SendRequest request5 = SendRequest.to(OTHER_ADDRESS, Coin.COIN.subtract(CENT.subtract(SATOSHI)));
    request5.ensureMinRequiredFee = true;
    wallet.completeTx(request5);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request5.tx.getFee());
    assertEquals(2, request5.tx.getOutputs().size());
    // If change is 0.1-satoshi and we already have a 0.1-satoshi output, fee should be reference fee
    SendRequest request7 = SendRequest.to(OTHER_ADDRESS, Coin.COIN.subtract(CENT.subtract(SATOSHI.multiply(2)).multiply(2)));
    request7.ensureMinRequiredFee = true;
    request7.tx.addOutput(CENT.subtract(SATOSHI), OTHER_ADDRESS);
    wallet.completeTx(request7);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request7.tx.getFee());
    assertEquals(3, request7.tx.getOutputs().size());
    // If we would have a change output == REFERENCE_DEFAULT_MIN_TX_FEE that would cause a fee, throw it away and make it fee
    SendRequest request8 = SendRequest.to(OTHER_ADDRESS, COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE));
    request8.ensureMinRequiredFee = true;
    wallet.completeTx(request8);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request8.tx.getFee());
    assertEquals(1, request8.tx.getOutputs().size());
    // ...in fact, also add fee if we would get back less than MIN_NONDUST_OUTPUT
    SendRequest request9 = SendRequest.to(OTHER_ADDRESS, COIN.subtract(
            Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).subtract(SATOSHI)));
    request9.ensureMinRequiredFee = true;
    wallet.completeTx(request9);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).subtract(SATOSHI), request9.tx.getFee());
    assertEquals(1, request9.tx.getOutputs().size());
    // ...but if we get back any more than that, we should get a refund (but still pay fee)
    SendRequest request10 = SendRequest.to(OTHER_ADDRESS, COIN.subtract(
            Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)));
    request10.ensureMinRequiredFee = true;
    wallet.completeTx(request10);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request10.tx.getFee());
    assertEquals(2, request10.tx.getOutputs().size());
    // ...of course fee should be min(request.fee, MIN_TX_FEE) so we should get MIN_TX_FEE.add(SATOSHI) here
    SendRequest request11 = SendRequest.to(OTHER_ADDRESS, COIN.subtract(
            Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(SATOSHI.multiply(2))));
    request11.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI);
    request11.ensureMinRequiredFee = true;
    wallet.completeTx(request11);
    assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request11.tx.getFee());
    assertEquals(2, request11.tx.getOutputs().size());
}