package com.mobify.astro.messaging;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;

import java.util.ArrayList;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MessageTest {

    private Message message;
    private JSONObject messageJson;

    @Before
    public void setup() throws Exception {
        message = new Message();
        messageJson = new JSONObject("{\"header\": \"test header\", \"payload\": {\"key\": \"value\"}}");
    }

    @Test
    public void testHasHeader() {
        message.setHeader("foo", "foo");

        assertTrue(message.hasHeader("foo"));
        assertFalse(message.hasHeader("bar"));
    }

    @Test
    public void testEscapesJSONDoubleQuotes() throws JSONException {
        JSONObject payload = new JSONObject("{\"doubleQuotes\": \"\\\"\\\"\"}");
        message.setPayload(payload);

        String jsonEscapedString = message.toEscapedJSONString();

        String expectedJSONString = "{\\\"payload\\\":{\\\"doubleQuotes\\\":\\\"\\\\\"\\\\\"\\\"}}";

        assertEquals(expectedJSONString, jsonEscapedString);
    }

    @Test
    public void testEscapesJSONSingleQuotes() throws JSONException {
        JSONObject payload = new JSONObject("{\"singleQuotes\": \"\'\'\"}");
        message.setPayload(payload);

        String jsonEscapedString = message.toEscapedJSONString();

        String expectedJSONString = "{\\\"payload\\\":{\\\"singleQuotes\\\":\\\"\\\'\\\'\\\"}}";

        assertEquals(expectedJSONString, jsonEscapedString);
    }

    @Test
    public void testSetPayloadFromJSON() throws JSONException {
        message.setPayloadFromJSON(messageJson);

        JSONAssert.assertEquals(messageJson.getJSONObject("payload"), message.getPayload(), true);
    }

    @Test
    public void testSetHeadersFromJSON() throws JSONException {
        message.setHeadersFromJSON(messageJson);

        assertEquals(messageJson.getString("header"), message.getHeader("header"));
    }

    @Test
    public void testSetPayloadFromJSONCatchesJSONException() throws JSONException {
        // Force a JSONException to be thrown
        JSONObject mockData = mock(JSONObject.class);
        when(mockData.getJSONObject("payload")).thenThrow(new JSONException(""));

        // Should catch the JSONException
        message.setPayloadFromJSON(mockData);
    }

    @Test
    public void testSetHeadersCatchesJSONException() throws JSONException {
        JSONObject mockData = mock(JSONObject.class);

        ArrayList<String> headers = new ArrayList<String>();
        headers.add("header");
        when(mockData.keys()).thenReturn(headers.iterator());

        // Force a JSONException to be thrown
        when(mockData.getString("header")).thenThrow(new JSONException(""));

        // Should catch the JSONException
        message.setHeadersFromJSON(mockData);
    }

    @Test
    public void testToJSONThrowsHeaderSerializationException() {
        message.setHeader(null, "foo");
        try {
            message.toJSON();
            fail();
        } catch (Exceptions.HeaderSerializationException e) {
            assertEquals(Exceptions.HeaderSerializationException.class, e.getClass());
        }
    }

    @Test
    public void testToStringThrowsSerializationException() {
        message.setHeader(null, "foo");
        try {
            message.toString();
            fail();
        } catch (Exceptions.SerializationException e) {
            assertEquals(Exceptions.SerializationException.class, e.getClass());
        }
    }
}
