package org.skyscreamer.nevado.jms.message;

import org.activemq.message.ActiveMQObjectMessage;
import org.junit.Assert;
import org.junit.Test;
import org.skyscreamer.nevado.jms.AbstractJMSTest;
import org.skyscreamer.nevado.jms.util.RandomData;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import java.io.Serializable;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: Carter Page
 * Date: 3/25/12
 * Time: 11:26 AM
 */
public class ObjectMessageTest extends AbstractJMSTest {
    @Test
    public void testObjectMessage() throws JMSException {
        ObjectMessage msg = createSession().createObjectMessage();
        testObjectMessage(msg);
    }

    @Test
    public void testAlienObjectMessage() throws JMSException {
        ObjectMessage msg = new ActiveMQObjectMessage();
        testObjectMessage(msg);
    }

    private void testObjectMessage(ObjectMessage msg) throws JMSException {
        TestObject testObject = new TestObject();
        msg.setObject(testObject);
        Message msgOut = sendAndReceive(msg);
        Assert.assertTrue("Should be an object message", msgOut instanceof ObjectMessage);
        Assert.assertEquals("Object should be equal", testObject, ((ObjectMessage)msgOut).getObject());
    }

    @Test
    public void testObjectMessage2() throws JMSException {
        TestObject testObject = new TestObject();
        ObjectMessage msg = createSession().createObjectMessage(testObject);
        Message msgOut = sendAndReceive(msg);
        Assert.assertTrue("Should be an object message", msgOut instanceof ObjectMessage);
        Assert.assertEquals("Object should be equal", testObject, ((ObjectMessage)msgOut).getObject());
    }

    @Test
    public void testBadObjectMessage() throws JMSException {
        TestObject testObject = new TestObject();
        ObjectMessage msg = createSession().createObjectMessage();
        msg.setObject(testObject);
        Message msgOut = sendAndReceive(msg);
        Assert.assertTrue("Should be an object message", msgOut instanceof ObjectMessage);
        // To be paranoid, let's check pulling something out and see that it fails
        ((Map)testObject._map.get("c")).remove("d");
        Assert.assertFalse("Object should be equal", testObject.equals(((ObjectMessage)msgOut).getObject()));
    }

    private static class TestObject implements Serializable {
        private final String _string = UUID.randomUUID().toString();
        private final int _int = (new Random()).nextInt();
        private final Map<String, Object> _map = new HashMap<String, Object>();
        private final List<Object> _list = new ArrayList<Object>();

        private TestObject() {
            _map.put("a", RandomData.readString());
            _map.put("b", RandomData.readString());
            Map<String, Object> subMap = new HashMap<String, Object>();
            subMap.put("d", RandomData.readString());
            subMap.put("e", RandomData.readString());
            _map.put("c", subMap);
            
            _list.add(RandomData.readString());
            _list.add(RandomData.readInt());
            List<Object> subList = new ArrayList<Object>();
            subList.add(RandomData.readInt());
            subList.add(RandomData.readString());
            _list.add(subList);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            TestObject that = (TestObject) o;

            if (_int != that._int) return false;
            if (!_list.equals(that._list)) return false;
            if (!_map.equals(that._map)) return false;
            if (_string != null ? !_string.equals(that._string) : that._string != null) return false;

            return true;
        }
    }
}

@@ -320,32 +320,61 @@
 s.ObjectMessage;
+%0A%0Aimport java.io.IOException;
 %0Aimport java.io.
@@ -1016,32 +1016,37 @@
  new TestObject(
+false
 );%0A        msg.s
@@ -1423,32 +1423,37 @@
  new TestObject(
+false
 );%0A        Objec
@@ -1754,32 +1754,687 @@
 Object());%0A    %7D
+%0A    %0A    @Test%0A    public void testObjectMessageTransientRef() throws JMSException %7B%0A        TestObject testObject = new TestObject(true);%0A        ObjectMessage msg = createSession().createObjectMessage(testObject);%0A        Message msgOut = sendAndReceive(msg);%0A        Assert.assertTrue(%22Should be an object message%22, msgOut instanceof ObjectMessage);%0A        Assert.assertEquals(%22Object should be equal%22, testObject, ((ObjectMessage)msgOut).getObject());%0A        Assert.assertEquals(%22testTransientRef Object should exist%22, %0A        %09%09%09%09testObject.testTransientRef, %0A        %09%09%09%09((TestObject)((ObjectMessage)msgOut).getObject()).testTransientRef);%0A    %7D
 %0A%0A    @Test%0A    
@@ -2537,16 +2537,21 @@
 tObject(
+false
 );%0A     
@@ -3374,16 +3374,78 @@
 ject%3E();
+%0A        private transient TestObject testTransientRef = null;
 %0A%0A      
@@ -3465,16 +3465,43 @@
 tObject(
+boolean includeTransientRef
 ) %7B%0A    
@@ -4106,24 +4106,168 @@
 d(subList);%0A
+            %0A            if (includeTransientRef) %7B%0A            %09testTransientRef = new TestObject(false); // avoid circular loop%0A            %7D%0A
         %7D%0A%0A 
@@ -4779,20 +4779,434 @@
 ;%0A        %7D%0A
+        %0A        private void writeObject(java.io.ObjectOutputStream out) throws IOException %7B%0A            out.defaultWriteObject();%0A            out.writeObject(testTransientRef);%0A        %7D%0A    %0A        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException %7B%0A            in.defaultReadObject();%0A            this.testTransientRef = (TestObject) in.readObject();%0A        %7D%0A
     %7D%0A%7D%0A

test for transient reference on serialization