package org.mockejb.jms.test;

import javax.jms.*;

import org.mockejb.jms.BytesMessageImpl;
import org.mockejb.jms.MessageUtility;

import java.io.*;

/**
 * Tests <code>BytesMessageImpl</code>.
 * 
 * @author Dimitar Gospodinov
 */
public class BytesMessageImplTest extends MessageTester {

    private BytesMessage msg;
    
    public BytesMessageImplTest(String name) {
        super(name);
    }

    protected void setUp() throws Exception {
        msg = new BytesMessageImpl();
        message = msg;
        super.setUp();
    }

    protected void tearDown() throws Exception {
        msg = null;
    }

    public void testMessageNotReadable() throws JMSException {

        // Uncomment if using JMS 1.1 or later.
        //        try {
        //            msg.getBodyLength();
        //            fail();
        //        } catch (MessageNotReadableException ex) {
        //        }
        try {
            msg.readBoolean();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readByte();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readBytes(new byte[5]);
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readBytes(new byte[5], 5);
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readChar();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readDouble();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readFloat();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readInt();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readLong();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readShort();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readUnsignedByte();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readUnsignedShort();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        try {
            msg.readUTF();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        checkMessageAttributes();
    }

    public void testMessageNotWritable() throws JMSException {

        msg.reset();
        
        // Uncomment if using JMS 1.1 or later.
        //        assertEquals(msg.getBodyLength(), 0);

        try {
            msg.writeBoolean(true);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeByte((byte) 1);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeBytes(new byte[5]);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeBytes(null);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeBytes(new byte[5], 0, 1);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeChar('a');
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeDouble(123.33);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeFloat((float) 22.22);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeInt(122);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeLong(11);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeShort((short) 88);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeObject(null);
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        try {
            msg.writeUTF("utf");
            fail();
        } catch (MessageNotWriteableException ex) {
        }
        checkMessageAttributes();
    }

    public void testBytesMessage() throws Throwable {

        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        DataOutputStream dataOut = new DataOutputStream(bytesOut);

        byte[] bytesData1 = { 1, 2, 3, 4, 5 };

        // Write to BytesMessage and DataOutputStream and then compare

        msg.writeBoolean(true);
        dataOut.writeBoolean(true);
        msg.writeByte((byte) 255);
        dataOut.writeByte((byte) 255);
        msg.writeBytes(bytesData1);
        dataOut.write(bytesData1);
        msg.writeBytes(bytesData1, 1, 2);
        dataOut.write(bytesData1, 1, 2);
        msg.writeChar('a');
        dataOut.writeChar('a');
        msg.writeDouble(1.77E307);
        dataOut.writeDouble(1.77E307);
        msg.writeFloat((float) 44.9991);
        dataOut.writeFloat((float) 44.9991);
        msg.writeInt(65536);
        dataOut.writeInt(65536);
        msg.writeLong(9999222233338888L);
        dataOut.writeLong(9999222233338888L);
        msg.writeShort((short) 32000);
        dataOut.writeShort(32000);
        msg.writeUTF("UTF");
        dataOut.writeUTF("UTF");

        byte[] bytes1 = bytesOut.toByteArray();

        msg.reset();
        compareBytes(bytes1, msg);

        /*
         * At this point all bytes from msg have been read. Any read must throw EOF
         * exception, except <code>readBytes</code> methods, which must return
         * -1.
         */
        try {
            msg.readUTF();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readShort();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readLong();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readInt();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readFloat();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readDouble();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readChar();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readByte();
            fail();
        } catch (MessageEOFException ex) {
        }
        try {
            msg.readBoolean();
            fail();
        } catch (MessageEOFException ex) {
        }
        assertEquals(msg.readBytes(new byte[50]), -1);
        assertEquals(msg.readBytes(new byte[50], 5), -1);
        try {
            msg.readBytes(new byte[50], -11);
            fail();
        } catch (IndexOutOfBoundsException ex) {
        }

        msg.reset();

        byte[] bytes2 = new byte[7];

        assertTrue(msg.readBoolean());
        assertEquals(msg.readByte(), (byte) 255);
        assertEquals(msg.readBytes(bytes2), 7);
        assertEquals(bytes2[0], 1);
        assertEquals(bytes2[1], 2);
        assertEquals(bytes2[2], 3);
        assertEquals(bytes2[3], 4);
        assertEquals(bytes2[4], 5);
        assertEquals(bytes2[5], 2);
        assertEquals(bytes2[6], 3);
        assertEquals(msg.readChar(), 'a');
        assertEquals(msg.readDouble(), 1.77E307, 0.01E307);
        assertEquals(msg.readFloat(), (float) 44.9991, (float) 0.0001);
        assertEquals(msg.readInt(), 65536);
        assertEquals(msg.readLong(), 9999222233338888L);
        assertEquals(msg.readShort(), (short) 32000);
        assertEquals(msg.readUTF(), "UTF");

        msg.reset();
        msg.readBoolean();
        msg.readByte();
        msg.readBytes(bytes2, 6);

        assertTrue(MessageUtility.compare(msg, new BytesMessageImpl(msg)));
        
        assertEquals(msg.readByte(), (byte) 3);
        assertEquals(msg.readChar(), 'a');
        assertEquals(msg.readDouble(), 1.77E307, 0.01E307);
        assertEquals(msg.readFloat(), (float) 44.9991, (float) 0.0001);
        assertEquals(msg.readInt(), 65536);
        assertEquals(msg.readLong(), 9999222233338888L);
        assertEquals(msg.readShort(), (short) 32000);
        assertEquals(msg.readUTF(), "UTF");

        checkMessageAttributes();
    }

    public void testReadOfUTF() throws JMSException {

        msg.writeLong(0x0001FFFF0001FF00L);
        msg.writeShort((short) 29999);
        msg.writeLong(0);
        msg.writeUTF("An UTF");
        msg.reset();

        try {
            msg.readUTF();
            fail();
        } catch (MessageFormatException ex) {
        }
        assertEquals(msg.readInt(), 0x1FFFF);
        try {
            msg.readUTF();
            fail();
        } catch (MessageFormatException ex) {
        }
        assertEquals(msg.readInt(), 0x0001FF00);
        assertEquals(msg.readShort(), (short) 29999);
        assertEquals(msg.readLong(), 0);
        assertEquals(msg.readUTF(), "An UTF");
    }

    public void testCloneOfWritableMessage() throws JMSException {

        msg.writeByte((byte) 253);
        msg.writeByte((byte) 254);
        msg.writeByte((byte) 255);

        BytesMessage msg1 = new BytesMessageImpl(msg);

        try {
            msg.readByte();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        msg.writeChar('X');
        msg.reset();

        byte[] bytes = new byte[5];
        assertEquals(msg.readBytes(bytes), 5);
        assertEquals(bytes[0], (byte) 253);
        assertEquals(bytes[1], (byte) 254);
        assertEquals(bytes[2], (byte) 255);
        assertEquals(bytes[3], (byte) (8 >> 'X'));
        assertEquals(bytes[4], (byte) 'X');
        msg.reset();
        bytes = new byte[3];
        assertEquals(msg.readBytes(bytes, 3), 3);

        try {
            msg1.readByte();
            fail();
        } catch (MessageNotReadableException ex) {
        }
        msg1.reset();
        compareBytes(bytes, msg1);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
    }

    private void compareBytes(byte[] sourceBytes, BytesMessage msg)
        throws JMSException {
        byte[] msgBytes1 = new byte[sourceBytes.length];
        byte[] msgBytes2 = new byte[sourceBytes.length];

        assertEquals(msg.readBytes(msgBytes1), sourceBytes.length);
        assertEquals(msg.readBytes(msgBytes2), -1);
        for (int i = 0; i < sourceBytes.length; i++) {
            assertEquals(sourceBytes[i], msgBytes1[i]);
            assertEquals(msgBytes2[i], 0);
        }
    }

}