Skip to content

Commit d6f7a72

Browse files
authored
Issue #44 coverage (#85)
* issue #44 - test coverage improvements - removed unused HTTPStatus class - added tests for first batch of transaction types - added missing getters on transactions - added hash/Code/equals to couple of places - added resources with serialized transaction data * more tests for transactions and associated objects * private key hex string is now always 64 characters long even when small private key is random and as such can start by 0. This was not handled properly and resulting hexa string was shorter than expected * fixed typo in log message * fixing typo in property name
1 parent e49c12a commit d6f7a72

File tree

53 files changed

+1281
-769
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1281
-769
lines changed

src/e2e/java/io/proximax/sdk/E2EContractTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ void prepare() {
7979

8080
@Test
8181
void test02CreateContract() {
82-
logger.info("Creating constract");
82+
logger.info("Creating contract");
8383
// prepare transaction
8484
ModifyContractTransaction trans = ModifyContractTransaction.create(getDeadline(),
8585
BigInteger.ZERO,
@@ -119,7 +119,7 @@ void test02CreateContract() {
119119

120120
@Test
121121
void test03ChangeExistingContract() {
122-
logger.info("Changing constract");
122+
logger.info("Changing contract");
123123
// prepare transaction - add one block to duration, move executor2 to verifiers
124124
ModifyContractTransaction trans = ModifyContractTransaction.create(getDeadline(),
125125
BigInteger.ZERO,

src/e2e/resources/config.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ xpxsdk.conf.timeout=30
2626

2727
#xpxsdk.conf.url=http://bctestnet1.xpxsirius.io:3000
2828
#xpxsdk.conf.seed.private_key=
29-
#vsdk.conf.network_type=TEST_NET
29+
#xpxsdk.conf.network_type=TEST_NET
3030
#xpxsdk.conf.timeout=60

src/main/java/io/proximax/core/crypto/PrivateKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,6 @@ public boolean equals(final Object obj) {
9595

9696
@Override
9797
public String toString() {
98-
return HexEncoder.getString(this.value.toByteArray());
98+
return HexEncoder.getString(this.value.toByteArray(), 32);
9999
}
100100
}

src/main/java/io/proximax/core/utils/HexEncoder.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ public static byte[] getBytes(final String hexString) {
5555
}
5656
}
5757

58+
/**
59+
* <p>Converts a byte array to a hex string of at minimum specified length prefixed by 0 characters as needed</p>
60+
*
61+
* <p>This implementation is specifically intended to make sure that if key is 32 bytes then output is 64
62+
* hexadecimal characters even if first bytes were 0 and input was shorter</p>
63+
*
64+
* @param bytes The input byte array
65+
* @param targetByteCount prefix 0 to make the source desired size
66+
* @return The output hex string.
67+
*/
68+
public static String getString(final byte[] bytes, int targetByteCount) {
69+
String hexString = getString(bytes);
70+
return StringUtils.repeat("00", targetByteCount - bytes.length) + hexString;
71+
}
72+
5873
/**
5974
* Converts a byte array to a hex string.
6075
*

src/main/java/io/proximax/core/utils/StringUtils.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
* Static class that contains string utility functions.
2121
*/
2222
public class StringUtils {
23+
24+
private StringUtils() {
25+
// hiding implicit constructor for utility class
26+
}
2327

2428
/**
2529
* Determines if the specified string is null or empty.
@@ -51,6 +55,27 @@ public static boolean isNullOrWhitespace(final String str) {
5155
return true;
5256
}
5357

58+
/**
59+
* <p>Repeat a String {@code repeat} times to form a new String.</p>
60+
*
61+
* <pre>
62+
* StringUtils.repeat(null, 2) = null
63+
* StringUtils.repeat("", 0) = ""
64+
* StringUtils.repeat("", 2) = ""
65+
* StringUtils.repeat("a", 3) = "aaa"
66+
* StringUtils.repeat("ab", 2) = "abab"
67+
* StringUtils.repeat("a", -2) = ""
68+
* </pre>
69+
*
70+
* @param str the String to repeat, may be null
71+
* @param repeat number of times to repeat str, negative treated as zero
72+
* @return a new String consisting of the original String repeated,
73+
* {@code null} if null String input
74+
*/
75+
public static String repeat(String str, int repeat) {
76+
return org.apache.commons.lang3.StringUtils.repeat(str, repeat);
77+
}
78+
5479
/**
5580
* Replaces a variable contained in a string with a value. A variable is defined as ${variable}.
5681
* This pattern is replaced by the given value.

src/main/java/io/proximax/sdk/infrastructure/AccountHttp.java

Lines changed: 17 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@
1717
package io.proximax.sdk.infrastructure;
1818

1919
import static io.proximax.sdk.utils.GsonUtils.stream;
20-
import static io.proximax.sdk.utils.dto.UInt64Utils.toBigInt;
2120

22-
import java.util.HashMap;
2321
import java.util.List;
24-
import java.util.Map;
2522
import java.util.Optional;
2623
import java.util.stream.Collectors;
2724

@@ -36,21 +33,15 @@
3633
import io.proximax.sdk.gen.model.AccountPropertiesInfoDTO;
3734
import io.proximax.sdk.gen.model.MultisigAccountGraphInfoDTO;
3835
import io.proximax.sdk.gen.model.MultisigAccountInfoDTO;
39-
import io.proximax.sdk.gen.model.MultisigDTO;
4036
import io.proximax.sdk.model.account.AccountInfo;
4137
import io.proximax.sdk.model.account.Address;
4238
import io.proximax.sdk.model.account.MultisigAccountGraphInfo;
4339
import io.proximax.sdk.model.account.MultisigAccountInfo;
4440
import io.proximax.sdk.model.account.PublicAccount;
4541
import io.proximax.sdk.model.account.props.AccountProperties;
46-
import io.proximax.sdk.model.blockchain.NetworkType;
47-
import io.proximax.sdk.model.mosaic.Mosaic;
48-
import io.proximax.sdk.model.mosaic.MosaicId;
4942
import io.proximax.sdk.model.transaction.AggregateTransaction;
5043
import io.proximax.sdk.model.transaction.Transaction;
51-
import io.proximax.sdk.utils.dto.AccountDTOUtils;
5244
import io.reactivex.Observable;
53-
import io.reactivex.functions.Function;
5445

5546
/**
5647
* Account http repository.
@@ -61,25 +52,15 @@ public class AccountHttp extends Http implements AccountRepository {
6152

6253
private static final String ROUTE = "/account/";
6354
private static final String PROPERTIES_SUFFIX = "/properties";
64-
55+
6556
public AccountHttp(BlockchainApi api) {
6657
super(api);
6758
}
6859

6960
@Override
7061
public Observable<AccountInfo> getAccountInfo(Address address) {
71-
return this.client.get(ROUTE + address.plain())
72-
.map(Http::mapStringOrError)
73-
.map(str -> objectMapper.readValue(str, AccountInfoDTO.class))
74-
.map(AccountInfoDTO::getAccount)
75-
.map(accountDTO -> new AccountInfo(
76-
Address.createFromRawAddress(AccountDTOUtils.getAddressEncoded(accountDTO)),
77-
toBigInt(accountDTO.getAddressHeight()), accountDTO.getPublicKey(),
78-
toBigInt(accountDTO.getPublicKeyHeight()),
79-
accountDTO.getMosaics().stream()
80-
.map(mosaicDTO -> new Mosaic(new MosaicId(toBigInt(mosaicDTO.getId())),
81-
toBigInt(mosaicDTO.getAmount())))
82-
.collect(Collectors.toList())));
62+
return this.client.get(ROUTE + address.plain()).map(Http::mapStringOrError)
63+
.map(str -> objectMapper.readValue(str, AccountInfoDTO.class)).map(AccountInfo::fromDto);
8364
}
8465

8566
@Override
@@ -92,58 +73,32 @@ public Observable<List<AccountInfo>> getAccountsInfo(List<Address> addresses) {
9273
requestBody.add("addresses", arr);
9374
return this.client.post(ROUTE, requestBody).map(Http::mapStringOrError)
9475
.map(str -> objectMapper.<List<AccountInfoDTO>>readValue(str, new TypeReference<List<AccountInfoDTO>>() {
95-
})).flatMapIterable(item -> item).map(AccountInfoDTO::getAccount).map(
96-
accountDTO -> new AccountInfo(
97-
Address.createFromRawAddress(AccountDTOUtils.getAddressEncoded(accountDTO)),
98-
toBigInt(accountDTO.getAddressHeight()), accountDTO.getPublicKey(),
99-
toBigInt(accountDTO.getPublicKeyHeight()),
100-
accountDTO.getMosaics().stream()
101-
.map(mosaicDTO -> new Mosaic(new MosaicId(toBigInt(mosaicDTO.getId())),
102-
toBigInt(mosaicDTO.getAmount())))
103-
.collect(Collectors.toList())))
104-
.toList().toObservable();
76+
})).flatMapIterable(item -> item).map(AccountInfo::fromDto).toList().toObservable();
10577
}
10678

10779
@Override
10880
public Observable<MultisigAccountInfo> getMultisigAccountInfo(Address address) {
10981
return this.client.get(ROUTE + address.plain() + "/multisig").map(Http::mapStringOrError)
11082
.map(str -> objectMapper.readValue(str, MultisigAccountInfoDTO.class))
111-
.map(MultisigAccountInfoDTO::getMultisig).map(transfromMultisigAccountInfoDTO(api.getNetworkType()));
83+
.map(dto -> MultisigAccountInfo.fromDto(dto, api.getNetworkType()));
11284
}
11385

11486
@Override
11587
public Observable<MultisigAccountGraphInfo> getMultisigAccountGraphInfo(Address address) {
116-
final NetworkType networkType = api.getNetworkType();
11788
return this.client.get(ROUTE + address.plain() + "/multisig/graph").map(Http::mapStringOrError)
11889
.map(str -> objectMapper.<List<MultisigAccountGraphInfoDTO>>readValue(str,
11990
new TypeReference<List<MultisigAccountGraphInfoDTO>>() {
12091
}))
121-
.map(multisigAccountGraphInfoDTOList -> {
122-
Map<Integer, List<MultisigAccountInfo>> multisigAccountInfoMap = new HashMap<>();
123-
multisigAccountGraphInfoDTOList.forEach(item -> multisigAccountInfoMap.put(item.getLevel(),
124-
item.getMultisigEntries().stream().map(MultisigAccountInfoDTO::getMultisig)
125-
.map(item2 -> new MultisigAccountInfo(new PublicAccount(item2.getAccount(), networkType),
126-
item2.getMinApproval(), item2.getMinRemoval(),
127-
item2.getCosignatories().stream()
128-
.map(cosigner -> new PublicAccount(cosigner, networkType))
129-
.collect(Collectors.toList()),
130-
item2.getMultisigAccounts().stream()
131-
.map(multisigAccount -> new PublicAccount(multisigAccount, networkType))
132-
.collect(Collectors.toList())))
133-
.collect(Collectors.toList())));
134-
return new MultisigAccountGraphInfo(multisigAccountInfoMap);
135-
});
92+
.map(dto -> MultisigAccountGraphInfo.fromDto(dto, api.getNetworkType()));
13693
}
13794

13895
@Override
13996
public Observable<AccountProperties> getAccountProperties(Address address) {
140-
return this.client.get(ROUTE + address.plain() + PROPERTIES_SUFFIX)
141-
.map(Http::mapStringOrError)
97+
return this.client.get(ROUTE + address.plain() + PROPERTIES_SUFFIX).map(Http::mapStringOrError)
14298
.map(str -> objectMapper.readValue(str, AccountPropertiesInfoDTO.class))
143-
.map(AccountPropertiesInfoDTO::getAccountProperties)
144-
.map(AccountProperties::fromDto);
99+
.map(AccountPropertiesInfoDTO::getAccountProperties).map(AccountProperties::fromDto);
145100
}
146-
101+
147102
@Override
148103
public Observable<List<AccountProperties>> getAccountProperties(List<Address> addresses) {
149104
// prepare JSON array with addresses
@@ -153,16 +108,15 @@ public Observable<List<AccountProperties>> getAccountProperties(List<Address> ad
153108
JsonObject requestBody = new JsonObject();
154109
requestBody.add("addresses", arr);
155110
// post to the API
156-
return this.client.post(ROUTE + PROPERTIES_SUFFIX, requestBody)
157-
.map(Http::mapStringOrError)
158-
.map(str -> objectMapper.<List<AccountPropertiesInfoDTO>>readValue(str, new TypeReference<List<AccountPropertiesInfoDTO>>() {}))
159-
.flatMapIterable(item -> item)
160-
.map(AccountPropertiesInfoDTO::getAccountProperties)
161-
.map(AccountProperties::fromDto)
162-
.toList().toObservable();
163-
111+
return this.client.post(ROUTE + PROPERTIES_SUFFIX, requestBody).map(Http::mapStringOrError)
112+
.map(str -> objectMapper.<List<AccountPropertiesInfoDTO>>readValue(str,
113+
new TypeReference<List<AccountPropertiesInfoDTO>>() {
114+
}))
115+
.flatMapIterable(item -> item).map(AccountPropertiesInfoDTO::getAccountProperties)
116+
.map(AccountProperties::fromDto).toList().toObservable();
117+
164118
}
165-
119+
166120
@Override
167121
public Observable<List<Transaction>> transactions(PublicAccount publicAccount) {
168122
return this.transactions(publicAccount, Optional.empty());
@@ -249,20 +203,4 @@ private Observable<List<Transaction>> findTransactions(PublicAccount publicAccou
249203
.collect(Collectors.toList()))
250204
.flatMapIterable(item -> item).map(new TransactionMapping()).toList().toObservable();
251205
}
252-
253-
/**
254-
* return function that transforms MultisigDTO to MultisigAccountInfo
255-
*
256-
* @param networkType
257-
* @return
258-
*/
259-
private Function<MultisigDTO, MultisigAccountInfo> transfromMultisigAccountInfoDTO(NetworkType networkType) {
260-
return multisig -> new MultisigAccountInfo(new PublicAccount(multisig.getAccount(), networkType),
261-
multisig.getMinApproval(), multisig.getMinRemoval(),
262-
multisig.getCosignatories().stream().map(cosigner -> new PublicAccount(cosigner, networkType))
263-
.collect(Collectors.toList()),
264-
multisig.getMultisigAccounts().stream()
265-
.map(multisigAccount -> new PublicAccount(multisigAccount, networkType))
266-
.collect(Collectors.toList()));
267-
}
268206
}

src/main/java/io/proximax/sdk/model/account/AccountInfo.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,17 @@
1616

1717
package io.proximax.sdk.model.account;
1818

19+
import static io.proximax.sdk.utils.dto.UInt64Utils.toBigInt;
20+
1921
import java.math.BigInteger;
2022
import java.util.List;
23+
import java.util.stream.Collectors;
2124

25+
import io.proximax.sdk.gen.model.AccountDTO;
26+
import io.proximax.sdk.gen.model.AccountInfoDTO;
2227
import io.proximax.sdk.model.mosaic.Mosaic;
28+
import io.proximax.sdk.model.mosaic.MosaicId;
29+
import io.proximax.sdk.utils.dto.AccountDTOUtils;
2330

2431
/**
2532
* The account info structure describes basic information for an account.
@@ -94,4 +101,16 @@ public List<Mosaic> getMosaics() {
94101
public PublicAccount getPublicAccount() {
95102
return PublicAccount.createFromPublicKey(this.publicKey, this.address.getNetworkType());
96103
}
104+
105+
public static AccountInfo fromDto(AccountInfoDTO dto) {
106+
AccountDTO accountDTO = dto.getAccount();
107+
return new AccountInfo(
108+
Address.createFromRawAddress(AccountDTOUtils.getAddressEncoded(accountDTO)),
109+
toBigInt(accountDTO.getAddressHeight()), accountDTO.getPublicKey(),
110+
toBigInt(accountDTO.getPublicKeyHeight()),
111+
accountDTO.getMosaics().stream()
112+
.map(mosaicDTO -> new Mosaic(new MosaicId(toBigInt(mosaicDTO.getId())),
113+
toBigInt(mosaicDTO.getAmount())))
114+
.collect(Collectors.toList()));
115+
}
97116
}

src/main/java/io/proximax/sdk/model/account/MultisigAccountGraphInfo.java

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,51 @@
1616

1717
package io.proximax.sdk.model.account;
1818

19+
import java.util.HashMap;
1920
import java.util.List;
2021
import java.util.Map;
2122
import java.util.Set;
23+
import java.util.stream.Collectors;
24+
25+
import io.proximax.sdk.gen.model.MultisigAccountGraphInfoDTO;
26+
import io.proximax.sdk.model.blockchain.NetworkType;
2227

2328
/**
24-
* The multisig account graph info structure describes the information of all the mutlisig levels an account is involved in.
29+
* The multisig account graph info structure describes the information of all the mutlisig levels an account is involved
30+
* in.
2531
*
2632
* @since 1.0
2733
*/
2834
public class MultisigAccountGraphInfo {
29-
private final Map<Integer, List<MultisigAccountInfo>> multisigAccounts;
30-
31-
public MultisigAccountGraphInfo(Map<Integer, List<MultisigAccountInfo>> multisigAccounts) {
32-
this.multisigAccounts = multisigAccounts;
33-
}
34-
35-
/**
36-
* Returns multisig accounts levels number.
37-
*
38-
* @return levels in the graph
39-
*/
40-
public Set<Integer> getLevelsNumber() {
41-
return this.multisigAccounts.keySet();
42-
}
43-
44-
/**
45-
* Returns multisig accounts.
46-
*
47-
* @return list of multisig accounts for each level
48-
*/
49-
public Map<Integer, List<MultisigAccountInfo>> getMultisigAccounts() {
50-
return multisigAccounts;
51-
}
35+
private final Map<Integer, List<MultisigAccountInfo>> multisigAccounts;
36+
37+
public MultisigAccountGraphInfo(Map<Integer, List<MultisigAccountInfo>> multisigAccounts) {
38+
this.multisigAccounts = multisigAccounts;
39+
}
40+
41+
/**
42+
* Returns multisig accounts levels number.
43+
*
44+
* @return levels in the graph
45+
*/
46+
public Set<Integer> getLevelsNumber() {
47+
return this.multisigAccounts.keySet();
48+
}
49+
50+
/**
51+
* Returns multisig accounts.
52+
*
53+
* @return list of multisig accounts for each level
54+
*/
55+
public Map<Integer, List<MultisigAccountInfo>> getMultisigAccounts() {
56+
return multisigAccounts;
57+
}
58+
59+
public static MultisigAccountGraphInfo fromDto(List<MultisigAccountGraphInfoDTO> dto, NetworkType networkType) {
60+
Map<Integer, List<MultisigAccountInfo>> multisigAccountInfoMap = new HashMap<>();
61+
dto.forEach(item -> multisigAccountInfoMap.put(item.getLevel(),
62+
item.getMultisigEntries().stream().map(item2 -> MultisigAccountInfo.fromDto(item2, networkType))
63+
.collect(Collectors.toList())));
64+
return new MultisigAccountGraphInfo(multisigAccountInfoMap);
65+
}
5266
}

0 commit comments

Comments
 (0)