/*
 * Copyright 2016 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onosproject.ospf.protocol.util;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.Ip4Address;
import org.onosproject.ospf.protocol.lsa.LsaHeader;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

/**
 * Unit test class for OspfUtil.
 */
public class OspfUtilTest {

    private final int ospfChecksumPos1 = 12;
    private final int ospfChecksumPos2 = 13;
    private final int lsaChecksumPos1 = 16;
    private final int lsaChecksumPos2 = 17;
    private final int ospfLengthPos1 = 2;
    private final int ospfLengthPos2 = 3;
    private final int lsaLengthPos1 = 18;
    private final int lsaLengthPos2 = 19;
    private final byte[] input = {0, 2};
    private final byte[] packet = {2, 1, 0, 52, -64, -88, 56, 1, -64, -88, 56, 1, 0, 100, 0, 100, 0, 0, 0, 0, 0, 0,
            0, 0, -64, -88, 56, 1, 0, 10, 1, 1, 0, 0, 0, 40, -64, -88, 56, 1, -64, -88, 56, 1, -64, -88, 56, 1, -64,
            -88, 56, 1};
    private final byte[] rLsa = {14, 16, 2, 1, -64, -88, -86, 2, -64, -88, -86, 2, -128, 0, 0, 1, 74, -114, 0, 48, 2,
            0, 0, 2, -64, -88, -86, 0, -1, -1, -1, 0, 3, 0, 0, 10, -64, -88, -86, 0, -1, -1, -1, 0, 3, 0, 0, 10};
    private final byte[] opaqueheader = {14, 16, 2, 1, -64, -88, -86, 2, -64, -88, -86, 2, -128, 0, 0, 1, 74, -114,
            0, 48};
    private int num;
    private int result;
    private int input2;
    private long input4;
    private ChannelBuffer channelBuffer;
    private byte[] result1;
    private LsaHeader lsaHeader;
    private boolean result2;
    private long result3;


    @Before
    public void setUp() throws Exception {

    }

    @After
    public void tearDown() throws Exception {
        channelBuffer = null;
        result1 = null;
        lsaHeader = null;
    }


    /**
     * Tests byteToInteger() method.
     */
    @Test
    public void testByteToInteger() throws Exception {
        result = OspfUtil.byteToInteger(input);
        assertThat(result, is(notNullValue()));
        assertThat(result, is(2));

    }

    /**
     * Tests byteToLong() method.
     */
    @Test
    public void testByteToLong() throws Exception {
        result3 = OspfUtil.byteToLong(input);
        assertThat(result3, is(notNullValue()));
        assertThat(result3, is(2L));
    }

    /**
     * Tests byteToInteger() method.
     */
    @Test
    public void testByteToLong1() throws Exception {
        result3 = OspfUtil.byteToLong(input);
        assertThat(result3, is(notNullValue()));
        assertThat(result3, is(2L));
    }

    /**
     * Tests byteToInteger() method.
     */
    @Test
    public void testByteToInteger1() throws Exception {
        result = OspfUtil.byteToInteger(input);
        assertThat(result, is(notNullValue()));
        assertThat(result, is(2));
    }

    /**
     * Tests to createRandomNumber() method.
     */
    @Test
    public void testCreateRandomNumber() throws Exception {
        num = OspfUtil.createRandomNumber();
        assertThat(num, is(notNullValue()));
    }

    /**
     * Tests readLsaHeader() method.
     */
    @Test
    public void testReadLsaHeader2() throws Exception {
        channelBuffer = ChannelBuffers.copiedBuffer(packet);
        lsaHeader = OspfUtil.readLsaHeader(channelBuffer);
        assertThat(lsaHeader, is(notNullValue()));
    }

    /**
     * Tests to readLsaHeader method.
     */
    @Test
    public void testReadLsaHeader1() throws Exception {
        channelBuffer = ChannelBuffers.copiedBuffer(opaqueheader);
        lsaHeader = OspfUtil.readLsaHeader(channelBuffer);
        assertThat(lsaHeader, is(notNullValue()));
    }

    /**
     * Tests convertToTwoBytes() method.
     */
    @Test
    public void testConvertToTwoBytes() throws Exception {
        input2 = 4;
        result1 = OspfUtil.convertToTwoBytes(input2);
        assertThat(result1.length, is(2));
        input2 = 1000;
        result1 = OspfUtil.convertToTwoBytes(input2);
        assertThat(result1.length, is(2));
    }

    /**
     * Tests convertToThreeBytes() method.
     */
    @Test
    public void testConvertToThreeBytes() throws Exception {
        input2 = 1000000;
        result1 = OspfUtil.convertToThreeBytes(input2);
        assertThat(result1.length, is(3));
        input2 = 1000;
        result1 = OspfUtil.convertToThreeBytes(input2);
        assertThat(result1.length, is(3));
        input2 = 1;
        result1 = OspfUtil.convertToThreeBytes(input2);
        assertThat(result1.length, is(3));
    }

    /**
     * Tests convertToFourBytes() method.
     */
    @Test
    public void testConvertToFourBytes() throws Exception {
        input4 = 214748364110L;
        result1 = OspfUtil.convertToFourBytes(input4);
        assertThat(result1.length, is(4));
        input4 = 1000000;
        result1 = OspfUtil.convertToFourBytes(input4);
        assertThat(result1.length, is(4));
        input4 = 10000;
        result1 = OspfUtil.convertToFourBytes(input4);
        assertThat(result1.length, is(4));
        input4 = 1;
        result1 = OspfUtil.convertToFourBytes(input4);
        assertThat(result1.length, is(4));

    }

