Cleaned up Subnet.java and added/extended unit tests. 60/28360/2
authorRyan Vail <r.vail@cablelabs.com>
Wed, 14 Oct 2015 01:32:34 +0000 (19:32 -0600)
committerRyan Vail <r.vail@cablelabs.com>
Wed, 14 Oct 2015 01:55:53 +0000 (19:55 -0600)
Subnet.java
  - Reordered modifiers to standard java lang spec order
  - Improved equals() with checks for null and this
  - Improved hashCode() by using all member vars used in equals().
  - Added braces to all if/else statements
  - Added constructor argument checks to ensure valid objects are created.
  - Renamed member variables to clearly identify what they are
  - Added javadoc
  - Added @Nullable and @Nonnull as appropriate

SubnetTest.java
  Fleshed out tests to cover all methods and cover more corner cases

PS2: minor javadoc error fix

Change-Id: I2b8097b096ee707ade064f6e583f72aba244e509
Signed-off-by: Ryan Vail <r.vail@cablelabs.com>
packetcable-policy-server/src/main/java/org/opendaylight/controller/packetcable/provider/Subnet.java
packetcable-policy-server/src/test/java/org/opendaylight/controller/packetcable/provider/SubnetTest.java

index c0db407d7ff8be37454bf16b597465628c5fba81..b8caf655b1e74d73772be6158c00e522361e3b91 100644 (file)
 package org.opendaylight.controller.packetcable.provider;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.math.BigInteger;
