diff --git a/src/main/java/io/zold/api/Wallet.java b/src/main/java/io/zold/api/Wallet.java index cdb0bc9..d8c952e 100644 --- a/src/main/java/io/zold/api/Wallet.java +++ b/src/main/java/io/zold/api/Wallet.java @@ -53,6 +53,7 @@ public interface Wallet { * This wallet's ID: an unsigned 64-bit integer. * @return This wallet's id * @throws IOException If an IO error occurs + * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) * @checkstyle MethodName (2 lines) */ long id() throws IOException; @@ -70,6 +71,7 @@ public interface Wallet { * same wallet, as identified by their {@link #id() id}. * @param other Other wallet * @return The merged wallet + * @throws IOException If an IO error occurs */ Wallet merge(Wallet other) throws IOException; @@ -90,6 +92,9 @@ final class Fake implements Wallet { */ private final long id; + /** + * Transactions. + */ private final Iterable transactions; /** @@ -100,10 +105,20 @@ public Fake(final long id) { this(id, new IterableOf<>()); } + /** + * Ctor. + * @param id The wallet id. + * @param transactions Transactions. + */ public Fake(final long id, final Transaction... transactions) { this(id, new IterableOf<>(transactions)); } + /** + * Ctor. + * @param id The wallet id. + * @param transactions Transactions. + */ public Fake(final long id, final Iterable transactions) { this.id = id; this.transactions = transactions; @@ -175,6 +190,21 @@ public void pay(final long amt, final long bnf) throws IOException { } @Override + // @todo #16:30min Following transactions should be ignored according + // to the whitepaper: + // a) If the transaction is negative and its signature is not valid, + // it is ignored; + // b) If the transaction makes the balance of the wallet negative, + // it is ignored; + // c) If the transaction is positive and it’s absent in the paying + // wallet (which exists at the node), it’s ignored; If the paying + // wallet doesn’t exist at the node, the transaction is ignored; + // + // @todo: #16:30min Merge method should update transactions + // in wallet's file and return concrete implementation not a fake one. + // Beware that tests should be refactored to take care of file cleanup + // after each case that merges wallets. + // public Wallet merge(final Wallet other) throws IOException { if (other.id() != this.id()) { throw new IOException( @@ -188,16 +218,17 @@ public Wallet merge(final Wallet other) throws IOException { ); } final Iterable ledger = this.ledger(); - final Collection candidates = new ArrayList<>(); + final Collection candidates = new ArrayList<>(0); for (final Transaction remote : other.ledger()) { final Collection filtered = new Filtered<>( input -> new UncheckedScalar<>( new Or( () -> remote.equals(input), - () -> remote.id() == input.id() && - remote.bnf() == input.bnf(), - () -> remote.id() == input.id() && remote.amount() < 0L, + () -> remote.id() == input.id() + && remote.bnf().equals(input.bnf()), + () -> remote.id() == input.id() + && remote.amount() < 0L, () -> remote.prefix().equals(input.prefix()) ) ).value(), @@ -207,10 +238,12 @@ public Wallet merge(final Wallet other) throws IOException { candidates.add(remote); } } - return new Wallet.Fake(this.id(), new Joined<>(ledger, candidates)); + return new Wallet.Fake( + this.id(), + new Joined(ledger, candidates) + ); } - @Override public Iterable ledger() { return new Mapped<>( diff --git a/src/test/java/io/zold/api/WalletTest.java b/src/test/java/io/zold/api/WalletTest.java index a707c5b..d9a88f8 100644 --- a/src/test/java/io/zold/api/WalletTest.java +++ b/src/test/java/io/zold/api/WalletTest.java @@ -46,7 +46,10 @@ * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle JavadocVariableCheck (500 lines) * @checkstyle MagicNumberCheck (500 lines) + * @checkstyle LineLengthCheck (500 lines) + * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ +@SuppressWarnings("PMD.TooManyMethods") public final class WalletTest { @Rule @@ -127,7 +130,7 @@ public void doesNotMergeExistingTransactions() throws IOException { final Wallet merged = wallet.merge( new Wallet.Fake( id, - new RtTransaction("003b;2017-07-19T21:25:07Z;ffffffffffa72367;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4...") + new RtTransaction("003b;2017-07-19T21:25:07Z;0000000000a72366;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4...") ) ); MatcherAssert.assertThat( @@ -143,7 +146,40 @@ public void doesNotMergeTransactionsWithSameIdAndBnf() throws IOException { final Wallet merged = wallet.merge( new Wallet.Fake( id, - new RtTransaction("003b;2017-07-18T21:25:07Z;ffffffffffa72367;xxsQuJa9;98bb82c81735c4ee;For food;QCuLuVr4...") + new RtTransaction("003b;2017-07-18T21:25:07Z;0000000000a72366;xxxxuuuu;98bb82c81735c4ee;For food;QCuLuVr4...") + ) + ); + MatcherAssert.assertThat( + new CollectionOf<>(merged.ledger()).size(), + new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + ); + } + + @Test + public void doesNotMergeTransactionsWithSameIdAndNegativeAmount() + throws IOException { + final long id = 5124095577148911L; + final Wallet wallet = new Wallet.File(this.wallet(id)); + final Wallet merged = wallet.merge( + new Wallet.Fake( + id, + new RtTransaction("003b;2017-07-18T21:25:07Z;ffffffffffa72366;xxxxuuuu;98bb82c81735c4ee;For food;QCuLuVr4...") + ) + ); + MatcherAssert.assertThat( + new CollectionOf<>(merged.ledger()).size(), + new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + ); + } + + @Test + public void doesNotMergeTransactionsWithSamePrefix() throws IOException { + final long id = 5124095577148911L; + final Wallet wallet = new Wallet.File(this.wallet(id)); + final Wallet merged = wallet.merge( + new Wallet.Fake( + id, + new RtTransaction("0011;2017-07-18T21:25:07Z;0000000000a72366;xksQuJa9;99bb82c81735c4ee;For food;QCuLuVr4...") ) ); MatcherAssert.assertThat(