// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
// Copyright (c) 2011, 2012 Open Networking Foundation
// Copyright (c) 2012, 2013 Big Switch Networks, Inc.
// This library was generated by the LoxiGen Compiler.
// See the file LICENSE.txt which should have been included in the source distribution

// Automatically generated by LOXI from template unit_test.java
// Do not modify

package org.projectfloodlight.openflow.protocol.ver13;

import org.projectfloodlight.openflow.protocol.*;
import org.projectfloodlight.openflow.protocol.action.*;
import org.projectfloodlight.openflow.protocol.actionid.*;
import org.projectfloodlight.openflow.protocol.bsntlv.*;
import org.projectfloodlight.openflow.protocol.errormsg.*;
import org.projectfloodlight.openflow.protocol.meterband.*;
import org.projectfloodlight.openflow.protocol.instruction.*;
import org.projectfloodlight.openflow.protocol.instructionid.*;
import org.projectfloodlight.openflow.protocol.match.*;
import org.projectfloodlight.openflow.protocol.oxm.*;
import org.projectfloodlight.openflow.protocol.queueprop.*;
import org.projectfloodlight.openflow.types.*;
import org.projectfloodlight.openflow.util.*;
import org.projectfloodlight.openflow.exceptions.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.Before;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.hamcrest.CoreMatchers;



public class OFBsnVirtualPortCreateRequestVer13L2GreTest {
    OFFactory factory;

    final static byte[] BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED =
        new byte[] { 0x4, 0x4, 0x0, 0x50, 0x1, 0x2, 0x3, 0x4, 0x0, 0x5c, 0x16, (byte) 0xc7, 0x0, 0x0, 0x0, 0xf, 0x0, 0x1, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, (byte) 0xc0, 0x0, 0x0, 0x2, (byte) 0xc0, 0x0, 0x10, 0x2, 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, (byte) 0xbe, (byte) 0xef, 0x0, 0x0, 0x4, 0x0, 0x66, 0x6f, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

    @Before
    public void setup() {
        factory = OFFactoryVer13.INSTANCE;
    }

    @Test
    public void testWrite() {
        OFBsnVirtualPortCreateRequest.Builder builder = factory.buildBsnVirtualPortCreateRequest();
        builder.setXid(0x01020304)
    .setVport(
        factory.buildBsnVportL2Gre()
            .setFlags(
                ImmutableSet.<OFBsnVportL2GreFlags>of(
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_DSCP_ASSIGN,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOOPBACK_IS_VALID,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_RATE_LIMIT_IS_VALID
                )
            )
            .setPortNo(OFPort.of(1))
            .setLoopbackPortNo(OFPort.of(2))
            .setLocalMac(MacAddress.of("0a:0b:0c:0d:0e:0f"))
            .setNhMac(MacAddress.of("01:02:03:04:05:06"))
            .setSrcIp(IPv4Address.of("192.0.0.2"))
            .setDstIp(IPv4Address.of("192.0.16.2"))
            .setDscp((short)1)
            .setTtl((short)64)
            .setVpn(0xbeef)
            .setRateLimit(0x400)
            .setIfName("foo")
            .build()
    );;
        OFBsnVirtualPortCreateRequest bsnVirtualPortCreateRequest = builder.build();
        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
        bsnVirtualPortCreateRequest.writeTo(bb);
        byte[] written = new byte[bb.readableBytes()];
        bb.readBytes(written);

        assertThat(written, CoreMatchers.equalTo(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED));
    }

    @Test
    public void testRead() throws Exception {
        OFBsnVirtualPortCreateRequest.Builder builder = factory.buildBsnVirtualPortCreateRequest();
        builder.setXid(0x01020304)
    .setVport(
        factory.buildBsnVportL2Gre()
            .setFlags(
                ImmutableSet.<OFBsnVportL2GreFlags>of(
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_DSCP_ASSIGN,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOOPBACK_IS_VALID,
                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_RATE_LIMIT_IS_VALID
                )
            )
            .setPortNo(OFPort.of(1))
            .setLoopbackPortNo(OFPort.of(2))
            .setLocalMac(MacAddress.of("0a:0b:0c:0d:0e:0f"))
            .setNhMac(MacAddress.of("01:02:03:04:05:06"))
            .setSrcIp(IPv4Address.of("192.0.0.2"))
            .setDstIp(IPv4Address.of("192.0.16.2"))
            .setDscp((short)1)
            .setTtl((short)64)
            .setVpn(0xbeef)
            .setRateLimit(0x400)
            .setIfName("foo")
            .build()
    );;
        OFBsnVirtualPortCreateRequest bsnVirtualPortCreateRequestBuilt = builder.build();

        ChannelBuffer input = ChannelBuffers.copiedBuffer(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED);

        // FIXME should invoke the overall reader once implemented
        OFBsnVirtualPortCreateRequest bsnVirtualPortCreateRequestRead = OFBsnVirtualPortCreateRequestVer13.READER.readFrom(input);
        assertEquals(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED.length, input.readerIndex());

        assertEquals(bsnVirtualPortCreateRequestBuilt, bsnVirtualPortCreateRequestRead);
   }

   @Test
   public void testReadWrite() throws Exception {
       ChannelBuffer input = ChannelBuffers.copiedBuffer(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED);

       // FIXME should invoke the overall reader once implemented
       OFBsnVirtualPortCreateRequest bsnVirtualPortCreateRequest = OFBsnVirtualPortCreateRequestVer13.READER.readFrom(input);
       assertEquals(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED.length, input.readerIndex());

       // write message again
       ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
       bsnVirtualPortCreateRequest.writeTo(bb);
       byte[] written = new byte[bb.readableBytes()];
       bb.readBytes(written);

       assertThat(written, CoreMatchers.equalTo(BSN_VIRTUAL_PORT_CREATE_REQUEST_SERIALIZED));
   }

}