+import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * @author c3oe.de, based on snippets from Scott Plante, John Kugelmann
  */
 public class Subnet
 {
-    final private int bytesSubnetCount;
-    final private BigInteger bigMask;
-    final private BigInteger bigSubnetMasked;
-    final private int prefixLen;
+    /** Minimum length of a v4 or v6 subnet mask */
+    private final static int MIN_MASK_BITS = 0;
+
+    /** Maximum length of a v4 subnet mask */
+    private final static int MAX_MASK_BITS_V4 = 32;
+
+    /** Maximum length of a v6 subnet mask */
+    private final static int MAX_MASK_BITS_V6 = 128;
+
+    /** The length of the subnet prefix */
+    private final int prefixLen;
 
-    /** For use via format "192.168.0.0/24" or "2001:db8:85a3:880:0:0:0:0/57" */
-    public Subnet( final InetAddress subnetAddress, final int bits )
+    /** The subnet mask */
+    private final BigInteger mask;
+
+    /** The actual routing prefix leading to this subnet */
+    private final BigInteger routingPrefix;
+
+    /** The number of bytes in an address. Will be 4 or 16 corresponding to ipv4 and ipv6 respectively */
+    private final int addressByteCount;
+
+    /**
+     * Generates a Subnet from CIDR style notation. <br>
+     * Eg. "192.168.0.0/24" or "2001:db8:85a3:880:0:0:0:0/57"
+     * @param subnetAddress An address in this subnet or the routing prefix leading to this subnet.
+     * @param prefixLength The number of prefix bits that are set, must be between [0..32] for ipv4 and [0..128] for ipv6
+     * @throws NullPointerException if the subnetAddress is null
+     * @throws IllegalArgumentException if the bits argument is not in the allowable range.
+     * @see <a href="http://wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation">http://wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation</a>
+     */
+    public Subnet(@Nonnull final InetAddress subnetAddress, final int prefixLength )
+    {
+        checkNotNull(subnetAddress, "subnetAddress can not be null");
+        final int maxMaskBits = (subnetAddress instanceof Inet4Address ? MAX_MASK_BITS_V4 : MAX_MASK_BITS_V6);
+        checkArgument(prefixLength >= MIN_MASK_BITS && prefixLength <= maxMaskBits, "The prefixLength must be in range [%s..%s] but was %s", MIN_MASK_BITS, maxMaskBits, prefixLength);
+
+        this.prefixLen = prefixLength;
+        this.addressByteCount = subnetAddress.getAddress().length; // 4 or 16
+        this.mask = BigInteger.valueOf( -1 ).shiftLeft(this.addressByteCount * 8 - prefixLength);
+
+        // ensure subnetAddress is properly masked and is not an address in the subnet
+        this.routingPrefix = new BigInteger( subnetAddress.getAddress() ).and( this.mask);
+    }
+
+    /**
+     * Generates a subnet from an address and subnet mask. The old ipv4 way.
+     * Eg: "192.168.0.0/255.255.255.0" or single address with no subnet
+     * @param subnetAddress An address in the subnet or the routing prefix leading to this subnet.
+     * @param subnetMask The subnet mask or null. If null the subnet will be a host identifier.
+     * */
+    public Subnet(@Nonnull final InetAddress subnetAddress, @Nullable final InetAddress subnetMask )
     {
-        this.prefixLen = bits;
-       this.bytesSubnetCount = subnetAddress.getAddress().length; // 4 or 16
-        this.bigMask = BigInteger.valueOf( -1 ).shiftLeft( this.bytesSubnetCount*8 - bits ); // mask = -1 << 32 - bits
-        this.bigSubnetMasked = new BigInteger( subnetAddress.getAddress() ).and( this.bigMask );
+        this(subnetAddress, maskToPrefixLen(subnetAddress, subnetMask));
     }
 
-    /** For use via format "192.168.0.0/255.255.255.0" or single address */
-    public Subnet( final InetAddress subnetAddress, final InetAddress mask )
+    /**
+     * Helper method that computes the prefix length an address and subnet mask pair.
+     * @param subnetAddress An address in the subnet
+     * @param subnetMask The mask or null. Expected to be CIDR compliant (mask is a continuous prefix).
+     *                   If null this will return the length of a host identifier.
+     * @return The prefix length
+     * @throws NullPointerException if subnetAddress is null
+     * @throws IllegalArgumentException if subnetMask is not null and
+     *              either (subnetAddress and subnetMask are not the same type)
+     *              or (if subnetMask is not CIDR compliant).
+     */
+    private static int maskToPrefixLen(@Nonnull final InetAddress subnetAddress, @Nullable final InetAddress subnetMask)
     {
-       this.bytesSubnetCount = subnetAddress.getAddress().length;
-        this.bigMask = null == mask ? BigInteger.valueOf( -1 ) : new BigInteger( mask.getAddress() ); // no mask given case is handled here.
-        this.bigSubnetMasked = new BigInteger( subnetAddress.getAddress() ).and( this.bigMask );
-        int lowestSetBit = bigMask.getLowestSetBit();
-        this.prefixLen = lowestSetBit == -1 ? 0 : 32 - lowestSetBit;
+        checkNotNull(subnetAddress, "subnetAddress can not be null");
+        if (subnetMask == null) {
+            return (subnetAddress instanceof Inet4Address ? MAX_MASK_BITS_V4 : MAX_MASK_BITS_V6);
+        }
+        else {
+            // address and mask must both be ipv4 or ipv6
+            checkArgument(subnetAddress.getClass().equals(subnetMask.getClass()));
+
+            // validate subnet mask. All leading bits should be set
+            final BigInteger m = new BigInteger(subnetMask.getAddress());
+            final BigInteger allOnes = BigInteger.valueOf(-1);
+            final int rightMostBit = m.getLowestSetBit();
+            final BigInteger validSubnet = allOnes.shiftLeft(rightMostBit);
+
+            checkArgument(validSubnet.equals(m), "Subnet should have contiguous prefix bits, mask: %s(%s)", subnetMask);
+
+            return (subnetAddress instanceof Inet4Address
+                    ? MAX_MASK_BITS_V4 - rightMostBit
+                    : MAX_MASK_BITS_V6 - rightMostBit);
+        }
     }
 
     /**
      * Subnet factory method.
-     * @param subnetMask format: "192.168.0.0/24" or "192.168.0.0/255.255.255.0"
+     * @param addressAndSubnetStr format: "192.168.0.0/24" or "192.168.0.0/255.255.255.0"
      *      or single address or "2001:db8:85a3:880:0:0:0:0/57"
      * @return a new instance
      * @throws UnknownHostException thrown if unsupported subnet mask.
      */
-    public static Subnet createInstance( final String subnetMask )
+    public static Subnet createInstance(@Nonnull final String addressAndSubnetStr )
             throws UnknownHostException
     {
-        final String[] stringArr = subnetMask.split("/");
-        if ( 2 > stringArr.length )
-            return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), null);
-        else if ( stringArr[ 1 ].contains(".") || stringArr[ 1 ].contains(":") )
-            return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), InetAddress.getByName( stringArr[ 1 ] ) );
-        else
-            return new Subnet( InetAddress.getByName( stringArr[ 0 ] ), Integer.parseInt( stringArr[ 1 ] ) );
+        final String[] stringArr = addressAndSubnetStr.split("/");
+        if ( 2 > stringArr.length ) {
+            return new Subnet(InetAddress.getByName(stringArr[0]), null);
+        }
+        else if ( stringArr[ 1 ].contains(".") || stringArr[ 1 ].contains(":") ) {
+            return new Subnet(InetAddress.getByName(stringArr[0]), InetAddress.getByName(stringArr[1]));
+        }
+        else {
+            return new Subnet(InetAddress.getByName(stringArr[0]), Integer.parseInt(stringArr[1]));
+        }
     }
 
