diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index f06ed47..966405c 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -17,7 +17,7 @@ jobs: with: distribution: 'temurin' java-version: 21 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.m2/repository key: maven-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/mvn.yml b/.github/workflows/mvn.yml index 64c5366..5784082 100644 --- a/.github/workflows/mvn.yml +++ b/.github/workflows/mvn.yml @@ -17,14 +17,14 @@ jobs: strategy: matrix: os: [ubuntu-24.04, windows-2022, macos-15] - java: [11, 17] + java: [21] steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: ${{ matrix.java }} - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-jdk-${{ matrix.java }}-maven-${{ hashFiles('**/pom.xml') }} diff --git a/README.md b/README.md index 52b3a3d..b9a17d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ - +# Zold Java API + +![Zold logo](https://www.zold.io/logo.svg) [![EO principles respected here](https://www.elegantobjects.org/badge.svg)](https://www.elegantobjects.org) [![DevOps By Rultor.com](https://www.rultor.com/b/zold-io/java-api)](https://www.rultor.com/p/zold-io/java-api) @@ -27,7 +29,9 @@ All you need is this: Java version required: 1.8+. -**We recommend you read the Zold [whitepaper](https://papers.zold.io/wp.pdf) in order to understand the concepts behind this API.** +**We recommend you read the Zold +[whitepaper](https://papers.zold.io/wp.pdf) in order to +understand the concepts behind this API.** First, you find a wallet in a directory of wallets: @@ -69,7 +73,7 @@ Just fork the repo and send us a pull request. Make sure your branch builds without any warnings/issues: -``` +```bash mvn clean install -Pqulice ``` @@ -77,9 +81,15 @@ mvn clean install -Pqulice These are the requirements for this API. -**Note:** The original whitepaper on *zold* can be found [here](https://www.zold.io/). The whitepaper and the documentation found at www.zold.io serve as the highest authority on the subject of *zold*. The following requirements are condensed versions of the points expressed in the aforementioned docs as they relate to the scope of this project: +**Note:** The original whitepaper on *zold* can be found in the +[Zold whitepaper](https://www.zold.io/). The whitepaper and the documentation +found at serve as the highest authority on the subject +of *zold*. The following requirements are condensed versions of the points +expressed in the aforementioned docs as they relate to the scope of this +project: -* Maintain a wallet in structured textual format, within which is a ledger that contains transactions for that wallet. +* Maintain a wallet in structured textual format, within which is a ledger + that contains transactions for that wallet. * Make payments: * Taxes according to fixed formula * Payments to other wallets @@ -88,36 +98,66 @@ These are the requirements for this API. * Receive payments: * Pull the paying wallet from the network * Merge the copies of the paying wallet with our own copy -* We need to refresh our local database of network nodes by querying the network. +* We need to refresh our local database of network nodes by querying + the network. * We must implement with Java 8 * Non-functional requirements were not made, but we expect * Flawless concurrency * "Decent" performance - * Design must respect the principles of [elegant objects](www.elegantobjects.org) - * Design must resemble the design of the original [ruby API](https://github.com/zold-io/zold) - + * Design must respect the principles of + [elegant objects](https://www.elegantobjects.org) + * Design must resemble the design of the original + [ruby API](https://github.com/zold-io/zold) ## Decisions and Alternatives -* `javax-json` is a Java API that can parse and also write JSON. As part of the EE7 spec, it is stable, well established, and is the standard. We can use it to write to our local database file. Alternatives are google's [gson](https://github.com/google/gson), [JSON-java](https://github.com/stleary/JSON-java), [jackson-databind](https://github.com/FasterXML/jackson-databind/), and many others. -* The standard `java.security` package contains everything we need to import keystores and sign/encrypt messages with RSA keys. There are lots of examples on the internet on how to use it. I am not aware of any other popular alternative out there. -* `cactoos-http` is a new object-oriented HTTP API under current development as part of project `cactoos` in Zerocracy. It is expected to be ready by the time this API goes to production. Other alternatives are Apache's [http client](https://hc.apache.org/httpcomponents-client-4.5.x/index.html) (not object-oriented), `jcabi-http` (too many dependencies), and many others. -* Our API will consist of our core classes that will communicate with the network using cactoos-http + javax.json, a local storage (`nodes.json`) for persistence of remote node data, will use the `java.security` package when signing the transactions, and will expect wallet files to have the `.z` extension ([discuss](https://github.com/zold-io/zold/issues/164)) and conform to the format specified in the whitepaper: +* `javax-json` is a Java API that can parse and also write JSON. As part of + the EE7 spec, it is stable, well established, and is the standard. We can + use it to write to our local database file. Alternatives are Google's + [gson](https://github.com/google/gson), + [JSON-java](https://github.com/stleary/JSON-java), + [jackson-databind](https://github.com/FasterXML/jackson-databind/), + and many others. +* The standard `java.security` package contains everything we need to import + keystores and sign/encrypt messages with RSA keys. There are lots of + examples on the internet on how to use it. I am not aware of any other + popular alternative out there. +* `cactoos-http` is a new object-oriented HTTP API under current development + as part of project `cactoos` in Zerocracy. It is expected to be ready by + the time this API goes to production. Other alternatives are Apache's + [http client](https://hc.apache.org/httpcomponents-client-4.5.x/index.html) + (not object-oriented), `jcabi-http` (too many dependencies), and many + others. +* Our API will consist of our core classes that will communicate with + the network using cactoos-http + javax.json, a local storage + (`nodes.json`) for persistence of remote node data, will use the + `java.security` package when signing the transactions, and will expect + wallet files to have the `.z` extension + ([discuss](https://github.com/zold-io/zold/issues/164)) and conform to + the format specified in the whitepaper: ![architecture](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/zold-io/java-api/master/src/site/resources/plantuml/architecture.plantuml) ## Concerns -* `cactoos-http` is designed according to the principles of EO, although it still has mayor hurdles to overcome (eg. see [#62](https://github.com/yegor256/cactoos-http/issues/62)). -* `javax.json` will parse data from the zold network and write our local database file in structured JSON format. Its usage is very simple, although we will probably have to be careful with regards to concurrent access to the file. +* `cactoos-http` is designed according to the principles of EO, although it + still has major hurdles to overcome (e.g. see + [#62](https://github.com/yegor256/cactoos-http/issues/62)). +* `javax.json` will parse data from the zold network and write our local + database file in structured JSON format. Its usage is very simple, + although we will probably have to be careful with regards to concurrent + access to the file. * `java.security` runtimes can handle RSA and MD5 on all platforms. ## Assumptions -* `cactoos-http` will reach the maturity level necessary to support our requirements +* `cactoos-http` will reach the maturity level necessary to support our + requirements * We can flawlessly manage synchronized access to our local database file ## Risks -* The `cactoos-http` project might not obtain the resources to reach maturity, or may not reach maturity for some other reason. -* Our bottleneck will be reading/writing our local database file. We might not be able to manage a "heavy" throughput. +* The `cactoos-http` project might not obtain the resources to reach + maturity, or may not reach maturity for some other reason. +* Our bottleneck will be reading/writing our local database file. We might + not be able to manage a "heavy" throughput. diff --git a/pom.xml b/pom.xml index aede2ef..f17d04d 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.jcabi parent - 0.66.0 + 0.73.1 io.zold java-api @@ -70,7 +70,7 @@ com.qulice qulice-maven-plugin - 0.17.4 + 0.27.6 checkstyle:/src/site/resources/.* @@ -86,7 +86,7 @@ org.cactoos cactoos - 0.35 + 0.61.0 javax.json @@ -95,25 +95,25 @@ com.github.victornoel.eo eo-envelopes - 0.0.3 + 1.0.0 provided org.llorllale cactoos-matchers - 0.11 + 0.25 test nl.jqno.equalsverifier equalsverifier - 2.4.8 + 4.5 test org.junit.vintage junit-vintage-engine - 5.9.3 + 5.14.4 test @@ -121,11 +121,17 @@ junit 4.13.2 test + + + org.hamcrest + hamcrest-core + + org.hamcrest - hamcrest-core - 1.3 + hamcrest + 3.0 test diff --git a/src/main/java/io/zold/api/Copies.java b/src/main/java/io/zold/api/Copies.java index 2cc7a92..c0a13b2 100644 --- a/src/main/java/io/zold/api/Copies.java +++ b/src/main/java/io/zold/api/Copies.java @@ -8,11 +8,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.cactoos.collection.CollectionOf; import org.cactoos.iterable.IterableEnvelope; import org.cactoos.iterable.IterableOf; import org.cactoos.iterable.Joined; import org.cactoos.iterable.Mapped; +import org.cactoos.list.ListOf; /** * Multiple copies of a Wallet. @@ -22,11 +22,11 @@ public final class Copies extends IterableEnvelope { /** * Ctor. - * @param id Id of the wallet to pull. - * @param remotes Remote nodes. + * @param id Id of the wallet to pull + * @param remotes Remote nodes */ Copies(final long id, final Iterable remotes) { - super(() -> copies(id, remotes)); + super(new IterableOf<>(() -> copies(id, remotes).iterator())); } /** @@ -36,7 +36,6 @@ public final class Copies extends IterableEnvelope { * @return Iterable Iterable of Copy * @throws IOException If fails */ - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private static Iterable copies(final long id, final Iterable remotes) throws IOException { final List copies = new ArrayList<>(10); @@ -51,10 +50,10 @@ private static Iterable copies(final long id, } } if (!updated) { - copies.add(new Copy(wallet, remote)); + copies.add(new Copies.Copy(wallet, remote)); } } - return new IterableOf<>(copies); + return new IterableOf<>(copies.iterator()); } /** @@ -69,9 +68,9 @@ private static Iterable copies(final long id, */ private static boolean equalWallets(final Wallet first, final Wallet second) throws IOException { - return first.id() == second.id() && new CollectionOf<>( + return first.id() == second.id() && new ListOf<>( first.ledger() - ).size() == new CollectionOf<>(second.ledger()).size(); + ).size() == new ListOf<>(second.ledger()).size(); } /** @@ -92,8 +91,8 @@ static final class Copy implements Comparable { /** * Ctor. - * @param wallet The wallet. - * @param remotes The remote nodes where the wallet was found. + * @param wallet The wallet + * @param remotes The remote nodes where the wallet was found */ Copy(final Wallet wallet, final Remote... remotes) { this(wallet, new IterableOf<>(remotes)); @@ -101,42 +100,53 @@ static final class Copy implements Comparable { /** * Ctor. - * @param wallet The wallet. - * @param remotes The remote nodes where the wallet was found. + * @param wallet The wallet + * @param remotes The remote nodes where the wallet was found */ Copy(final Wallet wallet, final Iterable remotes) { this.wlt = wallet; this.remotes = remotes; } + @Override + public int compareTo(final Copy other) { + return this.score().compareTo(other.score()); + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof Copy + && this.compareTo((Copy) obj) == 0; + } + + @Override + public int hashCode() { + return this.wlt.hashCode(); + } + /** * Creates new Copy instance with additional remote. * @param remote Remote * @return Copy Copy */ - public Copy with(final Remote remote) { - return new Copy(this.wallet(), new Joined<>(remote, this.remotes)); + Copies.Copy with(final Remote remote) { + return new Copies.Copy(this.wallet(), new Joined<>(remote, this.remotes)); } /** * The wallet. - * @return The wallet. + * @return The wallet */ - public Wallet wallet() { + Wallet wallet() { return this.wlt; } /** * The summary of the score of all the remote nodes. - * @return The score. + * @return The score */ - public Score score() { + Score score() { return new Score.Summed(new Mapped<>(Remote::score, this.remotes)); } - - @Override - public int compareTo(final Copy other) { - return this.score().compareTo(other.score()); - } } } diff --git a/src/main/java/io/zold/api/CpTransaction.java b/src/main/java/io/zold/api/CpTransaction.java index dab8f0c..abb7dd5 100644 --- a/src/main/java/io/zold/api/CpTransaction.java +++ b/src/main/java/io/zold/api/CpTransaction.java @@ -6,7 +6,6 @@ /** * Computed Transaction. - * * @since 1.0 * @todo #54:30min Implement the computation of the transaction string * based on the white paper. The unit tests should also be updated to @@ -17,9 +16,9 @@ public final class CpTransaction extends TransactionEnvelope { /** * Ctor. - * * @param amt Amount to pay in zents * @param bnf Wallet ID of beneficiary + * @checkstyle ConstructorsCodeFreeCheck (3 lines) */ CpTransaction(final long amt, final long bnf) { super(new RtTransaction(Long.toString(amt + bnf))); diff --git a/src/main/java/io/zold/api/Network.java b/src/main/java/io/zold/api/Network.java index f8700f9..53f222c 100644 --- a/src/main/java/io/zold/api/Network.java +++ b/src/main/java/io/zold/api/Network.java @@ -8,7 +8,6 @@ /** * Network of remote nodes. - * * @since 0.1 */ public interface Network extends Iterable { @@ -26,5 +25,4 @@ public interface Network extends Iterable { * @throws IOException If an IO error occurs */ Wallet pull(long id) throws IOException; - } diff --git a/src/main/java/io/zold/api/Remote.java b/src/main/java/io/zold/api/Remote.java index 3395a26..20d630b 100644 --- a/src/main/java/io/zold/api/Remote.java +++ b/src/main/java/io/zold/api/Remote.java @@ -6,14 +6,14 @@ package io.zold.api; import org.cactoos.iterable.Repeated; -import org.cactoos.text.RandomText; +import org.cactoos.text.Randomized; /** * Remote node. - * * @since 0.1 */ public interface Remote { + /** * This remote node's score. * @return The score @@ -35,6 +35,7 @@ public interface Remote { /** * A Fake {@link Remote}. + * @since 1.0 */ final class Fake implements Remote { @@ -49,7 +50,7 @@ final class Fake implements Remote { */ public Fake(final int val) { this(new RtScore( - new Repeated<>(val, new RandomText()) + new Repeated<>(val, new Randomized()) )); } diff --git a/src/main/java/io/zold/api/RtNetwork.java b/src/main/java/io/zold/api/RtNetwork.java index ae2cd74..9a189ab 100644 --- a/src/main/java/io/zold/api/RtNetwork.java +++ b/src/main/java/io/zold/api/RtNetwork.java @@ -8,12 +8,11 @@ import java.util.Iterator; import org.cactoos.iterable.Mapped; import org.cactoos.iterable.Sorted; -import org.cactoos.scalar.IoCheckedScalar; +import org.cactoos.scalar.IoChecked; import org.cactoos.scalar.Reduced; /** * Network implementation. - * * @since 0.1 * @todo #5:30min We must figure out how to 'load' some network. Loading the * network will be loading a local JSON file that contains data on all @@ -32,7 +31,7 @@ public final class RtNetwork implements Network { * @param remotes Remotes of the network */ RtNetwork(final Iterable remotes) { - this.nodes = remotes; + this.nodes = remotes; } @Override @@ -44,7 +43,7 @@ public void push(final Wallet wallet) { @Override public Wallet pull(final long id) throws IOException { - return new IoCheckedScalar<>( + return new IoChecked<>( new Reduced<>( Wallet::merge, new Mapped<>( diff --git a/src/main/java/io/zold/api/RtScore.java b/src/main/java/io/zold/api/RtScore.java index 5e74eaf..e73ecd4 100644 --- a/src/main/java/io/zold/api/RtScore.java +++ b/src/main/java/io/zold/api/RtScore.java @@ -5,11 +5,11 @@ package io.zold.api; import org.cactoos.Text; -import org.cactoos.iterable.LengthOf; +import org.cactoos.scalar.LengthOf; +import org.cactoos.scalar.Unchecked; /** * Default implementation for {@link Score}. - * * @since 1.0 */ public final class RtScore implements Score { @@ -21,8 +21,7 @@ public final class RtScore implements Score { /** * Ctor. - * - * @param sfxs The suffixes. + * @param sfxs The suffixes */ RtScore(final Iterable sfxs) { this.sfxs = sfxs; @@ -30,8 +29,8 @@ public final class RtScore implements Score { @Override public int compareTo(final Score other) { - return new LengthOf(other.suffixes()).intValue() - - new LengthOf(this.sfxs).intValue(); + return new Unchecked<>(new LengthOf(other.suffixes())).value().intValue() + - new Unchecked<>(new LengthOf(this.sfxs)).value().intValue(); } @Override diff --git a/src/main/java/io/zold/api/RtTransaction.java b/src/main/java/io/zold/api/RtTransaction.java index ffeabeb..9bc99ec 100644 --- a/src/main/java/io/zold/api/RtTransaction.java +++ b/src/main/java/io/zold/api/RtTransaction.java @@ -11,27 +11,24 @@ import java.util.List; import java.util.regex.Pattern; import org.cactoos.Text; -import org.cactoos.iterable.LengthOf; import org.cactoos.list.ListOf; -import org.cactoos.scalar.IoCheckedScalar; +import org.cactoos.scalar.IoChecked; import org.cactoos.scalar.ItemAt; -import org.cactoos.scalar.StickyScalar; -import org.cactoos.scalar.UncheckedScalar; +import org.cactoos.scalar.LengthOf; +import org.cactoos.scalar.Sticky; +import org.cactoos.scalar.Unchecked; import org.cactoos.text.FormattedText; -import org.cactoos.text.SplitText; +import org.cactoos.text.Split; import org.cactoos.text.TextOf; -import org.cactoos.text.TrimmedText; +import org.cactoos.text.Trimmed; import org.cactoos.text.UncheckedText; import org.cactoos.time.ZonedDateTimeOf; /** * RtTransaction. - * * @since 0.1 * @checkstyle ClassDataAbstractionCoupling (3 lines) */ -@SuppressWarnings({"PMD.AvoidCatchingGenericException", - "PMD.AvoidFieldNameMatchingMethodName"}) final class RtTransaction implements Transaction { /** @@ -66,18 +63,19 @@ final class RtTransaction implements Transaction { /** * String representation of transaction. */ - private final IoCheckedScalar transaction; + private final IoChecked transaction; /** * Ctor. * @param trnsct String representation of transaction + * @checkstyle LambdaBodyLengthCheck (28 lines) */ RtTransaction(final String trnsct) { - this.transaction = new IoCheckedScalar<>( - new StickyScalar<>( + this.transaction = new IoChecked<>( + new Sticky<>( () -> { if ( - new TrimmedText( + new Trimmed( new TextOf(trnsct) ).asString().isEmpty() ) { @@ -87,10 +85,10 @@ final class RtTransaction implements Transaction { } final List pieces = new ListOf<>( - new SplitText(trnsct, ";") + new Split(trnsct, ";") ); // @checkstyle MagicNumberCheck (1 line) - if (new LengthOf(pieces).intValue() != 7) { + if (new LengthOf(pieces).value().intValue() != 7) { throw new IOException( new FormattedText( // @checkstyle LineLength (1 line) @@ -106,12 +104,11 @@ final class RtTransaction implements Transaction { } @Override - @SuppressWarnings("PMD.ShortMethodName") public int id() throws IOException { final String ident = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( - 0, new SplitText(this.transaction.value(), ";") + 0, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -134,9 +131,9 @@ public int id() throws IOException { public ZonedDateTime time() throws IOException { return new ZonedDateTimeOf( new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( - 1, new SplitText(this.transaction.value(), ";") + 1, new Split(this.transaction.value(), ";") ) ).value() ).asString(), @@ -147,9 +144,9 @@ public ZonedDateTime time() throws IOException { @Override public long amount() throws IOException { final String amnt = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( - 2, new SplitText(this.transaction.value(), ";") + 2, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -171,10 +168,10 @@ public long amount() throws IOException { @Override public String prefix() throws IOException { final String prefix = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( //@checkstyle MagicNumberCheck (1 line) - 3, new SplitText(this.transaction.value(), ";") + 3, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -191,10 +188,10 @@ public String prefix() throws IOException { @Override public String bnf() throws IOException { final String bnf = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( //@checkstyle MagicNumberCheck (1 line) - 4, new SplitText(this.transaction.value(), ";") + 4, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -215,10 +212,10 @@ public String bnf() throws IOException { @Override public String details() throws IOException { final String dtls = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( //@checkstyle MagicNumberCheck (1 line) - 5, new SplitText(this.transaction.value(), ";") + 5, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -239,10 +236,10 @@ public String details() throws IOException { @Override public String signature() throws IOException { final String sign = new UncheckedText( - new IoCheckedScalar<>( + new IoChecked<>( new ItemAt<>( //@checkstyle MagicNumberCheck (1 line) - 6, new SplitText(this.transaction.value(), ";") + 6, new Split(this.transaction.value(), ";") ) ).value() ).asString(); @@ -264,11 +261,10 @@ public String signature() throws IOException { @Override public String toString() { - return new UncheckedScalar<>(this.transaction).value(); + return new Unchecked<>(this.transaction).value(); } @Override - @SuppressWarnings("PMD.OnlyOneReturn") public boolean equals(final Object obj) { if (this == obj) { return true; @@ -276,8 +272,7 @@ public boolean equals(final Object obj) { if (obj == null || this.getClass() != obj.getClass()) { return false; } - final RtTransaction that = (RtTransaction) obj; - return this.transaction.equals(that.transaction); + return this.transaction.equals(((RtTransaction) obj).transaction); } @Override diff --git a/src/main/java/io/zold/api/Score.java b/src/main/java/io/zold/api/Score.java index ae62862..5d5120b 100644 --- a/src/main/java/io/zold/api/Score.java +++ b/src/main/java/io/zold/api/Score.java @@ -12,9 +12,9 @@ /** * A remote node's score, equal to its number of suffixes. * - * The natural order of {@link Score} is from highest to lowest. + *

