Skip to content

Commit b6cad09

Browse files
committed
Merge branch 'coverage'
2 parents b91d7d7 + 6fc3546 commit b6cad09

File tree

58 files changed

+5719
-2779
lines changed

Some content is hidden

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

58 files changed

+5719
-2779
lines changed

address/.gitignore

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### IntelliJ IDEA ###
7+
.idea/modules.xml
8+
.idea/jarRepositories.xml
9+
.idea/compiler.xml
10+
.idea/libraries/
11+
*.iws
12+
*.iml
13+
*.ipr
14+
15+
### Eclipse ###
16+
.apt_generated
17+
.classpath
18+
.factorypath
19+
.project
20+
.settings
21+
.springBeans
22+
.sts4-cache
23+
24+
### NetBeans ###
25+
/nbproject/private/
26+
/nbbuild/
27+
/dist/
28+
/nbdist/
29+
/.nb-gradle/
30+
build/
31+
!**/src/main/**/build/
32+
!**/src/test/**/build/
33+
34+
### VS Code ###
35+
.vscode/
36+
37+
### Mac OS ###
38+
.DS_Store
39+
40+
smartcont/
41+
lib/
42+
**/*.boc
43+
**/*.exe
44+
**/*.addr

address/pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,28 @@
9595
<scope>test</scope>
9696
</dependency>
9797
</dependencies>
98+
99+
<build>
100+
<plugins>
101+
<plugin>
102+
<groupId>org.jacoco</groupId>
103+
<artifactId>jacoco-maven-plugin</artifactId>
104+
<version>0.8.11</version>
105+
<executions>
106+
<execution>
107+
<goals>
108+
<goal>prepare-agent</goal>
109+
</goals>
110+
</execution>
111+
<execution>
112+
<id>report</id>
113+
<phase>test</phase>
114+
<goals>
115+
<goal>report</goal>
116+
</goals>
117+
</execution>
118+
</executions>
119+
</plugin>
120+
</plugins>
121+
</build>
98122
</project>
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package org.ton.ton4j.address.coverage;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.junit.Assert.assertThrows;
5+
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.math.BigInteger;
9+
import java.nio.file.Files;
10+
import java.util.Arrays;
11+
import org.junit.Test;
12+
import org.junit.runner.RunWith;
13+
import org.junit.runners.JUnit4;
14+
import org.ton.ton4j.address.Address;
15+
import org.ton.ton4j.address.AddressType;
16+
import org.ton.ton4j.utils.Utils;
17+
18+
@RunWith(JUnit4.class)
19+
public class TestAddressCoverage {
20+
21+
private static byte[] bytes(int len, int value) {
22+
byte[] b = new byte[len];
23+
Arrays.fill(b, (byte) value);
24+
return b;
25+
}
26+
27+
private static String makeBase64Address(int tag, byte wc, byte[] hash) {
28+
// addr = [tag (1), wc (1), hash (32)], crc16 over addr, total 36 bytes
29+
byte[] addr = new byte[34];
30+
addr[0] = (byte) tag;
31+
addr[1] = wc;
32+
System.arraycopy(hash, 0, addr, 2, 32);
33+
byte[] crc = Utils.getCRC16ChecksumAsBytes(addr);
34+
byte[] full = new byte[36];
35+
System.arraycopy(addr, 0, full, 0, 34);
36+
System.arraycopy(crc, 0, full, 34, 2);
37+
return Utils.bytesToBase64(full);
38+
}
39+
40+
@Test
41+
public void testFactoryOfVariantsAndFlags() {
42+
byte[] hash = bytes(32, 0x11);
43+
44+
Address a1 = Address.of(Address.BOUNCEABLE_TAG, -1, hash);
45+
assertThat(a1.isBounceable()).isTrue();
46+
assertThat(a1.isWallet()).isFalse();
47+
assertThat(a1.isTestOnly()).isFalse();
48+
assertThat(a1.wc).isEqualTo((byte) -1);
49+
50+
Address a2 = Address.of(Address.NON_BOUNCEABLE_TAG, 0, hash);
51+
assertThat(a2.isBounceable()).isFalse();
52+
assertThat(a2.isWallet()).isTrue();
53+
assertThat(a2.wc).isEqualTo((byte) 0);
54+
55+
// TEST_FLAG path, wc 0xFF -> -1
56+
byte testBounceTag = (byte) (Address.BOUNCEABLE_TAG | Address.TEST_FLAG);
57+
Address a3 = Address.of(testBounceTag, 0xFF, hash);
58+
assertThat(a3.isTestOnly()).isTrue();
59+
assertThat(a3.isBounceable()).isTrue();
60+
assertThat(a3.wc).isEqualTo((byte) -1);
61+
62+
// of(byte[]) delegates to bounceable, wc default -1
63+
Address a4 = Address.of(hash);
64+
assertThat(a4.isBounceable()).isTrue();
65+
assertThat(a4.wc).isEqualTo((byte) -1);
66+
67+
// of(Address) copy
68+
Address a5 = Address.of(a3);
69+
assertThat(a5.wc).isEqualTo(a3.wc);
70+
assertThat(a5.isBounceable()).isEqualTo(a3.isBounceable());
71+
}
72+
73+
@Test
74+
public void testConstructorsAndNulls() {
75+
// String null guards
76+
assertThrows(IllegalArgumentException.class, () -> new Address((String) null));
77+
// Copy null guard
78+
assertThrows(IllegalArgumentException.class, () -> new Address((Address) null));
79+
}
80+
81+
@Test
82+
public void testRawParsingAndEdgeHexLengths() {
83+
byte[] hash = Utils.hexToSignedBytes("00" + "11".repeat(31)); // 64 hex chars starting with 00
84+
Address ok0 = new Address("0:" + Utils.bytesToHex(hash));
85+
assertThat(ok0.isWallet()).isTrue(); // raw marks wallet
86+
assertThat(ok0.isUserFriendly()).isFalse();
87+
88+
// length 63 -> prefixed with 0
89+
String hex63 = ("1" + "2".repeat(62)); // 63 chars
90+
Address ok63 = new Address("-1:" + hex63);
91+
assertThat(ok63.hashPart[0]).isEqualTo((byte) 0x01);
92+
93+
// length 1 -> left pad to 64
94+
Address ok1 = new Address("0:1");
95+
assertThat(ok1.hashPart).hasSize(32);
96+
97+
// invalid: multiple colons
98+
assertThrows(Error.class, () -> new Address("0:00:11"));
99+
// invalid wc
100+
assertThrows(Error.class, () -> new Address("1:"
101+
+ "0".repeat(64)));
102+
// invalid hex length (not 64, not 63, not 1)
103+
assertThrows(Error.class, () -> new Address("0:" + "1".repeat(2)));
104+
}
105+
106+
@Test
107+
public void testUserFriendlyParsingValidAndFlags() {
108+
byte[] hash = bytes(32, 0x22);
109+
110+
// Valid bounceable mainnet, wc 0
111+
String b64 = makeBase64Address(Address.BOUNCEABLE_TAG, (byte) 0, hash);
112+
Address a = new Address(b64);
113+
assertThat(a.isUserFriendly()).isTrue();
114+
assertThat(a.isUrlSafe()).isFalse();
115+
assertThat(a.isBounceable()).isTrue();
116+
assertThat(a.isWallet()).isFalse();
117+
// addressType is set within parseFriendlyAddress result
118+
assertThat(Address.parseFriendlyAddress(b64).addressType).isEqualTo(AddressType.STD_ADDRESS);
119+
120+
// Valid non-bounceable testnet, wc -1, url-safe input
121+
// Ensure produced base64 contains '+' or '/' so url-safe branch is triggered
122+
String b64tn;
123+
{
124+
byte[] h = Arrays.copyOf(hash, hash.length);
125+
int attempts = 0;
126+
while (true) {
127+
b64tn = makeBase64Address(Address.NON_BOUNCEABLE_TAG | Address.TEST_FLAG, (byte) -1, h);
128+
if (b64tn.indexOf('+') >= 0 || b64tn.indexOf('/') >= 0) {
129+
break;
130+
}
131+
// change hash deterministically
132+
h[attempts % h.length] ^= (byte) (1 + (attempts & 7));
133+
attempts++;
134+
if (attempts > 1024) {
135+
// fallback to avoid infinite loop; test can skip urlSafe assert in worst case
136+
break;
137+
}
138+
}
139+
}
140+
String urlSafe = b64tn.replace('+', '-').replace('/', '_');
141+
Address b = new Address(urlSafe);
142+
assertThat(b.isUserFriendly()).isTrue();
143+
// If original contained '+' or '/', then url-safe flag must be true
144+
assertThat(urlSafe.indexOf('-') >= 0 || urlSafe.indexOf('_') >= 0).isTrue();
145+
assertThat(b.isUrlSafe()).isTrue();
146+
assertThat(b.isBounceable()).isFalse();
147+
assertThat(b.isWallet()).isTrue();
148+
assertThat(b.isTestOnly()).isTrue();
149+
}
150+
151+
@Test
152+
public void testParseFriendlyAddressErrors() {
153+
byte[] hash = bytes(32, 0x33);
154+
155+
// wrong length 47 or 49
156+
assertThrows(Error.class, () -> Address.parseFriendlyAddress("A".repeat(47)));
157+
158+
// wrong decoded bytes length: construct a 48-char base64 that decodes to 35 bytes
159+
String invalidLen = Utils.bytesToBase64(bytes(35, 1)); // 48 chars, but 35 bytes
160+
assertThrows(Error.class, () -> Address.parseFriendlyAddress(invalidLen));
161+
162+
// wrong crc
163+
String good = makeBase64Address(Address.BOUNCEABLE_TAG, (byte) 0, hash);
164+
byte[] corrupted = Utils.base64ToBytes(good);
165+
corrupted[35] ^= 0x01; // flip a crc bit
166+
String wrongCrc = Utils.bytesToBase64(corrupted);
167+
assertThrows(Error.class, () -> Address.parseFriendlyAddress(wrongCrc));
168+
169+
// unknown tag (after removing TEST_FLAG)
170+
String badTag = makeBase64Address(0x00, (byte) 0, hash);
171+
assertThrows(Error.class, () -> Address.parseFriendlyAddress(badTag));
172+
173+
// invalid wc (not 0 or -1)
174+
String badWc = makeBase64Address(Address.BOUNCEABLE_TAG, (byte) 1, hash);
175+
assertThrows(Error.class, () -> Address.parseFriendlyAddress(badWc));
176+
}
177+
178+
@Test
179+
public void testToStringVariantsAndRoundTrip() {
180+
byte[] hash = bytes(32, 0x44);
181+
Address a = Address.of(Address.BOUNCEABLE_TAG, -1, hash);
182+
183+
String bounce = a.toBounceable();
184+
assertThat(bounce).hasSize(48);
185+
assertThat(Address.of(bounce)).isEqualTo(a);
186+
187+
String bounceT = a.toBounceableTestnet();
188+
assertThat(bounceT).hasSize(48);
189+
190+
String nonB = a.toNonBounceable();
191+
assertThat(nonB).hasSize(48);
192+
193+
String nonBT = a.toNonBounceableTestnet();
194+
assertThat(nonBT).hasSize(48);
195+
196+
String raw = a.toRaw();
197+
assertThat(raw).contains(":");
198+
199+
// default toString delegates to bounceable
200+
assertThat(a.toString()).isEqualTo(bounce);
201+
202+
// explicit overloads
203+
assertThat(a.toString(false)) // raw
204+
.isEqualTo(raw);
205+
assertThat(a.toString(true)) // user-friendly
206+
.hasSize(48);
207+
assertThat(a.toString(true, false)) // non-URL-safe base64 (same length)
208+
.hasSize(48);
209+
assertThat(a.toString(true, true, true)) // same as bounceable
210+
.isEqualTo(bounce);
211+
212+
// Ensure raw constructed from raw string round-trips
213+
Address fromRaw = Address.of(raw);
214+
assertThat(fromRaw.toRaw()).isEqualTo(raw);
215+
}
216+
217+
@Test
218+
public void testNumericConversionsAndShard() {
219+
byte[] hash = bytes(32, 0x00);
220+
hash[0] = (byte) 0xF0; // to control shard high nibble (0xF)
221+
Address a = Address.of(Address.BOUNCEABLE_TAG, 0, hash);
222+
223+
assertThat(a.toHex()).isEqualTo(Utils.bytesToHex(hash));
224+
assertThat(a.toBigInteger()).isEqualTo(new BigInteger(Utils.bytesToHex(hash), 16));
225+
assertThat(a.toDecimal()).isEqualTo(a.toBigInteger().toString(10));
226+
227+
long shardL = a.getShardAsLong();
228+
BigInteger shardB = a.getShardAsBigInt();
229+
assertThat(shardB.longValue()).isEqualTo(shardL);
230+
231+
// getHash returns unsigned values
232+
int[] unsigned = a.getHash();
233+
assertThat(unsigned[0]).isEqualTo(0xF0);
234+
}
235+
236+
@Test
237+
public void testEqualsAndHashCode() {
238+
byte[] h1 = bytes(32, 0x55);
239+
byte[] h2 = bytes(32, 0x56);
240+
241+
Address a1 = Address.of(Address.BOUNCEABLE_TAG, -1, h1);
242+
Address a2 = Address.of(Address.BOUNCEABLE_TAG, -1, h1);
243+
Address a3 = Address.of(Address.BOUNCEABLE_TAG, 0, h1);
244+
Address a4 = Address.of(Address.BOUNCEABLE_TAG, -1, h2);
245+
246+
assertThat(a1).isEqualTo(a2);
247+
assertThat(a1.hashCode()).isEqualTo(a2.hashCode());
248+
assertThat(a1).isNotEqualTo(a3);
249+
assertThat(a1).isNotEqualTo(a4);
250+
assertThat(a1).isNotEqualTo(null);
251+
assertThat(a1).isNotEqualTo("str");
252+
253+
// self-equality to cover (this == obj) branch
254+
assertThat(a1.equals(a1)).isTrue();
255+
}
256+
257+
@Test
258+
public void testSaveToFileAndIsValid() throws IOException {
259+
byte[] hash = bytes(32, 0x66);
260+
Address a = Address.of(Address.NON_BOUNCEABLE_TAG, -1, hash);
261+
262+
File tmp = File.createTempFile("addr", ".bin");
263+
tmp.deleteOnExit();
264+
a.saveToFile(tmp.getAbsolutePath());
265+
266+
byte[] stored = Files.readAllBytes(tmp.toPath());
267+
// Expect 32 bytes hash + 4 bytes of wc as int (big-endian)
268+
assertThat(stored.length).isEqualTo(36);
269+
assertThat(Arrays.copyOf(stored, 32)).containsExactly(hash);
270+
// last 4 bytes should represent -1 (0xFF FF FF FF)
271+
assertThat(stored[32]).isEqualTo((byte) 0xFF);
272+
assertThat(stored[33]).isEqualTo((byte) 0xFF);
273+
assertThat(stored[34]).isEqualTo((byte) 0xFF);
274+
assertThat(stored[35]).isEqualTo((byte) 0xFF);
275+
276+
// isValid true/false
277+
String good = a.toString();
278+
assertThat(Address.isValid(good)).isTrue();
279+
assertThat(Address.isValid("bad")) .isFalse();
280+
}
281+
282+
@Test
283+
public void testOfFactoryUnknownTagError() {
284+
byte[] hash = bytes(32, 0x77);
285+
// Flags that are not bounceable or non-bounceable after TEST_FLAG removal
286+
byte badFlags = 0x00; // clearly invalid tag
287+
assertThrows(Error.class, () -> Address.of(badFlags, 0, hash));
288+
289+
// Also try with TEST_FLAG set; after removal remains invalid
290+
byte badWithTest = (byte) (0x03 | Address.TEST_FLAG);
291+
assertThrows(Error.class, () -> Address.of(badWithTest, -1, hash));
292+
}
293+
}

bitstring/pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,28 @@
8989
<scope>test</scope>
9090
</dependency>
9191
</dependencies>
92+
93+
<build>
94+
<plugins>
95+
<plugin>
96+
<groupId>org.jacoco</groupId>
97+
<artifactId>jacoco-maven-plugin</artifactId>
98+
<version>0.8.11</version>
99+
<executions>
100+
<execution>
101+
<goals>
102+
<goal>prepare-agent</goal>
103+
</goals>
104+
</execution>
105+
<execution>
106+
<id>report</id>
107+
<phase>test</phase>
108+
<goals>
109+
<goal>report</goal>
110+
</goals>
111+
</execution>
112+
</executions>
113+
</plugin>
114+
</plugins>
115+
</build>
92116
</project>

0 commit comments

Comments
 (0)