+    /**
+     * Returns the length of the routing prefix length.
+     * @return the routing prefix length.
+     */
     public int getPrefixLen() {
                return prefixLen;
        }
 
-       public boolean isInNet( final InetAddress address )
+    /**
+     * Determins if the passed in address is contained in this subnet.
+     * @param address The address to test.
+     * @return true if the address is in this subnet.
+     */
+       public boolean isInNet(@Nonnull final InetAddress address )
     {
+        checkNotNull(address, "address must not be null");
+
         final byte[] bytesAddress = address.getAddress();
-        if ( this.bytesSubnetCount != bytesAddress.length )
+        if ( this.addressByteCount != bytesAddress.length ) {
             return false;
+        }
         final BigInteger bigAddress = new BigInteger( bytesAddress );
-        return  bigAddress.and( this.bigMask ).equals( this.bigSubnetMasked );
+        return bigAddress.and(this.mask).equals(this.routingPrefix);
     }
 
     @Override
     final public boolean equals( Object obj )
     {
-        if ( ! (obj instanceof Subnet) )
-            return false;
+        if (null == obj) return false;
+        if (this == obj) return true;
+        if (!(obj instanceof Subnet)) return false;
+
         final Subnet other = (Subnet)obj;
-        return  this.bigSubnetMasked.equals( other.bigSubnetMasked ) &&
-                this.bigMask.equals( other.bigMask ) &&
-                this.bytesSubnetCount == other.bytesSubnetCount;
+        return  this.prefixLen == other.prefixLen &&
+                this.routingPrefix.equals(other.routingPrefix) &&
+                this.mask.equals(other.mask) &&
+                this.addressByteCount == other.addressByteCount;
     }
 
     @Override
     final public int hashCode()
     {
-        return this.bytesSubnetCount;
+        return new HashCodeBuilder(997, 311)
+                .append(prefixLen)
+                .append(mask)
+                .append(routingPrefix)
+                .append(addressByteCount)
+                .build();
     }
 
     @Override
     public String toString()
     {
         final StringBuilder buf = new StringBuilder();
-        bigInteger2IpString( buf, this.bigSubnetMasked, this.bytesSubnetCount );
+        bigInteger2IpString( buf, this.routingPrefix, this.addressByteCount);
         buf.append( '/' );
-        bigInteger2IpString( buf, this.bigMask, this.bytesSubnetCount );
+        bigInteger2IpString( buf, this.mask, this.addressByteCount);
         return buf.toString();
     }
 
@@ -101,13 +198,16 @@ public class Subnet
         int integer;
         for ( int i = 0; i < displayBytes; i++ )
         {
-            if ( 0 < i && ! isIPv4 && i % 2 == 0 )
-                buf.append( ':' );
-            else if ( 0 < i && isIPv4 )
-                buf.append( '.' );
+            if ( 0 < i && ! isIPv4 && i % 2 == 0 ) {
+                buf.append(':');
+            }
+            else if ( 0 < i && isIPv4 ) {
+                buf.append('.');
+            }
             integer = 0xFF & (i < diffLen ? fillByte : bytes[ i - diffLen ]);
-            if ( ! isIPv4 && 0x10 > integer )
-                buf.append( '0' );
+            if ( ! isIPv4 && 0x10 > integer ) {
+                buf.append('0');
+            }
             buf.append( isIPv4 ? integer : Integer.toHexString( integer ) );
         }
     }
index 229c7d726b5ea8d34833f24c98acabce4bb29e17..b0360ad8ac9528e682ab9412f935b4e5f2f739b9 100644 (file)
 package org.opendaylight.controller.packetcable.provider;
 
+import com.google.common.net.InetAddresses;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 
+import static org.hamcrest.CoreMatchers.*;
 import static org.junit.Assert.*;
 
