package org.mockejb.jms.test;

import java.util.Enumeration;
import javax.jms.*;

import org.mockejb.jms.MapMessageImpl;
import org.mockejb.jms.MessageUtility;

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

    private MapMessage msg;

    public MapMessageImplTest(String name) {
        super(name);
    }

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

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

    public void testAllValues() throws JMSException {
        assertFalse(msg.getMapNames().hasMoreElements());
        assertNull(msg.getObject("some name"));

        msg.setBoolean("boolean", false);
        msg.setByte("byte", (byte) 127);
        msg.setShort("short", (short) 8192);
        msg.setShort("short", (short) 8193);
        msg.setInt("int", 65536);
        msg.setLong("long", 400111000111L);
        msg.setFloat("float", (float) 34.8);
        msg.setDouble("double", 23232311111.8821);
        msg.setString("string", "str_val");
        Object obj = Long.valueOf("900111000111");
        msg.setObject("obj_long", obj);
        msg.setBoolean("boolean1", true);
        msg.setChar("char", 'd');

        byte[] bytes = { 1, 2, 3, 4, 127 };
        msg.setBytes("bytes1", bytes);
        msg.setBytes("bytes2", bytes, 2, 3);

        checkValues(msg, obj);
        MapMessage msg1 = new MapMessageImpl(msg);
        checkValues(new MapMessageImpl(msg), obj);
        checkMessageAttributes(msg1);
        checkMessageAttributes();

        msg.clearProperties();
        assertFalse(msg.getPropertyNames().hasMoreElements());

        try {
            msg.setObjectProperty("obj", new Object());
            fail();
        } catch (MessageFormatException ex) {
        }
    }

    private void checkValues(MapMessage msg, Object objValue)
        throws JMSException {
        Enumeration e = msg.getMapNames();
        int i = 0;
        Object obj;
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            if (name.equals("boolean")) {
                assertFalse(msg.getBoolean("boolean"));
                obj = msg.getObject("boolean");
                assertTrue(obj instanceof Boolean);
                assertFalse(((Boolean) obj).booleanValue());
            } else if (name.equals("byte")) {
                assertEquals(msg.getByte("byte"), (byte) 127);
                obj = msg.getObject("byte");
                assertTrue(obj instanceof Byte);
                assertEquals(((Byte) obj).byteValue(), (byte) 127);
            } else if (name.equals("short")) {
                assertEquals(msg.getShort("short"), (short) 8193);
                obj = msg.getObject("short");
                assertTrue(obj instanceof Short);
                assertEquals(((Short) obj).shortValue(), (short) 8193);
            } else if (name.equals("int")) {
                assertEquals(msg.getInt("int"), 65536);
                obj = msg.getObject("int");
                assertTrue(obj instanceof Integer);
                assertEquals(((Integer) obj).intValue(), 65536);
            } else if (name.equals("long")) {
                assertEquals(msg.getLong("long"), 400111000111L);
                obj = msg.getObject("long");
                assertTrue(obj instanceof Long);
                assertEquals(((Long) obj).longValue(), 400111000111L);
            } else if (name.equals("float")) {
                assertEquals(msg.getFloat("float"), (float) 34.8, (float) 0.1);
                obj = msg.getObject("float");
                assertTrue(obj instanceof Float);
                assertEquals(
                    ((Float) obj).floatValue(),
                    (float) 34.8,
                    (float) 0.1);
            } else if (name.equals("double")) {
                assertEquals(msg.getDouble("double"), 23232311111.8821, 0.0001);
                obj = msg.getObject("double");
                assertTrue(obj instanceof Double);
                assertEquals(
                    ((Double) obj).doubleValue(),
                    23232311111.8821,
                    0.0001);
            } else if (name.equals("string")) {
                assertEquals(msg.getString("string"), "str_val");
                obj = msg.getObject("string");
                assertTrue(obj instanceof String);
                assertEquals(obj, "str_val");
            } else if (name.equals("obj_long")) {
                assertSame(msg.getObject("obj_long"), objValue);
            } else if (name.equals("boolean1")) {
                assertTrue(msg.getBoolean("boolean1"));
                obj = msg.getObject("boolean1");
                assertTrue(obj instanceof Boolean);
                assertTrue(((Boolean) obj).booleanValue());
            } else if (name.equals("char")) {
                assertEquals(msg.getChar("char"), 'd');
                obj = msg.getObject("char");
                assertTrue(obj instanceof Character);
                assertEquals(((Character) obj).charValue(), 'd');
            } else if (name.equals("bytes1")) {
                byte[] bytes = msg.getBytes("bytes1");
                assertNotNull(bytes);
                assertEquals(bytes.length, 5);
                assertEquals((byte) bytes[0], (byte) 1);
                assertEquals((byte) bytes[1], (byte) 2);
                assertEquals((byte) bytes[2], (byte) 3);
                assertEquals((byte) bytes[3], (byte) 4);
                assertEquals((byte) bytes[4], (byte) 127);
            } else if (name.equals("bytes2")) {
                byte[] bytes = msg.getBytes("bytes2");
                assertNotNull(bytes);
                assertEquals(bytes.length, 3);
                assertEquals((byte) bytes[0], (byte) 3);
                assertEquals((byte) bytes[1], (byte) 4);
                assertEquals((byte) bytes[2], (byte) 127);
            } else {
                fail();
            }
            i++;
        }
        assertEquals(i, 13);
    }

    public void testBoolean() throws JMSException {

        msg.setBoolean("boolean", true);
        assertTrue(msg.itemExists("boolean"));
        assertTrue(msg.getBoolean("boolean"));
        assertEquals(msg.getString("boolean"), "true");
        assertTrue(msg.getObject("boolean") instanceof Boolean);
        assertTrue(((Boolean) msg.getObject("boolean")).booleanValue());

        msg.setBoolean("boolean", false);
        assertFalse(msg.getBoolean("boolean"));

        msg.setObject("boolean", Boolean.FALSE);
        assertFalse(msg.getBoolean("boolean"));

        try {
            msg.getChar("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getLong("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("boolean");
            fail();
        } catch (MessageFormatException ex) {
        }

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("boolean"));
        assertFalse(msg1.getBoolean("boolean"));
        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testByte() throws JMSException {

        msg.setByte("byte", (byte) 127);
        assertTrue(msg.itemExists("byte"));
        assertEquals(msg.getByte("byte"), (byte) 127);
        assertEquals(msg.getShort("byte"), (short) 127);
        assertEquals(msg.getInt("byte"), 127);
        assertEquals(msg.getLong("byte"), 127L);
        assertEquals(msg.getString("byte"), Byte.valueOf("127").toString());
        assertTrue(msg.getObject("byte") instanceof Byte);
        assertEquals(((Byte) msg.getObject("byte")).byteValue(), (byte) 127);

        msg.setObject("byte", new Byte((byte) 126));
        assertEquals(msg.getByte("byte"), (byte) 126);

        try {
            msg.getBoolean("byte");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("byte");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("byte");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("byte");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setByte("byte", (byte) 125);
        assertEquals(msg.getByte("byte"), (byte) 125);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("byte"));
        assertEquals(msg1.getByte("byte"), (byte) 125);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testChar() throws JMSException {

        msg.setChar("char", 'e');
        assertTrue(msg.itemExists("char"));
        assertEquals(msg.getChar("char"), 'e');
        assertTrue(msg.getObject("char") instanceof Character);
        assertEquals(((Character) msg.getObject("char")).charValue(), 'e');
        assertEquals(msg.getString("char"), "e");

        msg.setObject("char", new Character('x'));
        assertEquals(msg.getChar("char"), 'x');

        try {
            msg.getBoolean("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getLong("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("char");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("char");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setChar("char", 'g');
        assertEquals(msg.getChar("char"), 'g');

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("char"));
        assertEquals(msg1.getChar("char"), 'g');

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testShort() throws JMSException {

        msg.setShort("short", (short) 29000);
        assertTrue(msg.itemExists("short"));
        assertEquals(msg.getShort("short"), (short) 29000);
        assertEquals(msg.getInt("short"), 29000);
        assertEquals(msg.getLong("short"), 29000L);
        assertEquals(msg.getString("short"), Short.valueOf("29000").toString());
        assertTrue(msg.getObject("short") instanceof Short);
        assertEquals(
            ((Short) msg.getObject("short")).shortValue(),
            (short) 29000);

        msg.setObject("short", new Short((short) 29001));
        assertTrue(msg.getObject("short") instanceof Short);
        assertEquals(
            ((Short) msg.getObject("short")).shortValue(),
            (short) 29001);

        try {
            msg.getBoolean("short");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("short");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("short");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("short");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("short");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setShort("short", (short) 29002);
        assertEquals(msg.getShort("short"), (short) 29002);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("short"));
        assertEquals(msg1.getShort("short"), (short) 29002);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testInt() throws JMSException {

        msg.setInt("int", 120000);
        assertTrue(msg.itemExists("int"));
        assertEquals(msg.getInt("int"), 120000);
        assertEquals(msg.getLong("int"), 120000L);
        assertEquals(
            msg.getString("int"),
            Integer.valueOf("120000").toString());
        assertTrue(msg.getObject("int") instanceof Integer);
        assertEquals(((Integer) msg.getObject("int")).intValue(), 120000);

        msg.setObject("int", new Integer(120001));
        assertTrue(msg.getObject("int") instanceof Integer);
        assertEquals(((Integer) msg.getObject("int")).intValue(), 120001);

        try {
            msg.getBoolean("int");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("int");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("int");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("int");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("int");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("int");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setInt("int", 240000);
        assertEquals(msg.getInt("int"), 240000);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("int"));
        assertEquals(msg1.getInt("int"), 240000);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testLong() throws JMSException {

        msg.setLong("long", 222200002222L);
        assertTrue(msg.itemExists("long"));
        assertEquals(msg.getLong("long"), 222200002222L);
        assertEquals(
            msg.getString("long"),
            Long.valueOf("222200002222").toString());
        assertTrue(msg.getObject("long") instanceof Long);
        assertEquals(((Long) msg.getObject("long")).longValue(), 222200002222L);

        msg.setObject("long", new Long(222299992222L));
        assertTrue(msg.getObject("long") instanceof Long);
        assertEquals(((Long) msg.getObject("long")).longValue(), 222299992222L);

        try {
            msg.getBoolean("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("long");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("long");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setLong("long", 222288882222L);
        assertEquals(msg.getLong("long"), 222288882222L);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("long"));
        assertEquals(msg1.getLong("long"), 222288882222L);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testFloat() throws JMSException {

        msg.setFloat("float", (float) 1678.1234);
        assertTrue(msg.itemExists("float"));
        assertEquals(msg.getFloat("float"), (float) 1678.1234, (float) 0.0001);
        assertEquals(msg.getDouble("float"), 1678.1234, 0.0001);
        assertEquals(
            msg.getString("float"),
            Float.valueOf("1678.1234").toString());
        assertTrue(msg.getObject("float") instanceof Float);
        assertEquals(
            ((Float) msg.getObject("float")).floatValue(),
            (float) 1678.1234,
            (float) 0.0001);

        msg.setObject("float", new Float((float) 1778.1234));
        assertTrue(msg.getObject("float") instanceof Float);
        assertEquals(
            ((Float) msg.getObject("float")).floatValue(),
            (float) 1778.1234,
            (float) 0.0001);

        try {
            msg.getBoolean("float");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("float");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("float");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("float");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("float");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getLong("float");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setFloat("float", (float) 1677.1004);
        assertEquals(msg.getFloat("float"), (float) 1677.1004, (float) 0.0001);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("float"));
        assertEquals(msg1.getFloat("float"), (float) 1677.1004, (float) 0.0001);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testDouble() throws JMSException {

        msg.setDouble("double", 9.989667788E304);
        assertTrue(msg.itemExists("double"));
        assertEquals(msg.getDouble("double"), 9.989667788E304, 0.000000001E304);
        assertEquals(
            msg.getString("double"),
            Double.valueOf("9.989667788E304").toString());
        assertTrue(msg.getObject("double") instanceof Double);
        assertEquals(
            ((Double) msg.getObject("double")).doubleValue(),
            9.989667788E304,
            0.000000001E304);

        msg.setObject("double", new Double(9.911111788E304));
        assertTrue(msg.getObject("double") instanceof Double);
        assertEquals(
            ((Double) msg.getObject("double")).doubleValue(),
            9.911111788E304,
            0.000000001E304);

        try {
            msg.getBoolean("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getLong("double");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("double");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setDouble("double", -8.7654321E-303);
        assertEquals(msg.getDouble("double"), -8.7654321E-303, 0.0000001E-303);

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("double"));
        assertEquals(msg1.getDouble("double"), -8.7654321E-303, 0.0000001E-303);

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    public void testString() throws JMSException {

        msg.setString("string", "123");
        assertTrue(msg.itemExists("string"));
        assertEquals(msg.getString("string"), "123");
        assertEquals(msg.getByte("string"), Byte.valueOf("123").byteValue());
        assertTrue(msg.getObject("string") instanceof String);
        assertEquals(msg.getObject("string").toString(), "123");

        msg.setObject("string", "124");
        assertTrue(msg.getObject("string") instanceof String);
        assertEquals(msg.getObject("string").toString(), "124");

        assertEquals(msg.getShort("string"), Short.valueOf("124").shortValue());

        assertEquals(msg.getInt("string"), Integer.valueOf("124").intValue());

        assertEquals(msg.getLong("string"), Long.valueOf("124").longValue());

        try {
            msg.getChar("string");
            fail();
        } catch (MessageFormatException ex) {
        }
        msg.setString("string", "a");
        try {
            msg.getChar("string");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setString("string", "123.55");
        assertEquals(
            msg.getFloat("string"),
            Float.valueOf("123.55").floatValue(),
            (float) 0.01);
        assertEquals(
            msg.getDouble("string"),
            Double.valueOf("123.55").doubleValue(),
            0.01);

        msg.setString("string", Boolean.valueOf("true").toString());
        assertTrue(msg.getBoolean("string"));

        msg.setInt("string", -5555);
        assertEquals(msg.getInt("string"), -5555);
        assertEquals(msg.getString("string"), Integer.toString(-5555));

        msg.setString("null", null);
        assertNull(msg.getObject("null"));
        assertNull(msg.getString("null"));

        MapMessage msg1 = new MapMessageImpl(msg);
        assertTrue(msg1.itemExists("string"));
        assertEquals(msg1.getString("string"), Integer.toString(-5555));
        assertTrue(msg1.itemExists("null"));
        assertNull(msg1.getString("null"));

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

    private void checkBytes(byte[] source, MapMessage msg, String name)
        throws JMSException {

        assertTrue(msg.itemExists(name));

        Object o = msg.getObject(name);
        byte[] bytesRead = msg.getBytes(name);

        assertNotNull(o);
        assertNotNull(bytesRead);
        assertTrue(o instanceof byte[]);
        assertNotSame(source, o);
        assertNotSame(source, bytesRead);
        assertNotSame(bytesRead, o);
        assertEquals(((byte[]) o).length, source.length);
        assertEquals(bytesRead.length, source.length);

        for (int i = 0; i < source.length; i++) {
            assertEquals(source[i], bytesRead[i]);
            assertEquals(source[i], ((byte[]) o)[i]);
        }
    }

    public void testByteArray() throws JMSException {

        byte[] bytes1 = { 1, 0, 1, 0, 11, 127, -128, 11, 15 };

        msg.setBytes("bytes1", bytes1);
        checkBytes(bytes1, msg, "bytes1");

        msg.setBytes("bytes2", bytes1, 2, 5);
        byte[] bytes2 = { 1, 0, 11, 127, -128 };
        checkBytes(bytes2, msg, "bytes2");

        try {
            msg.getBoolean("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getByte("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getChar("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getShort("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getInt("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getLong("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getFloat("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getDouble("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }
        try {
            msg.getString("bytes1");
            fail();
        } catch (MessageFormatException ex) {
        }

        msg.setBytes("b1", null);
        assertNull(msg.getBytes("b1"));
        assertNull(msg.getObject("b1"));

        try {
            msg.setBytes("b1", null, 0, 1);
            fail();
        } catch (IllegalArgumentException ex) {
        }
        try {
            msg.setBytes("b1", new byte[5], -1, 5);
            fail();
        } catch (IllegalArgumentException ex) {
        }
        try {
            msg.setBytes("b1", new byte[5], 1, -5);
            fail();
        } catch (IllegalArgumentException ex) {
        }
        try {
            msg.setBytes("b1", new byte[5], 2, 5);
            fail();
        } catch (IllegalArgumentException ex) {
        }

        MapMessage msg1 = new MapMessageImpl(msg);

        checkBytes(bytes1, msg1, "bytes1");
        checkBytes(bytes2, msg1, "bytes2");
        assertTrue(msg1.itemExists("b1"));
        assertNull(msg1.getBytes("b1"));
        assertNull(msg1.getObject("b1"));

        checkMessageAttributes(msg1);
        checkMessageAttributes();
        assertTrue(MessageUtility.compare(msg, msg1));
    }

}