    /**
     * Tests convertToFourBytes() method.
     */
    @Test
    public void testConvertToFourBytes1() throws Exception {
        input4 = 2147483635;
        result1 = OspfUtil.convertToFourBytes(this.input4);
        assertThat(result1.length, is(4));
        this.input4 = 1000000;
        result1 = OspfUtil.convertToFourBytes(this.input4);
        assertThat(result1.length, is(4));
        this.input4 = 10000;
        result1 = OspfUtil.convertToFourBytes(this.input4);
        assertThat(result1.length, is(4));
        this.input4 = 1;
        result1 = OspfUtil.convertToFourBytes(this.input4);
        assertThat(result1.length, is(4));

    }

    /**
     * Tests addLengthAndCheckSum() method.
     */
    @Test
    public void testAddLengthAndCheckSum() throws Exception {
        result1 = OspfUtil.addLengthAndCheckSum(packet, ospfLengthPos1, ospfLengthPos2,
                                                ospfChecksumPos1, ospfChecksumPos2);
        assertThat(result1[ospfChecksumPos1], is(packet[ospfChecksumPos1]));
        assertThat(result1[ospfChecksumPos2], is(packet[ospfChecksumPos2]));
        assertThat(result1[ospfLengthPos1], is(packet[ospfLengthPos1]));
        assertThat(result1[ospfLengthPos2], is(packet[ospfLengthPos2]));
    }

    /**
     * Tests addMetadata() method.
     */
    @Test
    public void testAddMetadata() throws Exception {
        result1 = OspfUtil.addMetadata(packet, 123, Ip4Address.valueOf("1.1.1.1"));
        assertThat(result1, is(notNullValue()));
    }

    /**
     * Tests addLengthAndCheckSum() method.
     */
    @Test
    public void testAddLsaLengthAndCheckSum() throws Exception {
        result1 = OspfUtil.addLengthAndCheckSum(rLsa, lsaLengthPos1, lsaLengthPos2,
                                                lsaChecksumPos1, lsaChecksumPos2);
        assertThat(result1[lsaLengthPos1], is(rLsa[lsaLengthPos1]));
        assertThat(result1[lsaLengthPos2], is(rLsa[lsaLengthPos2]));
        assertThat(result1[lsaChecksumPos1], is(rLsa[lsaChecksumPos1]));
        assertThat(result1[lsaChecksumPos2], is(rLsa[lsaChecksumPos2]));
    }

    /**
     * Tests addMetadata() method.
     */
    @Test
    public void testAddMetaData() throws Exception {
        result1 = OspfUtil.addMetadata(packet, 1, Ip4Address.valueOf("2.2.2.2"));
        assertThat(result1, is(notNullValue()));
    }

    /**
     * Tests sameNetwork() method.
     */
    @Test
    public void testSameNetwork() throws Exception {
        result2 = OspfUtil.sameNetwork(Ip4Address.valueOf("10.10.10.10"), Ip4Address.valueOf("10.10.10.11"),
                                       Ip4Address.valueOf("255.255.255.255"));
        assertThat(result2, is(false));
        result2 = OspfUtil.sameNetwork(Ip4Address.valueOf("10.10.10.10"), Ip4Address.valueOf("10.10.10.10"),
                                       Ip4Address.valueOf("255.255.255.255"));
        assertThat(result2, is(true));
    }

    /**
     * Tests isOpaqueEnabled() method.
     */
    @Test
    public void testIsOpaqueEnabled() throws Exception {
        result2 = OspfUtil.isOpaqueEnabled(2);
        assertThat(result2, is(false));
    }

    /**
     * Tests sameNetwork() method.
     */
    @Test
    public void testisIsOpaqueEnabled() throws Exception {
        result2 = OspfUtil.isOpaqueEnabled(2);
        assertThat(result2, is(false));
    }

    /**
     * Tests readLsaHeader() method.
     */
    @Test
    public void testReadLsaHeader() throws Exception {
        byte[] header = {0, 10, 2, 1, 7, 7, 7, 7, 7, 7, 7, 7, -128, 0, 0, 2, 46, -126, 0,
                48, 0, 0, 0, 2, 1, 1, 1, 1, 10, 10, 10, 7, 1, 0, 0, 10, 10, 10, 10, 0, -1, -1, -1,
                0, 3, 0, 0, 10, 0, 10, 66, 10, 1, 0, 0, 1, 7, 7, 7, 7, -128, 0, 0, 1, -64, 79, 0,
                116, 0, 1, 0, 4, 0, 0, 0, 0, 0, 2, 0, 84, 0, 1, 0, 1, 1, 0, 0, 0, 0, 2, 0, 4, 10,
                10, 10, 0, 0, 5, 0, 4, 0, 0, 0, 0, 0, 6, 0, 4, 73, -104, -106, -128, 0, 7, 0, 4, 73
                , -104, -106, -128, 0, 8, 0, 32, 73, -104, -106, -128, 73, -104, -106, -128, 73, -104, -106,
                -128, 73, -104, -106, -128, 73, -104, -106, -128, 73, -104, -106, -128, 73, -104, -106, -128,
                73, -104, -106, -128, 0, 9, 0, 4, 0, 0, 0, 0};
        channelBuffer = ChannelBuffers.copiedBuffer(header);
        lsaHeader = OspfUtil.readLsaHeader(channelBuffer);
        assertThat(lsaHeader, is(notNullValue()));
    }

    /**
     * Tests readLsaHeader() method.
     */
    @Test
    public void testReadreadLsaHeader() throws Exception {
        byte[] header = {0, 2, 2, 1, -64, -88, -86, 3, -64, -88, -86, 3, -128, 0, 0, 1, 58, -100, 0, 48};
        channelBuffer = ChannelBuffers.copiedBuffer(header);
        lsaHeader = OspfUtil.readLsaHeader(channelBuffer);
        assertThat(lsaHeader, is(notNullValue()));
    }
}