diff --git a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4.java b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4.java index 0827d33..b0a7d78 100644 --- a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4.java +++ b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4.java @@ -24,6 +24,7 @@ package com.github.jgonian.ipmath; import java.math.BigInteger; +import java.net.Inet4Address; import java.util.regex.Pattern; public final class Ipv4 extends AbstractIp { @@ -74,6 +75,20 @@ public static Ipv4 of(String value) { return parse(value); } + public static Ipv4 of(byte[] octets) { + Validate.isTrue(octets.length == TOTAL_OCTETS, "exactly " + TOTAL_OCTETS + " octets are required"); + long result = 0; + for (int i = 0; i < octets.length; i++) { + result = addOctet(result, Byte.toUnsignedInt(octets[i])); + } + return new Ipv4(result); + } + + public static Ipv4 of(Inet4Address value) { + Validate.notNull(value, "value is required"); + return of(value.getAddress()); + } + public static Ipv4 parse(String ipv4Address) { try { String ipv4String = Validate.notNull(ipv4Address).trim(); diff --git a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4Range.java b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4Range.java index 23d7527..6484564 100644 --- a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4Range.java +++ b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv4Range.java @@ -24,6 +24,7 @@ package com.github.jgonian.ipmath; import java.math.BigInteger; +import java.net.Inet4Address; public final class Ipv4Range extends AbstractIpRange { @@ -55,6 +56,14 @@ public static Ipv4RangeBuilder from(Long from) { return new Ipv4RangeBuilder(Ipv4.of(from)); } + public static Ipv4RangeBuilder from(byte[] from) { + return new Ipv4RangeBuilder(Ipv4.of(from)); + } + + public static Ipv4RangeBuilder from(Inet4Address from) { + return new Ipv4RangeBuilder(Ipv4.of(from)); + } + public static Ipv4RangeBuilder from(String from) { return new Ipv4RangeBuilder(Ipv4.parse(from)); } @@ -125,6 +134,14 @@ public Ipv4Range to(Long end) { return to(Ipv4.of(end)); } + public Ipv4Range to(byte[] end) { + return to(Ipv4.of(end)); + } + + public Ipv4Range to(Inet4Address end) { + return to(Ipv4.of(end)); + } + public Ipv4Range to(String end) { return to(Ipv4.parse(end)); } diff --git a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6.java b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6.java index 57b1f1a..a7c969c 100644 --- a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6.java +++ b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6.java @@ -24,6 +24,7 @@ package com.github.jgonian.ipmath; import java.math.BigInteger; +import java.net.Inet6Address; import java.util.regex.Pattern; import static java.math.BigInteger.ONE; @@ -47,8 +48,10 @@ public final class Ipv6 extends AbstractIp { private static final String COLON = ":"; private static final String ZERO = "0"; private static final int BITS_PER_PART = 16; - private static final int TOTAL_OCTETS = 8; + private static final int TOTAL_PARTS = 8; private static final int COLON_COUNT_IPV6 = 7; + private static final int BITS_PER_OCTET = 8; + private static final int TOTAL_OCTETS = 16; private static final BigInteger MINUS_ONE = BigInteger.valueOf(-1); private final BigInteger value; @@ -71,6 +74,20 @@ public static Ipv6 of(String value) { return parse(value); } + public static Ipv6 of(byte[] octets) { + Validate.isTrue(octets.length == TOTAL_OCTETS, "exactly " + TOTAL_OCTETS + " octets are required"); + BigInteger result = BigInteger.ZERO; + for (int i = 0; i < octets.length; i++) { + result = result.shiftLeft(BITS_PER_OCTET).add(BigInteger.valueOf(Byte.toUnsignedInt(octets[i]))); + } + return new Ipv6(result); + } + + public static Ipv6 of(Inet6Address value) { + Validate.notNull(value, "value is required"); + return of(value.getAddress()); + } + @Override public int compareTo(Ipv6 other) { return value.compareTo(other.value); @@ -174,8 +191,8 @@ public static Ipv6 parse(final String ipv6Address) { ipv6String = expandMissingColons(ipv6String, indexOfDoubleColons); } - final String[] split = ipv6String.split(COLON, TOTAL_OCTETS); - Validate.isTrue(split.length == TOTAL_OCTETS); + final String[] split = ipv6String.split(COLON, TOTAL_PARTS); + Validate.isTrue(split.length == TOTAL_PARTS); BigInteger ipv6value = BigInteger.ZERO; for (String part : split) { Validate.isTrue(part.length() <= MAX_PART_LENGTH); diff --git a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6Range.java b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6Range.java index e657e8c..2662ad5 100644 --- a/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6Range.java +++ b/commons-ip-math/src/main/java/com/github/jgonian/ipmath/Ipv6Range.java @@ -25,6 +25,7 @@ import static java.math.BigInteger.*; import java.math.BigInteger; +import java.net.Inet6Address; public final class Ipv6Range extends AbstractIpRange { @@ -52,6 +53,14 @@ public static Ipv6RangeBuilder from(BigInteger from) { return new Ipv6RangeBuilder(Ipv6.of(from)); } + public static Ipv6RangeBuilder from(byte[] from) { + return new Ipv6RangeBuilder(Ipv6.of(from)); + } + + public static Ipv6RangeBuilder from(Inet6Address from) { + return new Ipv6RangeBuilder(Ipv6.of(from)); + } + public static Ipv6RangeBuilder from(String from) { return new Ipv6RangeBuilder(Ipv6.parse(from)); } @@ -119,6 +128,14 @@ public Ipv6Range to(BigInteger end) { return to(Ipv6.of(end)); } + public Ipv6Range to(byte[] end) { + return to(Ipv6.of(end)); + } + + public Ipv6Range to(Inet6Address end) { + return to(Ipv6.of(end)); + } + public Ipv6Range to(String end) { return to(Ipv6.parse(end)); } diff --git a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4RangeTest.java b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4RangeTest.java index 9b84e85..633fc99 100644 --- a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4RangeTest.java +++ b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4RangeTest.java @@ -25,6 +25,9 @@ import org.junit.Test; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -226,6 +229,21 @@ public void testBuilderWithLongs() { assertEquals(ip3, range.end()); } + @Test + public void testBuilderWithByteArrays() { + Ipv4Range range = Ipv4Range.from(new byte[] {0, 0, 0, 1}).to(new byte[] {0, 0, 0, 3}); + assertEquals(ip1, range.start()); + assertEquals(ip3, range.end()); + } + + @Test + public void testBuilderWithInetAddresses() throws UnknownHostException + { + Ipv4Range range = Ipv4Range.from((Inet4Address) InetAddress.getByAddress(new byte[]{0, 0, 0, 1})).to((Inet4Address) InetAddress.getByAddress(new byte[]{0, 0, 0, 3})); + assertEquals(ip1, range.start()); + assertEquals(ip3, range.end()); + } + @Test public void testBuilderWithStrings() { Ipv4Range range = Ipv4Range.from("0.0.0.1").to("0.0.0.3"); diff --git a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4Test.java b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4Test.java index 7863e62..51b6ed5 100644 --- a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4Test.java +++ b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv4Test.java @@ -27,6 +27,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; @@ -45,11 +48,21 @@ public void testEqualsContract() { } @Test - public void testBuilderMethods() { + public void testBuilderMethods() throws UnknownHostException { Ipv4 sample = new Ipv4(1l); assertEquals(sample, Ipv4.of(BigInteger.ONE)); assertEquals(sample, Ipv4.of(1l)); assertEquals(sample, Ipv4.of("0.0.0.1")); + assertEquals(sample, Ipv4.of(new byte[] {0, 0, 0, 1})); + assertEquals(sample, Ipv4.of((Inet4Address) InetAddress.getByAddress(new byte[] {0, 0, 0, 1}))); + assertEquals(InetAddress.getByAddress(new byte[] {0, 0, 0, 1}), InetAddress.getByName("0.0.0.1")); + } + + @Test + public void testByteArrayBuilder() throws UnknownHostException { + Ipv4 sample = new Ipv4(3325256709l); + // Explicitly test for cases that involve Java's unsigned byte usage. + assertEquals(sample, Ipv4.of(InetAddress.getByName("198.51.100.5").getAddress())); } @Test @@ -59,6 +72,27 @@ public void testBuilderWithNull() { Ipv4.of((BigInteger) null); } + @Test + public void testBuilderWithNullInetAddress() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("value is required"); + Ipv4.of((Inet4Address) null); + } + + @Test + public void testBuilderNotEnoughBytes() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("exactly 4 octets are required"); + Ipv4.of(new byte[3]); + } + + @Test + public void testBuilderToManyBytes() { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("exactly 4 octets are required"); + Ipv4.of(new byte[5]); + } + @Test public void testUpperBound() { thrown.expect(IllegalArgumentException.class); diff --git a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6RangeTest.java b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6RangeTest.java index cb7f7ae..d79b836 100644 --- a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6RangeTest.java +++ b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6RangeTest.java @@ -26,6 +26,9 @@ import org.junit.Test; import java.math.BigInteger; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.*; import static com.github.jgonian.ipmath.Ipv4.LAST_IPV4_ADDRESS; @@ -213,6 +216,20 @@ public void testBuilderWithBigIntegers() { assertEquals(ip3, range.end()); } + @Test + public void testBuilderWithByteArrays() { + Ipv6Range range = Ipv6Range.from(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}).to(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}); + assertEquals(ip1, range.start()); + assertEquals(ip3, range.end()); + } + + @Test + public void testBuilderWithInetAddresses() throws UnknownHostException { + Ipv6Range range = Ipv6Range.from((Inet6Address) InetAddress.getByAddress(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})).to((Inet6Address) InetAddress.getByAddress(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3})); + assertEquals(ip1, range.start()); + assertEquals(ip3, range.end()); + } + @Test public void testBuilderWithStrings() { Ipv6Range range = Ipv6Range.from("::1").to("::3"); diff --git a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6Test.java b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6Test.java index dcd2c7f..3a10eb7 100644 --- a/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6Test.java +++ b/commons-ip-math/src/test/java/com/github/jgonian/ipmath/Ipv6Test.java @@ -28,6 +28,9 @@ import org.junit.Test; import java.math.BigInteger; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import static junit.framework.Assert.assertEquals; @@ -50,6 +53,17 @@ public void testFactoryMethodWithString() { assertEquals(new Ipv6(BigInteger.ZERO), Ipv6.of("::")); } + @Test + public void testFactoryMethodWithByteArray() { + assertEquals(new Ipv6(BigInteger.ZERO), Ipv6.of(new byte[16])); // Java initializes byte array to all zero. + } + + @Test + public void testByteArrayBuilder() throws UnknownHostException { + // Explicitly test for cases that involve Java's unsigned byte usage. + assertEquals(Ipv6.LAST_IPV6_ADDRESS, Ipv6.of(InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").getAddress())); + } + // Representing IPv6 Addresses @Test @@ -182,11 +196,26 @@ public void shouldNotParseNull() { Ipv6.parse(null); } + @Test(expected = IllegalArgumentException.class) + public void shouldNotParseNullInetAddress() { + Ipv6.of((Inet6Address) null); + } + @Test(expected = IllegalArgumentException.class) public void shouldFailOnEmptyString() { Ipv6.parse(""); } + @Test(expected = IllegalArgumentException.class) + public void testBuilderNotEnoughBytes() { + Ipv4.of(new byte[15]); + } + + @Test(expected = IllegalArgumentException.class) + public void testBuilderToManyBytes() { + Ipv4.of(new byte[17]); + } + @Test public void shouldParseFullAddressesCaseInsensitively() { assertEquals(Ipv6.parse("abcd:ef01:2345:6789:abcd:ef01:2345:6789"), Ipv6.parse("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789"));