The natural order of {@link Score} is from highest to lowest. * - * Note: {@link Score} has a natural ordering that is inconsistent with equals. + *

Note: {@link Score} has a natural ordering that is inconsistent with equals. * * @since 0.1 */ @@ -30,14 +30,13 @@ public interface Score extends Comparable { /** * Summary of multiple {@link Score}. - * * @since 1.0 */ final class Summed extends ScoreEnvelope { + /** * Ctor. - * - * @param scores Multiple scores to summary. + * @param scores Multiple scores to summary */ Summed(final Iterable scores) { super(new RtScore( diff --git a/src/main/java/io/zold/api/TaxBeneficiaries.java b/src/main/java/io/zold/api/TaxBeneficiaries.java index 004b3e0..72c3b8e 100644 --- a/src/main/java/io/zold/api/TaxBeneficiaries.java +++ b/src/main/java/io/zold/api/TaxBeneficiaries.java @@ -7,27 +7,26 @@ import java.util.Comparator; import org.cactoos.iterable.Filtered; import org.cactoos.iterable.IterableEnvelope; -import org.cactoos.iterable.LengthOf; import org.cactoos.iterable.Sorted; +import org.cactoos.scalar.LengthOf; /** * {@link Remote} nodes that should receive taxes. - * * @since 1.0 */ public final class TaxBeneficiaries extends IterableEnvelope { /** * Ctor. - * - * @param nodes Remote nodes to select from. + * @param nodes Remote nodes to select from + * @checkstyle ConstructorsCodeFreeCheck (10 lines) */ public TaxBeneficiaries(final Iterable nodes) { - super(() -> new Sorted<>( + super(new Sorted<>( Comparator.comparing(Remote::score), new Filtered<>( // @checkstyle MagicNumberCheck (1 line) - n -> new LengthOf(n.score().suffixes()).intValue() >= 16, + n -> new LengthOf(n.score().suffixes()).value().intValue() >= 16, nodes ) )); diff --git a/src/main/java/io/zold/api/Taxes.java b/src/main/java/io/zold/api/Taxes.java index 9ecd730..4e8b05c 100644 --- a/src/main/java/io/zold/api/Taxes.java +++ b/src/main/java/io/zold/api/Taxes.java @@ -10,7 +10,6 @@ /** * Taxes payment algorithm. - * * @since 1.0 * @todo #61:30min Implement tax payment to remote nodes. * Payment should happen only if the wallet is in debt of more than @@ -30,8 +29,7 @@ public final class Taxes implements Proc { /** * Ctor. - * - * @param nodes Remote nodes. + * @param nodes Remote nodes */ public Taxes(final Iterable nodes) { this.bnfs = new TaxBeneficiaries(nodes); diff --git a/src/main/java/io/zold/api/Transaction.java b/src/main/java/io/zold/api/Transaction.java index 35a638a..950b254 100644 --- a/src/main/java/io/zold/api/Transaction.java +++ b/src/main/java/io/zold/api/Transaction.java @@ -10,12 +10,10 @@ /** * A payment transaction. - * * @since 0.1 * @checkstyle ParameterNumberCheck (500 lines) */ @GenerateEnvelope -@SuppressWarnings("PMD.TooManyMethods") public interface Transaction { /** @@ -24,7 +22,6 @@ public interface Transaction { * @throws IOException When something goes wrong * @checkstyle MethodNameCheck (3 lines) */ - @SuppressWarnings("PMD.ShortMethodName") int id() throws IOException; /** @@ -80,7 +77,9 @@ public interface Transaction { /** * Fake implementation of Transaction. + * @since 1.0 */ + @SuppressWarnings("PMD.DataClass") final class Fake implements Transaction { /** @@ -92,22 +91,27 @@ final class Fake implements Transaction { * Datetime of the transaction. */ private final ZonedDateTime time; + /** * Transaction amount. */ private final long amount; + /** * Transaction prefix. */ private final String prefix; + /** * Transaction beneficiary. */ private final String bnf; + /** * Transaction details. */ private final String details; + /** * Transaction signature. */ @@ -115,7 +119,6 @@ final class Fake implements Transaction { /** * Constructor. - * * @param id Transaction id * @param time Transaction time * @param amount Transaction amount @@ -126,7 +129,7 @@ final class Fake implements Transaction { * @todo #61:30min Too many parameters on Fake constructor. * Transaction.Fake have too many parameters; think and implement a * way of reducing this number. After this implementation correct - * all other Fake usages to receive the new paramater values. + * all other Fake usages to receive the new parameter values. */ public Fake(final int id, final ZonedDateTime time, final long amount, final String prefix, final String bnf, final String details, @@ -141,7 +144,6 @@ public Fake(final int id, final ZonedDateTime time, final long } @Override - @SuppressWarnings("PMD.ShortMethodName") public int id() throws IOException { return this.id; } diff --git a/src/main/java/io/zold/api/Wallet.java b/src/main/java/io/zold/api/Wallet.java index 0fc8b9a..f3cdf4d 100644 --- a/src/main/java/io/zold/api/Wallet.java +++ b/src/main/java/io/zold/api/Wallet.java @@ -4,21 +4,24 @@ */ package io.zold.api; -import java.io.FileWriter; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.Path; -import org.cactoos.collection.Filtered; +import java.nio.file.StandardOpenOption; +import org.cactoos.iterable.Filtered; import org.cactoos.iterable.IterableOf; import org.cactoos.iterable.Joined; import org.cactoos.iterable.Mapped; import org.cactoos.iterable.Skipped; import org.cactoos.list.ListOf; -import org.cactoos.scalar.CheckedScalar; +import org.cactoos.scalar.Checked; import org.cactoos.scalar.Or; -import org.cactoos.scalar.UncheckedScalar; +import org.cactoos.scalar.Unchecked; import org.cactoos.text.FormattedText; -import org.cactoos.text.SplitText; +import org.cactoos.text.Split; import org.cactoos.text.TextOf; import org.cactoos.text.UncheckedText; @@ -30,9 +33,8 @@ * Beware that tests should be refactored to take care of file cleanup * after each case that merges wallets. */ -@SuppressWarnings({"PMD.ShortMethodName", "PMD.TooManyMethods", - "PMD.UnusedFormalParameter"}) public interface Wallet { + /** * This wallet's ID: an unsigned 64-bit integer. * @return This wallet's id @@ -67,7 +69,7 @@ public interface Wallet { /** * This wallet's RSA key. - * @return This wallet's RSA key. + * @return This wallet's RSA key */ String key(); @@ -96,7 +98,7 @@ final class Fake implements Wallet { /** * Constructor. - * @param id The wallet id. + * @param id The wallet id */ public Fake(final long id) { this(id, new IterableOf<>()); @@ -104,8 +106,8 @@ public Fake(final long id) { /** * Ctor. - * @param id The wallet id. - * @param transactions Transactions. + * @param id The wallet id + * @param transactions Transactions */ public Fake(final long id, final Transaction... transactions) { this(id, new IterableOf<>(transactions)); @@ -113,9 +115,9 @@ public Fake(final long id, final Transaction... transactions) { /** * Constructor. - * @param id The wallet id. - * @param pubkey The public RSA key of the wallet owner. - * @param network The network the walet belongs to. + * @param id The wallet id + * @param pubkey The public RSA key of the wallet owner + * @param network The network the wallet belongs to * @checkstyle UnusedFormalParameter (2 lines) */ public Fake(final long id, final String pubkey, final String network) { @@ -124,8 +126,8 @@ public Fake(final long id, final String pubkey, final String network) { /** * Ctor. - * @param id The wallet id. - * @param transactions Transactions. + * @param id The wallet id + * @param transactions Transactions */ public Fake(final long id, final Iterable transactions) { this.id = id; @@ -160,6 +162,7 @@ public String key() { /** * Default File implementation. + * @since 1.0 * @checkstyle ClassDataAbstractionCouplingCheck (2 lines) */ final class File implements Wallet { @@ -179,10 +182,11 @@ final class File implements Wallet { @Override public long id() throws IOException { - return new CheckedScalar<>( + // @checkstyle ProhibitLineSeparatorInStringsCheck (10 lines) + return new Checked<>( () -> Long.parseUnsignedLong( new ListOf<>( - new SplitText( + new Split( new TextOf(this.path), "\n" ) @@ -196,7 +200,12 @@ public long id() throws IOException { @Override public void pay(final long amt, final long bnf) throws IOException { - try (final Writer out = new FileWriter(this.path.toFile(), true)) { + try ( + Writer out = new OutputStreamWriter( + Files.newOutputStream(this.path, StandardOpenOption.APPEND), + StandardCharsets.UTF_8 + ) + ) { out.write('\n'); out.write(new CpTransaction(amt, bnf).toString()); } @@ -225,25 +234,27 @@ public Wallet merge(final Wallet other) throws IOException { ); } final Iterable ledger = this.ledger(); - final Iterable candidates = new Filtered<>( - incoming -> new Filtered<>( - origin -> new UncheckedScalar<>( - new Or( - () -> incoming.equals(origin), - () -> incoming.id() == origin.id() - && incoming.bnf().equals(origin.bnf()), - () -> incoming.id() == origin.id() - && incoming.amount() < 0L, - () -> incoming.prefix().equals(origin.prefix()) - ) - ).value(), - ledger - ).isEmpty(), - other.ledger() - ); return new Wallet.Fake( this.id(), - new Joined(ledger, candidates) + new Joined( + ledger, + new Filtered<>( + incoming -> !new Filtered<>( + origin -> new Unchecked<>( + new Or( + () -> incoming.equals(origin), + () -> incoming.id() == origin.id() + && incoming.bnf().equals(origin.bnf()), + () -> incoming.id() == origin.id() + && incoming.amount() < 0L, + () -> incoming.prefix().equals(origin.prefix()) + ) + ).value(), + ledger + ).iterator().hasNext(), + other.ledger() + ) + ) ); } @@ -252,14 +263,14 @@ public Iterable ledger() { return new Mapped<>( txt -> new RtTransaction(txt.asString()), new Skipped<>( + // @checkstyle MagicNumberCheck (1 line) + 5, new ListOf<>( - new SplitText( + new Split( new TextOf(this.path), "\\n" ) - ), - // @checkstyle MagicNumberCheck (1 line) - 5 + ) ) ); } diff --git a/src/main/java/io/zold/api/Wallets.java b/src/main/java/io/zold/api/Wallets.java index b105373..d6b5d3a 100644 --- a/src/main/java/io/zold/api/Wallets.java +++ b/src/main/java/io/zold/api/Wallets.java @@ -9,26 +9,24 @@ /** * Wallets. - * * @since 0.1 */ public interface Wallets extends Iterable { + /** * Create a wallet. - * @return The new wallet. - * @throws IOException If an error occurs. + * @return The new wallet + * @throws IOException If an error occurs */ Wallet create() throws IOException; /** * Create a wallet. - * - * @param id The wallet id. - * @param pubkey The wallet public key. - * @param network The network the wallet belongs. - * @return The new wallet. - * @throws IOException If an error occurs. + * @param id The wallet id + * @param pubkey The wallet public key + * @param network The network the wallet belongs + * @return The new wallet + * @throws IOException If an error occurs */ - Wallet create(final long id, final String pubkey, final String - network) throws IOException; + Wallet create(long id, String pubkey, String network) throws IOException; } diff --git a/src/main/java/io/zold/api/WalletsIn.java b/src/main/java/io/zold/api/WalletsIn.java index 16dda0a..82fcced 100644 --- a/src/main/java/io/zold/api/WalletsIn.java +++ b/src/main/java/io/zold/api/WalletsIn.java @@ -15,10 +15,10 @@ import org.cactoos.io.Directory; import org.cactoos.iterable.Filtered; import org.cactoos.iterable.Mapped; -import org.cactoos.scalar.IoCheckedScalar; -import org.cactoos.scalar.SolidScalar; +import org.cactoos.scalar.IoChecked; +import org.cactoos.scalar.Solid; import org.cactoos.text.FormattedText; -import org.cactoos.text.JoinedText; +import org.cactoos.text.Joined; import org.cactoos.text.UncheckedText; /** @@ -31,7 +31,7 @@ public final class WalletsIn implements Wallets { /** * Path containing wallets. */ - private final IoCheckedScalar path; + private final IoChecked path; /** * Filter for matching file extensions. @@ -76,16 +76,16 @@ public WalletsIn(final Path pth, final Random random) { /** * Ctor. * @param pth Path with wallets - * @param random Randomizer * @param ext Wallets file extension + * @param random Randomizer */ public WalletsIn(final Scalar pth, final String ext, final Random random) { - this.path = new IoCheckedScalar<>( - new SolidScalar<>(pth) + this.path = new IoChecked<>( + new Solid<>(pth) ); this.filter = new IoCheckedFunc( - (file) -> file.toFile().isFile() + file -> file.toFile().isFile() && FileSystems.getDefault() .getPathMatcher(String.format("glob:**.%s", ext)) .matches(file) @@ -97,10 +97,12 @@ public WalletsIn(final Scalar pth, final String ext, @Override public Wallet create() throws IOException { final Path wpth = this.path.value().resolve( - new JoinedText( - ".", - Long.toHexString(this.random.nextLong()), - this.ext + new UncheckedText( + new Joined( + ".", + Long.toHexString(this.random.nextLong()), + this.ext + ) ).asString() ); if (wpth.toFile().exists()) { @@ -132,8 +134,8 @@ public Wallet create(final long id, final String pubkey, final String @Override public Iterator iterator() { try { - return new Mapped( - (pth) -> new Wallet.File(pth), + return new Mapped( + pth -> new Wallet.File(pth), new Filtered<>(this.filter, new Directory(this.path.value())) ).iterator(); } catch (final IOException ex) { diff --git a/src/main/java/io/zold/api/package-info.java b/src/main/java/io/zold/api/package-info.java index 41e4bd1..a387269 100644 --- a/src/main/java/io/zold/api/package-info.java +++ b/src/main/java/io/zold/api/package-info.java @@ -5,7 +5,6 @@ /** * Java API. - * * @since 0.1 */ package io.zold.api; diff --git a/src/test/java/io/zold/api/CopiesTest.java b/src/test/java/io/zold/api/CopiesTest.java index 59d1095..a880fa1 100644 --- a/src/test/java/io/zold/api/CopiesTest.java +++ b/src/test/java/io/zold/api/CopiesTest.java @@ -4,8 +4,8 @@ */ package io.zold.api; -import org.cactoos.collection.CollectionOf; import org.cactoos.iterable.IterableOf; +import org.cactoos.list.ListOf; import org.cactoos.text.TextOf; import org.hamcrest.MatcherAssert; import org.hamcrest.core.IsEqual; @@ -13,7 +13,6 @@ /** * Test case for {@link Copies}. - * * @since 1.0 * @todo #56:30min Add more test scenarios to Copies. * Scenarios: @@ -22,26 +21,33 @@ * remotes return wallets with different content * @checkstyle JavadocMethodCheck (500 lines) */ -public final class CopiesTest { +final class CopiesTest { @Test - public void createsOneCopy() { - final Iterable copies = new Copies( - 1L, - new IterableOf<>( - new Remote.Fake(new RtScore(new IterableOf<>(new TextOf("a")))), - new Remote.Fake(new RtScore(new IterableOf<>(new TextOf("b")))) - ) - ); + void createsOneCopy() { MatcherAssert.assertThat( - new CollectionOf<>(copies).size(), + new ListOf<>(CopiesTest.copies()).size(), new IsEqual<>(1) ); + } + + @Test + void groupsRemotesScoresIntoSingleCopy() { MatcherAssert.assertThat( - new CollectionOf<>( - copies.iterator().next().score().suffixes() + new ListOf<>( + CopiesTest.copies().iterator().next().score().suffixes() ).size(), new IsEqual<>(2) ); } + + private static Iterable copies() { + return new Copies( + 1L, + new IterableOf<>( + new Remote.Fake(new RtScore(new IterableOf<>(new TextOf("a")))), + new Remote.Fake(new RtScore(new IterableOf<>(new TextOf("b")))) + ) + ); + } } diff --git a/src/test/java/io/zold/api/CpTransactionTest.java b/src/test/java/io/zold/api/CpTransactionTest.java index d892e38..99d4e8b 100644 --- a/src/test/java/io/zold/api/CpTransactionTest.java +++ b/src/test/java/io/zold/api/CpTransactionTest.java @@ -13,17 +13,17 @@ /** * Test case for {@link CpTransaction}. - * * @since 1.0 * @checkstyle LineLengthCheck (500 lines) * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle MagicNumberCheck (500 lines) */ -public final class CpTransactionTest { +@SuppressWarnings("PMD.UnnecessaryLocalRule") +final class CpTransactionTest { @Test @Disabled - public void returnAmount() throws IOException { + void returnAmount() throws IOException { final long amount = 256; MatcherAssert.assertThat( "Cannot return amount", @@ -34,7 +34,7 @@ public void returnAmount() throws IOException { @Test @Disabled - public void returnSignatureForPositiveTransaction() throws IOException { + void returnSignatureForPositiveTransaction() throws IOException { final long id = 1024; MatcherAssert.assertThat( "Cannot return signature", @@ -45,7 +45,7 @@ public void returnSignatureForPositiveTransaction() throws IOException { @Test @Disabled - public void returnPrefix() throws IOException { + void returnPrefix() throws IOException { final long id = 1024; final Wallet wallet = new Wallet.Fake(id); MatcherAssert.assertThat( @@ -57,7 +57,7 @@ public void returnPrefix() throws IOException { @Test @Disabled - public void returnBeneficiary() throws IOException { + void returnBeneficiary() throws IOException { final long id = 1024; final Wallet wallet = new Wallet.Fake(id); MatcherAssert.assertThat( diff --git a/src/test/java/io/zold/api/NetworkTest.java b/src/test/java/io/zold/api/NetworkTest.java index d20fbce..73700e9 100644 --- a/src/test/java/io/zold/api/NetworkTest.java +++ b/src/test/java/io/zold/api/NetworkTest.java @@ -14,7 +14,6 @@ /** * Test case for {@link Network}. - * * @since 0.1 * @todo #5:30min Implement Remote interface. Remote Interface must be * implemented because Network depends on Remote behavior. Network.pull @@ -24,30 +23,29 @@ * @checkstyle MagicNumberCheck (500 lines) * @checkstyle ClassDataAbstractionCouplingCheck (2 lines) */ -public final class NetworkTest { +@SuppressWarnings("PMD.UnnecessaryLocalRule") +final class NetworkTest { @Test - public void pushWalletToAllRemotes() { - final Remote highremote = Mockito.mock(Remote.class); - final Remote lowremote = Mockito.mock(Remote.class); + void pushesWalletToTheFirstRemote() { + final Remote first = Mockito.mock(Remote.class); + final Remote second = Mockito.mock(Remote.class); final Wallet wallet = Mockito.mock(Wallet.class); - new RtNetwork( - new IterableOf( - highremote, lowremote - ) - ).push(wallet); - Mockito.verify( - highremote, - Mockito.times(1) - ).push(Mockito.any(Wallet.class)); - Mockito.verify( - lowremote, - Mockito.times(1) - ).push(Mockito.any(Wallet.class)); + new RtNetwork(new IterableOf(first, second)).push(wallet); + Mockito.verify(first, Mockito.times(1)).push(Mockito.any(Wallet.class)); } @Test - public void pullsWalletWithTheRightId() throws IOException { + void pushesWalletToTheSecondRemote() { + final Remote first = Mockito.mock(Remote.class); + final Remote second = Mockito.mock(Remote.class); + final Wallet wallet = Mockito.mock(Wallet.class); + new RtNetwork(new IterableOf(first, second)).push(wallet); + Mockito.verify(second, Mockito.times(1)).push(Mockito.any(Wallet.class)); + } + + @Test + void pullsWalletWithTheRightId() throws IOException { final long id = 1L; MatcherAssert.assertThat( new RtNetwork( diff --git a/src/test/java/io/zold/api/RtTransactionTest.java b/src/test/java/io/zold/api/RtTransactionTest.java index ac34fdf..a9498a7 100644 --- a/src/test/java/io/zold/api/RtTransactionTest.java +++ b/src/test/java/io/zold/api/RtTransactionTest.java @@ -16,17 +16,16 @@ /** * Test case for {@link RtTransaction}. - * * @since 0.1 * @checkstyle LineLengthCheck (500 lines) * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle MagicNumber (500 lines) */ -@SuppressWarnings({"PMD.AvoidCatchingGenericException", "PMD.TooManyMethods"}) +@SuppressWarnings("PMD.TooManyMethods") public final class RtTransactionTest { @Test - public void shouldObeyEqualsHashcodeContract() { + public void obeysEqualsHashcodeContract() { EqualsVerifier.forClass(RtTransaction.class) .withNonnullFields("transaction") .verify(); @@ -38,7 +37,7 @@ public void returnsId() throws IOException { new RtTransaction( "abcd;2017-07-19T21:25:07Z;0000000000a72366;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4..." ).id(), - new IsEqual<>(43981) + new IsEqual<>(43_981) ); } @@ -129,7 +128,7 @@ public void returnsPositiveAmount() throws IOException { new RtTransaction( "003b;2017-07-19T21:25:07Z;0000000000a72366;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4..." ).amount(), - new IsEqual<>(10953574L) + new IsEqual<>(10_953_574L) ); } @@ -139,7 +138,7 @@ public void returnsNegativeAmount() throws IOException { new RtTransaction( "003b;2017-07-19T21:25:07Z;ffffffffffa72366;xksQuJa9;98bb82c81735c4ee;For food;QCuLuVr4..." ).amount(), - new IsEqual<>(-5823642L) + new IsEqual<>(-5_823_642L) ); } @@ -206,25 +205,34 @@ public void returnsPrefix() throws IOException { ); } - @Test(expected = IOException.class) - public void prefixFormatViolated() throws IOException { - new RtTransaction( - "003b;2017-07-19T21:25:07Z;ffffffffffa72367;|invalidprefix|;98bb82c81735c4ee; For food;QCuLuVr4..." - ).prefix(); + @Test + public void prefixFormatViolated() { + Assertions.assertThrows( + IOException.class, + () -> new RtTransaction( + "003b;2017-07-19T21:25:07Z;ffffffffffa72367;|invalidprefix|;98bb82c81735c4ee; For food;QCuLuVr4..." + ).prefix() + ); } - @Test(expected = IOException.class) - public void prefixSizeViolatedLess() throws IOException { - new RtTransaction( - "003b;2017-07-19T21:25:07Z;ffffffffffa72367;FF4D;98bb82c81735c4ee; For food;QCuLuVr4..." - ).prefix(); + @Test + public void prefixSizeViolatedLess() { + Assertions.assertThrows( + IOException.class, + () -> new RtTransaction( + "003b;2017-07-19T21:25:07Z;ffffffffffa72367;FF4D;98bb82c81735c4ee; For food;QCuLuVr4..." + ).prefix() + ); } - @Test(expected = IOException.class) - public void prefixSizeViolatedMore() throws IOException { - new RtTransaction( - "003b;2017-07-19T21:25:07Z;ffffffffffa72367;FF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4D;98bb82c81735c4ee; For food;QCuLuVr4..." - ).prefix(); + @Test + public void prefixSizeViolatedMore() { + Assertions.assertThrows( + IOException.class, + () -> new RtTransaction( + "003b;2017-07-19T21:25:07Z;ffffffffffa72367;FF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4DFF4D;98bb82c81735c4ee; For food;QCuLuVr4..." + ).prefix() + ); } @Test @@ -240,11 +248,14 @@ public void prefixNotPresent() throws IOException { ); } - @Test(expected = IOException.class) - public void invalidTransactionString() throws IOException { - new RtTransaction( - "this is a invalid transaction String" - ).prefix(); + @Test + public void invalidTransactionString() { + Assertions.assertThrows( + IOException.class, + () -> new RtTransaction( + "this is a invalid transaction String" + ).prefix() + ); } @Test diff --git a/src/test/java/io/zold/api/ScoreTest.java b/src/test/java/io/zold/api/ScoreTest.java index 87710b9..ae1fbdb 100644 --- a/src/test/java/io/zold/api/ScoreTest.java +++ b/src/test/java/io/zold/api/ScoreTest.java @@ -5,8 +5,8 @@ package io.zold.api; import org.cactoos.iterable.IterableOf; +import org.cactoos.iterable.Sorted; import org.cactoos.list.ListOf; -import org.cactoos.list.Sorted; import org.cactoos.text.TextOf; import org.hamcrest.MatcherAssert; import org.hamcrest.collection.IsIterableContainingInOrder; @@ -15,11 +15,11 @@ /** * Test case for {@link Score}. - * * @since 1.0 * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ +@SuppressWarnings("PMD.UnnecessaryLocalRule") public final class ScoreTest { @Test diff --git a/src/test/java/io/zold/api/TaxBeneficiariesTest.java b/src/test/java/io/zold/api/TaxBeneficiariesTest.java index a709ddc..1f2fb59 100644 --- a/src/test/java/io/zold/api/TaxBeneficiariesTest.java +++ b/src/test/java/io/zold/api/TaxBeneficiariesTest.java @@ -13,11 +13,11 @@ /** * Test case for {@link TaxBeneficiaries}. - * * @since 1.0 * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle MagicNumberCheck (500 lines) */ +@SuppressWarnings("PMD.UnnecessaryLocalRule") public final class TaxBeneficiariesTest { @Test diff --git a/src/test/java/io/zold/api/TaxesTest.java b/src/test/java/io/zold/api/TaxesTest.java index eaae6ed..eec84da 100644 --- a/src/test/java/io/zold/api/TaxesTest.java +++ b/src/test/java/io/zold/api/TaxesTest.java @@ -8,17 +8,13 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; -import org.cactoos.text.JoinedText; +import org.cactoos.text.Joined; import org.cactoos.time.ZonedDateTimeOf; -import org.hamcrest.MatcherAssert; -import org.hamcrest.core.IsCollectionContaining; -import org.hamcrest.core.IsEqual; -import org.hamcrest.core.StringContains; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * Test case for {@link Taxes}. - * * @since 1.0 * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) @@ -26,11 +22,11 @@ * @checkstyle MethodBodyCommentsCheck (500 lines) * @checkstyle AbbreviationAsWordInNameCheck (500 lines) */ -@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") -public final class TaxesTest { +@SuppressWarnings("PMD.UnnecessaryLocalRule") +final class TaxesTest { - @Test(expected = UnsupportedOperationException.class) - public void pay() throws Exception { + @Test + void pay() throws Exception { final String prefix = "transaction"; final String beneficiary = "4096"; final ZonedDateTime first = @@ -40,7 +36,7 @@ public void pay() throws Exception { ).value(); final List ledger = new ArrayList<>(5); // @checkstyle AvoidInstantiatingObjectsInLoops (26 lines) - for (int index = 0; index < 5; index = ++index) { + for (int index = 0; index < 5; ++index) { ledger.add( new Transaction.Fake( index, @@ -48,12 +44,12 @@ public void pay() throws Exception { 1024 * index, prefix, beneficiary, - new JoinedText( + new Joined( "", prefix, Integer.toString(index) ).asString(), - new JoinedText( + new Joined( "", "signature", Integer.toString(index) @@ -67,28 +63,25 @@ public void pay() throws Exception { new Remote.Fake(counter) ); } - final Wallet wallet = new Wallet.Fake(102030, ledger); - new Taxes(remotes).exec(wallet); - MatcherAssert.assertThat( - "Didn't paid anything", - wallet.ledger(), - new IsCollectionContaining<>( - // @todo #61:30min Create and implement an Transaction - // matcher, where we can assure if some transaction have - // some values for its fields. After its implementation, fix - // this test so it can assure that the wallet has at least - // one transaction with TAXES prefix - new IsEqual<>( - new StringContains("TAXES") - ) - ) + final Wallet wallet = new Wallet.Fake(102_030, ledger); + // @todo #61:30min Once Taxes.exec is implemented, replace this + // assertThrows with the original assertion that ensures the wallet + // ledger contains a transaction with the "TAXES" prefix. + Assertions.assertThrows( + UnsupportedOperationException.class, + () -> new Taxes(remotes).exec(wallet) ); } - @Test(expected = UnsupportedOperationException.class) - public void didntPayWhenLessThanOneZLDDebt() { - throw new UnsupportedOperationException( - "selectedCorrectTaxReceiver() not yet supported" + @Test + void didntPayWhenLessThanOneZLDDebt() { + Assertions.assertThrows( + UnsupportedOperationException.class, + () -> { + throw new UnsupportedOperationException( + "selectedCorrectTaxReceiver() not yet supported" + ); + } ); } @@ -98,10 +91,15 @@ public void didntPayWhenLessThanOneZLDDebt() { // wallet with "TAXES" prefix and must obey the rule set in #40 ("A first // algorithm could pay the max to each node until there is nothing else // to pay."). - @Test(expected = UnsupportedOperationException.class) - public void payToRightNodes() { - throw new UnsupportedOperationException( - "payToRightNodes() not yet supported" + @Test + void payToRightNodes() { + Assertions.assertThrows( + UnsupportedOperationException.class, + () -> { + throw new UnsupportedOperationException( + "payToRightNodes() not yet supported" + ); + } ); } } diff --git a/src/test/java/io/zold/api/WalletTest.java b/src/test/java/io/zold/api/WalletTest.java index 21915d7..4853fe6 100644 --- a/src/test/java/io/zold/api/WalletTest.java +++ b/src/test/java/io/zold/api/WalletTest.java @@ -8,7 +8,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import org.cactoos.collection.CollectionOf; import org.cactoos.list.ListOf; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; @@ -19,18 +18,17 @@ import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.junit.rules.TemporaryFolder; -import org.llorllale.cactoos.matchers.FuncApplies; +import org.llorllale.cactoos.matchers.IsApplicable; /** * Test case for {@link Wallet}. - * * @since 0.1 * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle JavadocVariableCheck (500 lines) * @checkstyle MagicNumberCheck (500 lines) * @checkstyle ClassDataAbstractionCouplingCheck (3 lines) */ -@SuppressWarnings("PMD.TooManyMethods") +@SuppressWarnings({"PMD.TooManyMethods", "PMD.UnnecessaryLocalRule"}) public final class WalletTest { @Rule @@ -38,7 +36,7 @@ public final class WalletTest { @Test public void readsWalletId() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); MatcherAssert.assertThat(wallet.id(), Matchers.is(id)); } @@ -71,14 +69,14 @@ public void throwNumberFormatExceptionIfIdIsInvalid() throws IOException { public void pay() throws IOException { final Path path = this.folder.newFile().toPath(); path.toFile().delete(); - Files.copy(this.wallet(5124095577148911L), path); + Files.copy(this.wallet(5_124_095_577_148_911L), path); final Wallet wallet = new Wallet.File(path); MatcherAssert.assertThat( wlt -> { wlt.pay(1, 1234); return wlt.ledger(); }, - new FuncApplies<>( + new IsApplicable<>( wallet, new IsIterableWithSize( new IsEqual<>(new ListOf<>(wallet.ledger()).size() + 1) @@ -89,7 +87,7 @@ public void pay() throws IOException { @Test public void mergesWallets() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); final Wallet merged = wallet.merge( new Wallet.Fake( @@ -99,14 +97,14 @@ public void mergesWallets() throws IOException { ) ); MatcherAssert.assertThat( - new CollectionOf<>(merged.ledger()).size(), - new IsEqual<>(new CollectionOf<>(wallet.ledger()).size() + 1) + new ListOf<>(merged.ledger()).size(), + new IsEqual<>(new ListOf<>(wallet.ledger()).size() + 1) ); } @Test public void doesNotMergeWalletsWithDifferentId() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); MatcherAssert.assertThat( Assertions.assertThrows( @@ -121,7 +119,7 @@ public void doesNotMergeWalletsWithDifferentId() throws IOException { @Test public void doesNotMergeExistingTransactions() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); final Wallet merged = wallet.merge( new Wallet.Fake( @@ -131,14 +129,14 @@ public void doesNotMergeExistingTransactions() throws IOException { ) ); MatcherAssert.assertThat( - new CollectionOf<>(merged.ledger()).size(), - new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + new ListOf<>(merged.ledger()).size(), + new IsEqual<>(new ListOf<>(wallet.ledger()).size()) ); } @Test public void doesNotMergeTransactionsWithSameIdAndBnf() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); final Wallet merged = wallet.merge( new Wallet.Fake( @@ -148,15 +146,15 @@ public void doesNotMergeTransactionsWithSameIdAndBnf() throws IOException { ) ); MatcherAssert.assertThat( - new CollectionOf<>(merged.ledger()).size(), - new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + new ListOf<>(merged.ledger()).size(), + new IsEqual<>(new ListOf<>(wallet.ledger()).size()) ); } @Test public void doesNotMergeTransactionsWithSameIdAndNegativeAmount() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); final Wallet merged = wallet.merge( new Wallet.Fake( @@ -166,14 +164,14 @@ public void doesNotMergeTransactionsWithSameIdAndNegativeAmount() ) ); MatcherAssert.assertThat( - new CollectionOf<>(merged.ledger()).size(), - new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + new ListOf<>(merged.ledger()).size(), + new IsEqual<>(new ListOf<>(wallet.ledger()).size()) ); } @Test public void doesNotMergeTransactionsWithSamePrefix() throws IOException { - final long id = 5124095577148911L; + final long id = 5_124_095_577_148_911L; final Wallet wallet = new Wallet.File(this.wallet(id)); final Wallet merged = wallet.merge( new Wallet.Fake( @@ -183,23 +181,26 @@ public void doesNotMergeTransactionsWithSamePrefix() throws IOException { ) ); MatcherAssert.assertThat( - new CollectionOf<>(merged.ledger()).size(), - new IsEqual<>(new CollectionOf<>(wallet.ledger()).size()) + new ListOf<>(merged.ledger()).size(), + new IsEqual<>(new ListOf<>(wallet.ledger()).size()) ); } @Test - @SuppressWarnings("PMD.AvoidDuplicateLiterals") public void walletShouldBeAbleToReturnLedger() throws Exception { MatcherAssert.assertThat( - new Wallet.File(this.wallet(5124095577148911L)).ledger(), + new Wallet.File(this.wallet(5_124_095_577_148_911L)).ledger(), Matchers.iterableWithSize(2) ); } - @Test(expected = UnsupportedOperationException.class) + @Test public void keyIsNotYetImplemented() throws IOException { - new Wallet.File(this.folder.newFile().toPath()).key(); + final Path path = this.folder.newFile().toPath(); + Assertions.assertThrows( + UnsupportedOperationException.class, + () -> new Wallet.File(path).key() + ); } private Path wallet(final long id) { diff --git a/src/test/java/io/zold/api/WalletsInTest.java b/src/test/java/io/zold/api/WalletsInTest.java index 7164287..a93e25d 100644 --- a/src/test/java/io/zold/api/WalletsInTest.java +++ b/src/test/java/io/zold/api/WalletsInTest.java @@ -19,11 +19,11 @@ /** * Test case for {@link WalletsIn}. - * * @since 0.1 * @checkstyle JavadocMethodCheck (500 lines) * @checkstyle JavadocVariableCheck (500 lines) */ +@SuppressWarnings("PMD.UnnecessaryLocalRule") public final class WalletsInTest { @Rule @@ -60,31 +60,21 @@ public void createsWalletInFolder() throws IOException { ); } - @Test(expected = UnsupportedOperationException.class) + @Test public void createsRightWallet() throws IOException { final Path path = this.folder.newFolder().toPath(); - final String network = "zold"; - final String pubkey = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC"; - final long id = 1; - final Wallet actual = new WalletsIn(path).create( - id, pubkey, network - ); - final Wallet expected = new Wallet.Fake( - id, - pubkey, - network - ); - MatcherAssert.assertThat( - "Created wallet with different values than expected", - actual, - new IsEqual<>(expected) + Assertions.assertThrows( + UnsupportedOperationException.class, + () -> new WalletsIn(path).create( + 1L, "AAAAB3NzaC1yc2EAAAADAQABAAABAQC", "zold" + ) ); } @Test public void doesNotOverwriteExistingWallet() throws Exception { final Path path = this.folder.newFolder().toPath(); - final Random random = new FkRandom(16725L); + final Random random = new WalletsInTest.FkRandom(16_725L); new WalletsIn(path, random).create(); MatcherAssert.assertThat( Assertions.assertThrows( @@ -97,8 +87,9 @@ public void doesNotOverwriteExistingWallet() throws Exception { /** * Fake randomizer that returns the same value each time. + * @since 1.0 */ - private static class FkRandom extends Random { + private static final class FkRandom extends Random { /** * Serial version. @@ -112,7 +103,7 @@ private static class FkRandom extends Random { /** * Ctor. - * @param val Value that represents a random number. + * @param val Value that represents a random number */ FkRandom(final long val) { super(); diff --git a/src/test/java/io/zold/api/package-info.java b/src/test/java/io/zold/api/package-info.java index ada927f..1ba2a41 100644 --- a/src/test/java/io/zold/api/package-info.java +++ b/src/test/java/io/zold/api/package-info.java @@ -5,7 +5,6 @@ /** * Java API, tests. - * * @since 0.1 */ package io.zold.api;