+public class SubnetTest {
 
-import java.net.UnknownHostException;
+    // Various address class level prefix lengths
+    private static final int CLASS_A = 8;
+    private static final int CLASS_B = 16;
+    private static final int CLASS_C = 24;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.Spy;
-import org.mockito.runners.MockitoJUnitRunner;
+    private InetAddress addressV4 = null;
+    private InetAddress addressV6 = null;
 
-import com.google.common.net.InetAddresses;
+    private InetAddress v4MaskClassA;
+    private InetAddress v4MaskClassB;
+    private InetAddress v4MaskClassC;
 
-@RunWith(MockitoJUnitRunner.class)
-public class SubnetTest {
+    @Before
+    public final void setup()
+    {
+        addressV4 = InetAddresses.forString("192.168.0.1");
+        addressV6 = InetAddresses.forString("2001:db8::1");
+
+        v4MaskClassA = InetAddresses.forString("255.0.0.0");
+        v4MaskClassB = InetAddresses.forString("255.255.0.0");
+        v4MaskClassC = InetAddresses.forString("255.255.255.0");
+    }
+
+    @After
+    public final void tearDown()
+    {
+        addressV4 = null;
+        addressV6 = null;
+
+        v4MaskClassA = null;
+        v4MaskClassB = null;
+        v4MaskClassC = null;
+    }
+
+    @Test
+    public final void testCtorCidr()
+    {
+        assertThat(new Subnet(addressV4, 24), is(notNullValue()));
+        assertThat(new Subnet(addressV6, 24), is(notNullValue()));
+    }
+
+    @Test
+    public final void testCtorAddressAndMask()
+    {
+        assertThat(new Subnet(addressV4, InetAddresses.forString("255.255.255.0")), is(notNullValue()));
+        assertThat(new Subnet(addressV4, null), is(notNullValue()));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public final void testSubnetCtorCidrBadMaskv4_1()
+    {
+        new Subnet(addressV4, -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public final void testSubnetCtorCidrBadMaskv4_2()
+    {
+        new Subnet(addressV4, 33);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public final void testSubnetCtorCidrBadMaskv6_1()
+    {
+        new Subnet(addressV6, -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public final void testSubnetCtorCidrBadMaskv6_2()
+    {
+        new Subnet(addressV6, 129);
+    }
+
+    @Test
+    public final void testGetPrefixLen()
+    {
+        Subnet subnet = new Subnet(addressV4, CLASS_C);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_C) );
+
+        subnet = new Subnet(addressV4, CLASS_B);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_B) );
+
+        subnet = new Subnet(addressV4, CLASS_A);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_A) );
+
+        subnet = new Subnet(addressV4, v4MaskClassC);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_C) );
+
+        subnet = new Subnet(addressV4, v4MaskClassB);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_B) );
+
+        subnet = new Subnet(addressV4, v4MaskClassA);
+        assertThat(subnet, is(notNullValue()) );
+        assertThat(subnet.getPrefixLen(), is(CLASS_A) );
+
+    }
+
+    @Test
+    public final void testSubnetCtorCidrAllValidMasks()
+    {
+        // validating no exceptions are thrown for valid masks
+        for (int iMask = 0; iMask < 33; ++iMask) {
+            final Subnet subnet = new Subnet(addressV4, iMask);
+            assertThat(subnet.getPrefixLen(),  is(iMask) );
+        }
+
+        for (int iMask = 0; iMask < 129; ++iMask) {
+            final Subnet subnet = new Subnet(addressV6, iMask);
+            assertThat(subnet.getPrefixLen(),  is(iMask) );
+        }
+    }
+
+
+    @Test
+    public final void testEquals()
+    {
+        final Subnet s41 = new Subnet(addressV4, 24);
+        final Subnet s42 = new Subnet(addressV4, 24);
+        final Subnet s43 = new Subnet(addressV4, 16);
+
+        final Subnet s61 = new Subnet(addressV6, 24);
+        final Subnet s62 = new Subnet(addressV6, 56);
+        final Subnet s63 = new Subnet(addressV6, 56);
+
+        assertThat(s41, is(equalTo(s41)));
+        assertThat(s41, is(equalTo(s42)));
+        assertThat(s41, is(not(equalTo(s43))));
+        assertThat(s41, is(not(equalTo(s61))));
+        assertThat(s41, is(not(equalTo(s62))));
+        assertThat(s41, is(not(equalTo(s63))));
+        assertThat(s41, is(not(equalTo(null))));
+        assertNotEquals(s41, "random string");
+
+        assertThat(s42, is(equalTo(s41)));
+        assertThat(s42, is(equalTo(s42)));
+        assertThat(s42, is(not(equalTo(s43))));
+        assertThat(s42, is(not(equalTo(s61))));
+        assertThat(s42, is(not(equalTo(s62))));
+        assertThat(s42, is(not(equalTo(s63))));
+        assertThat(s42, is(not(equalTo(null))));
+        assertNotEquals(s42, "random string");
+
+        assertThat(s43, is(not(equalTo(s41))));
+        assertThat(s43, is(not(equalTo(s42))));
+        assertThat(s43, is(equalTo(s43)));
+        assertThat(s43, is(not(equalTo(s61))));
+        assertThat(s43, is(not(equalTo(s62))));
+        assertThat(s43, is(not(equalTo(s63))));
+        assertThat(s43, is(not(equalTo(null))));
+        assertNotEquals(s43, "random string");
+
+        assertThat(s61, is(not(equalTo(s41))));
+        assertThat(s61, is(not(equalTo(s42))));
+        assertThat(s61, is(not(equalTo(s43))));
+        assertThat(s61, is(equalTo(s61)));
+        assertThat(s61, is(not(equalTo(s62))));
+        assertThat(s61, is(not(equalTo(s63))));
+        assertThat(s61, is(not(equalTo(null))));
+        assertNotEquals(s61, "random string");
+
+        assertThat(s62, is(not(equalTo(s41))));
+        assertThat(s62, is(not(equalTo(s42))));
+        assertThat(s62, is(not(equalTo(s43))));
+        assertThat(s62, is(not(equalTo(s61))));
+        assertThat(s62, is(equalTo(s62)));
+        assertThat(s62, is(equalTo(s63)));
+        assertThat(s62, is(not(equalTo(null))));
+        assertNotEquals(s62, "random string");
+
+        assertThat(s63, is(not(equalTo(s41))));
+        assertThat(s63, is(not(equalTo(s42))));
+        assertThat(s63, is(not(equalTo(s43))));
+        assertThat(s63, is(not(equalTo(s61))));
+        assertThat(s63, is(equalTo(s62)));
+        assertThat(s63, is(equalTo(s63)));
+        assertThat(s63, is(not(equalTo(null))));
+        assertNotEquals(s63, "random string");
+    }
+
+    @Test
+    public final void testHashcode()
+    {
+        final Subnet s41 = new Subnet(addressV4, 24);
+        final Subnet s42 = new Subnet(addressV4, 24);
+        final Subnet s43 = new Subnet(addressV4, 16);
+
+        final Subnet s61 = new Subnet(addressV6, 24);
+        final Subnet s62 = new Subnet(addressV6, 56);
+        final Subnet s63 = new Subnet(addressV6, 56);
+
+        assertThat(s41.hashCode(), is(equalTo(s41.hashCode())));
+        assertThat(s41.hashCode(), is(equalTo(s42.hashCode())));
+        assertThat(s41.hashCode(), is(not(equalTo(s43.hashCode()))));
+        assertThat(s41.hashCode(), is(not(equalTo(s61.hashCode()))));
+        assertThat(s41.hashCode(), is(not(equalTo(s62.hashCode()))));
+        assertThat(s41.hashCode(), is(not(equalTo(s63.hashCode()))));
+
+        assertThat(s42.hashCode(), is(equalTo(s41.hashCode())));
+        assertThat(s42.hashCode(), is(equalTo(s42.hashCode())));
+        assertThat(s42.hashCode(), is(not(equalTo(s43.hashCode()))));
+        assertThat(s42.hashCode(), is(not(equalTo(s61.hashCode()))));
+        assertThat(s42.hashCode(), is(not(equalTo(s62.hashCode()))));
+        assertThat(s42.hashCode(), is(not(equalTo(s63.hashCode()))));
+
+        assertThat(s43.hashCode(), is(not(equalTo(s41.hashCode()))));
+        assertThat(s43.hashCode(), is(not(equalTo(s42.hashCode()))));
+        assertThat(s43.hashCode(), is(equalTo(s43.hashCode())));
+        assertThat(s43.hashCode(), is(not(equalTo(s61.hashCode()))));
+        assertThat(s43.hashCode(), is(not(equalTo(s62.hashCode()))));
+        assertThat(s43.hashCode(), is(not(equalTo(s63.hashCode()))));
+
+        assertThat(s61.hashCode(), is(not(equalTo(s41.hashCode()))));
+        assertThat(s61.hashCode(), is(not(equalTo(s42.hashCode()))));
+        assertThat(s61.hashCode(), is(not(equalTo(s43.hashCode()))));
+        assertThat(s61.hashCode(), is(equalTo(s61.hashCode())));
+        assertThat(s61.hashCode(), is(not(equalTo(s62.hashCode()))));
+        assertThat(s61.hashCode(), is(not(equalTo(s63.hashCode()))));
+
+        assertThat(s62.hashCode(), is(not(equalTo(s41.hashCode()))));
+        assertThat(s62.hashCode(), is(not(equalTo(s42.hashCode()))));
+        assertThat(s62.hashCode(), is(not(equalTo(s43.hashCode()))));
+        assertThat(s62.hashCode(), is(not(equalTo(s61.hashCode()))));
+        assertThat(s62.hashCode(), is(equalTo(s62.hashCode())));
+        assertThat(s62.hashCode(), is(equalTo(s63.hashCode())));
+
+        assertThat(s63.hashCode(), is(not(equalTo(s41.hashCode()))));
+        assertThat(s63.hashCode(), is(not(equalTo(s42.hashCode()))));
+        assertThat(s63.hashCode(), is(not(equalTo(s43.hashCode()))));
+        assertThat(s63.hashCode(), is(not(equalTo(s61.hashCode()))));
+        assertThat(s63.hashCode(), is(equalTo(s62.hashCode())));
+        assertThat(s63.hashCode(), is(equalTo(s63.hashCode())));
+    }
 
     @Test
     public final void testCreateInstance() throws UnknownHostException {
-           Subnet localSubnet = Subnet.createInstance("192.168.0.0/255.255.255.0");
-           assertNotNull(localSubnet);
-           assertEquals("192.168.0.0/255.255.255.0", localSubnet.toString());
-           assertEquals(Subnet.createInstance("192.168.0.0/255.255.255.0"), localSubnet);
+        Subnet subnet = Subnet.createInstance("192.168.0.0/255.255.255.0");
+        assertThat(subnet, is(notNullValue(Subnet.class)));
+        assertThat(subnet.toString(), is("192.168.0.0/255.255.255.0"));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.0/255.255.255.0"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.0/24"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.10/255.255.255.0"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.10/24"))));
+
+        subnet = Subnet.createInstance("192.168.0.1");
+        assertThat(subnet, is(notNullValue(Subnet.class)));
+        assertThat(subnet.toString(), is("192.168.0.1/255.255.255.255"));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.1"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.1/32"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.1/255.255.255.255"))));
+
+        subnet = Subnet.createInstance("192.168.0.0/8");
+        assertThat(subnet, is(notNullValue(Subnet.class)));
+        assertThat(subnet.toString(), is("192.0.0.0/255.0.0.0"));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.168.0.0/8"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.175.0.10/8"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.10.0.0/255.0.0.0"))));
+        assertThat(subnet, is(equalTo(Subnet.createInstance("192.1.0.100/255.0.0.0"))));
+
+    }
+
+    @Test
+    public final void testIsInNet()
+    {
+        Subnet subnet = new Subnet(addressV4, CLASS_C);
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.100")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.168.1.1")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.167.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("191.168.0.1")));
+        assertFalse(subnet.isInNet(addressV6));
+
+        subnet = new Subnet(addressV4, CLASS_B);
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.100")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.255")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.1.1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.1.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.167.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("191.168.0.1")));
+        assertFalse(subnet.isInNet(addressV6));
+
+        subnet = new Subnet(addressV4, CLASS_A);
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.100")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.255")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.1.1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.1.255")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.167.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("191.168.0.1")));
+        assertFalse(subnet.isInNet(addressV6));
+
+        subnet = new Subnet(addressV4, 32);
+        assertTrue(subnet.isInNet(InetAddresses.forString("192.168.0.1")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.168.0.100")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.168.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.168.1.1")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.168.1.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("192.167.0.255")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("191.168.0.1")));
+        assertFalse(subnet.isInNet(addressV6));
+
+        subnet = new Subnet(addressV6, 64);
+        assertTrue(subnet.isInNet(InetAddresses.forString("2001:db8::1")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("2001:db8::100")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("2001:db8::ffff")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("2001:db7::1")));
+        assertFalse(subnet.isInNet(InetAddresses.forString("2000:db8::")));
+        assertTrue(subnet.isInNet(InetAddresses.forString("2001:db8:0:0:1::1")));
+        assertFalse(subnet.isInNet(addressV4));
+
     }
 }