package org.springframework.data.simpledb.util.marshaller;

import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class JsonMarshallerTest {

    private JsonMarshaller cut;

    @Before
    public void setUp() {
        cut = new JsonMarshaller();
    }

    @Test
    public void unmarshal_should_properly_unmarshal_a_json_string_into_the_target_class_instance() throws IOException {

        // Prepare
        String userJsonString = new String(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(
                "org/springframework/data/simpledb/util/marshaller/user.json")));
        assertNotNull(userJsonString);

        // Exercise
        User expectedUser = cut.unmarshal(userJsonString, User.class);

        // Verify
        assertNotNull(expectedUser);
        assertEquals(User.Gender.MALE, expectedUser.getGender());
        assertEquals("Joe", expectedUser.getName().getFirst());
        assertEquals("Sixpack", expectedUser.getName().getLast());
        assertNotNull(expectedUser.getUserImage());
    }

    @Test
    public void unmarshal_should_unmarshal_a_json_string_without_knowing_the_target_class_type() throws IOException {

        // Prepare
        String userJsonString = new String(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream(
                "org/springframework/data/simpledb/util/marshaller/user_with_classinfo.json")));
        assertNotNull(userJsonString);

        // Exercise
        User returnedUser = (User) cut.unmarshal(userJsonString);

        // Verify
        assertNotNull(returnedUser);
        assertEquals(User.Gender.MALE, returnedUser.getGender());
        assertEquals("Joe", returnedUser.getName().getFirst());
        assertEquals("Sixpack", returnedUser.getName().getLast());
        assertNotNull(returnedUser.getUserImage());
    }

    @Test
    public void marshal_should_marshal_Object() throws IOException {

        // Prepare
        User newUser = new User();
        newUser.setName(new User.Name());
        newUser.getName().setFirst("Joe");
        newUser.getName().setLast("Sixpack");
        Object object = newUser;

        // Exercise
        String marshalledUser = cut.marshal(object);
        User returnedUser = (User) cut.unmarshal(marshalledUser);

        // Verify
        assertNotNull(returnedUser);
        assertEquals(newUser.getName().getFirst(), returnedUser.getName().getFirst());
        assertEquals(newUser.getName().getLast(), returnedUser.getName().getLast());
    }

}

class User {
    public enum Gender {MALE}

    public static class Name {
        private String _first;

        private String _last;

        public String getFirst() {
            return _first;
        }

        public String getLast() {
            return _last;
        }

        public void setFirst(String s) {
            _first = s;
        }

        public void setLast(String s) {
            _last = s;
        }
    }

    private Gender _gender;
    private Name _name;
    private boolean _isVerified;
    private byte[] _userImage;

    public Name getName() {
        return _name;
    }

    public Gender getGender() {
        return _gender;
    }

    public byte[] getUserImage() {
        return _userImage;
    }

    public void setName(Name n) {
        _name = n;
    }

    public void setGender(Gender _gender) {
        this._gender = _gender;
    }

    public boolean isVerified() {
        return _isVerified;
    }

    public void setVerified(boolean _isVerified) {
        this._isVerified = _isVerified;
    }

    public void setUserImage(byte[] _userImage) {
        this._userImage = _userImage;
    }
}
@@ -167,16 +167,70 @@
 ception;
+%0Aimport java.util.LinkedHashMap;%0Aimport java.util.Map;
 %0A%0Aimport
@@ -2182,148 +2182,25 @@
 r = 
-new User();%0A        newUser.setName(new User.Name());%0A        newUser.getName().setFirst(%22Joe%22);%0A        newUser.getName().setLast(%22Sixpack%22
+createSampleUser(
 );%0A 
@@ -2599,23 +2599,739 @@
 ast());%0A
-
     %7D%0A%0A
+%0A    @Test%0A    public void should_marshal_unmarshal_maps_of_Strings()%7B%0A        Map%3CString, String%3E map = new LinkedHashMap%3C%3E();%0A        map.put(%22TestKey%22, %22Test Value%22);%0A%0A        String marsahledMap = cut.marshal(map);%0A%0A        Map%3CString, String%3E unmarshaledMap = (Map%3CString, String%3E)cut.unmarshal(marsahledMap);%0A%0A        assertEquals(map.keySet(), unmarshaledMap.keySet());%0A%0A        String ret = unmarshaledMap.get(%22TestKey%22);%0A        assertEquals(%22Test Value%22, ret);%0A%0A    %7D%0A%0A%0A    private User createSampleUser() %7B%0A        User newUser = new User();%0A        newUser.setName(new User.Name());%0A        newUser.getName().setFirst(%22Joe%22);%0A        newUser.getName().setLast(%22Sixpack%22);%0A        return newUser;%0A    %7D%0A%0A%0A
 %7D%0A%0Aclass

add test to reflect supported Maps