package hirs.data.persist;

import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * NetworkInfoTest is a unit test class for NetworkInfo.
 */
public class NetworkInfoTest {

    private static final String HOSTNAME = "test hostname";
    private static final InetAddress IP_ADDRESS = getTestIpAddress();
    private static final byte[] MAC_ADDRESS = new byte[] {11, 22, 33, 44, 55,
            66};

    private static InetAddress getTestIpAddress() {
        try {
            final byte[] byteAddress = new byte[] {127, 0, 0, 1};
            return InetAddress.getByAddress(byteAddress);
        } catch (UnknownHostException e) {
            return null;
        }
    }

    /**
     * Tests instantiation of a NetworkInfo object.
     */
    @Test
    public final void networkInfo() {
        new NetworkInfo(null, null, null);
    }

    /**
     * Tests the getter for hostname of the NetworkInfo object. Hostname can be
     * null if not known.
     */
    @Test
    public final void hostnameTest() {
        NetworkInfo networkInfo = new NetworkInfo(null, null, null);
        Assertions.assertNull(networkInfo.getHostname());

        networkInfo = new NetworkInfo(HOSTNAME, null, null);
        Assertions.assertEquals(HOSTNAME, networkInfo.getHostname());
    }

    /**
     * Tests the getter for the IP address of the NetworkInfo object. IP address
     * can be null if not known.
     */
    @Test
    public final void ipAddressTest() {
        NetworkInfo networkInfo = new NetworkInfo(null, null, null);
        Assertions.assertNull(networkInfo.getIpAddress());

        networkInfo = new NetworkInfo(null, IP_ADDRESS, null);
        Assertions.assertEquals(IP_ADDRESS, networkInfo.getIpAddress());
    }

    /**
     * Tests the getter for the MAC address of the NetworkInfo object. MAC
     * address can be null if not known.
     */
    @Test
    public final void macAddressTest() {
        NetworkInfo networkInfo = new NetworkInfo(null, null, null);
        Assertions.assertNull(networkInfo.getMacAddress());

        networkInfo = new NetworkInfo(null, null, MAC_ADDRESS);
        Assertions.assertArrayEquals(MAC_ADDRESS, networkInfo.getMacAddress());
    }

    /**
     * Tests that trying to set the MAC address to a byte array that's an
     * invalid size throws an exception.
     */
    @Test
    public final void macAddressInvalidSizeTest() {
        final byte[] invalidMacAddress = new byte[] {11, 22, 33, 44, 55};
        Assertions.assertThrows(IllegalArgumentException.class, () -> new NetworkInfo(
                null, null, invalidMacAddress
        ));
    }

    /**
     * Tests that hashcodes generated by two equal NetworkInfo objects are
     * equal.
     */
    @Test
    public final void testHashCodeEquals() {
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        Assertions.assertEquals(ni2.hashCode(), ni1.hashCode());
    }

    /**
     * Tests that hashcodes generated by NetworkInfo objects with different
     * hostnames are not equal.
     */
    @Test
    public final void testHashCodeNotEqualsHostname() {
        String hostname2 = "test hostname2";
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(hostname2, IP_ADDRESS, MAC_ADDRESS);
        Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode());
    }

    /**
     * Tests that hashcodes generated by NetworkInfo objects with different IP
     * addresses are not equal.
     *
     * @throws UnknownHostException in case the InetAddress is not created correctly
     */
    @Test
    public final void testHashCodeNotEqualsIpAddress()
            throws UnknownHostException {
        final byte[] byteAddress = new byte[] {127, 0, 0, 2};
        final InetAddress ipAddress2 =
                InetAddress.getByAddress(byteAddress);
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
        Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode());
    }

    /**
     * Tests that hashcodes generated by NetworkInfo objects with different MAC
     * address are not equal.
     */
    @Test
    public final void testHashCodeNotEqualsMacAddress() {
        final byte[] macAddress2 = new byte[] {11, 22, 33, 44, 55, 67};
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2);
        Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode());
    }

    /**
     * Tests that two NetworkInfo objects are equal if they have the same
     * hostname, IP address, and MAC address.
     */
    @Test
    public final void testEqual() {
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        Assertions.assertEquals(ni2, ni1);
    }

    /**
     * Tests that two NetworkInfo objects are not equal if they have different
     * hostnames.
     */
    @Test
    public final void testNotEqualsHostname() {
        String hostname2 = "test hostname2";
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(hostname2, IP_ADDRESS, MAC_ADDRESS);
        Assertions.assertNotEquals(ni2, ni1);
    }

    /**
     * Tests that two NetworkInfo objects are not equal if they have different
     * IP addresses.
     *
     * @throws UnknownHostException in case InetAddress is not created correctly
     */
    @Test
    public final void testNotEqualsIpAddress() throws UnknownHostException {
        final byte[] byteAddress = new byte[] {127, 0, 0, 2};
        final InetAddress ipAddress2 =
                InetAddress.getByAddress(byteAddress);
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
        Assertions.assertNotEquals(ni2, ni1);
    }

    /**
     * Tests that two NetworkInfo objects are not equal if they have different
     * MAC addresses.
     */
    @Test
    public final void testNotEqualsMacAddress() {
        final byte[] macAddress2 = new byte[] {11, 22, 33, 44, 55, 67};
        NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
        NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2);
        Assertions.assertNotEquals(ni2, ni1);
    }
}
