freemarker.ext.dump.DumpDirectiveTest.java Source code

Java tutorial

Introduction

Here is the source code for freemarker.ext.dump.DumpDirectiveTest.java

Source

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package freemarker.ext.dump;

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

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;

import freemarker.core.CollectionAndSequence;
import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.CollectionModel;
import freemarker.ext.dump.BaseDumpDirective.DateType;
import freemarker.ext.dump.BaseDumpDirective.Key;
import freemarker.ext.dump.BaseDumpDirective.Type;
import freemarker.ext.dump.BaseDumpDirective.Value;
import freemarker.template.Configuration;
import freemarker.template.SimpleCollection;
import freemarker.template.Template;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

/**
 * Unit tests of dump directive. The tests follow the same basic pattern:
 * 1. Create the data model
 * 2. Create the expected dump data structure
 * 3. Create the actual dump data structure by running the data model through a processing environment
 * 4. Compare expected and actual dump data structures
 * 
 * @author rjy7
 *
 */
public class DumpDirectiveTest {

    private Template template;

    @Before
    public void setUp() {
        Configuration config = new Configuration();
        String templateStr = "";
        try {
            template = new Template("template", new StringReader(templateStr), config);
        } catch (Exception e) {
            fail(e.getMessage());
        }
        // Turn off log messages to console
        Logger.getLogger(BaseDumpDirective.class).setLevel(Level.OFF);
    }

    @Test
    public void dumpUndefinedValue() {

        String varName = "dog";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.VALUE.toString(), Value.UNDEFINED.toString());

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpString() {

        String varName = "dog";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        String value = "Rover";
        dataModel.put(varName, value);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.STRING);
        expectedDumpValue.put(Key.VALUE.toString(), value);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpBoolean() {

        String varName = "isLoggedIn";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        boolean value = true;
        dataModel.put(varName, value);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.BOOLEAN);
        expectedDumpValue.put(Key.VALUE.toString(), value);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpNumber() {

        String varName = "tabCount";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        int value = 7;
        dataModel.put(varName, value);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.NUMBER);
        expectedDumpValue.put(Key.VALUE.toString(), value);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpSimpleDate() {

        String varName = "now";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Date now = new Date();
        dataModel.put(varName, now);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DATE);
        expectedDumpValue.put(Key.DATE_TYPE.toString(), DateType.UNKNOWN);
        expectedDumpValue.put(Key.VALUE.toString(), now);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpCalendarDate() {

        String varName = "myDate";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Calendar c = Calendar.getInstance();
        c.set(1991, Calendar.MAY, 5);
        Date myDate = c.getTime();
        dataModel.put("myDate", myDate);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DATE);
        expectedDumpValue.put(Key.DATE_TYPE.toString(), DateType.UNKNOWN);
        expectedDumpValue.put(Key.VALUE.toString(), myDate);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpDateTime() {

        String varName = "timestamp";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Timestamp ts = new Timestamp(1302297332043L);
        dataModel.put(varName, ts);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DATE);
        expectedDumpValue.put(Key.DATE_TYPE.toString(), DateType.DATETIME);
        expectedDumpValue.put(Key.VALUE.toString(), ts);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpSqlDate() {

        String varName = "date";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        java.sql.Date date = new java.sql.Date(1302297332043L);
        dataModel.put(varName, date);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DATE);
        expectedDumpValue.put(Key.DATE_TYPE.toString(), DateType.DATE);
        expectedDumpValue.put(Key.VALUE.toString(), date);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpTime() {

        String varName = "time";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Time time = new Time(1302297332043L);
        dataModel.put(varName, time);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DATE);
        expectedDumpValue.put(Key.DATE_TYPE.toString(), DateType.TIME);
        expectedDumpValue.put(Key.VALUE.toString(), time);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpHelplessMethod() {

        String varName = "square";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateMethodModel methodModel = new HelplessMethod();
        dataModel.put(varName, methodModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.METHOD);
        expectedDumpValue.put(Key.CLASS.toString(), methodModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), null);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpHelpfulMethod() {

        String varName = "square";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateMethodModel methodModel = new HelpfulMethod();
        dataModel.put(varName, methodModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.METHOD);
        expectedDumpValue.put(Key.CLASS.toString(), methodModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), getMethodHelp(varName));

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpMethodWithStringHelp() {

        String varName = "square";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateMethodModel methodModel = new MethodWithStringHelp();
        dataModel.put(varName, methodModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.METHOD);
        expectedDumpValue.put(Key.CLASS.toString(), methodModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), null);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpMethodWithStringStringMapHelp() {

        String varName = "square";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateMethodModel methodModel = new MethodWithStringStringMapHelp();
        dataModel.put(varName, methodModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.METHOD);
        expectedDumpValue.put(Key.CLASS.toString(), methodModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), new HashMap<String, Object>());

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpHelplessDirective() {

        String varName = "dump";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateDirectiveModel directiveModel = new HelplessDirective();
        dataModel.put(varName, directiveModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DIRECTIVE);
        expectedDumpValue.put(Key.CLASS.toString(), directiveModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), null);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpHelpfulDirective() {

        String varName = "dump";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateDirectiveModel directiveModel = new HelpfulDirective();
        dataModel.put(varName, directiveModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DIRECTIVE);
        expectedDumpValue.put(Key.CLASS.toString(), directiveModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), getDirectiveHelp(varName));

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpDirectiveWithStringHelp() {

        String varName = "dump";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateDirectiveModel directiveModel = new DirectiveWithStringHelp();
        dataModel.put(varName, directiveModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DIRECTIVE);
        expectedDumpValue.put(Key.CLASS.toString(), directiveModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), null);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpDirectiveWithStringStringMapHelp() {

        String varName = "dump";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        TemplateDirectiveModel directiveModel = new DirectiveWithStringStringMapHelp();
        dataModel.put(varName, directiveModel);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.DIRECTIVE);
        expectedDumpValue.put(Key.CLASS.toString(), directiveModel.getClass().getName());
        expectedDumpValue.put(Key.HELP.toString(), new HashMap<String, Object>());

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpStringList() {

        String varName = "fruit";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        List<String> myList = new ArrayList<String>();
        myList.add("apples");
        myList.add("bananas");
        myList.add("oranges");
        dataModel.put(varName, myList);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myListItemsExpectedDump = new ArrayList<Map<String, Object>>(myList.size());
        for (String str : myList) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), str);
            myListItemsExpectedDump.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myListItemsExpectedDump);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpStringArray() {

        String varName = "fruit";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        String[] myArray = { "apples", "bananas", "oranges" };
        dataModel.put(varName, myArray);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myArrayExpectedDumpValue = new ArrayList<Map<String, Object>>(myArray.length);
        for (String str : myArray) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), str);
            myArrayExpectedDumpValue.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myArrayExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpMixedList() {

        String varName = "stuff";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        List<Object> mixedList = new ArrayList<Object>();

        String myString = "apples";
        mixedList.add(myString);

        int myInt = 4;
        mixedList.add(myInt);

        boolean myBool = true;
        mixedList.add(myBool);

        List<String> myList = new ArrayList<String>();
        myList.add("dog");
        myList.add("cat");
        myList.add("elephant");
        mixedList.add(myList);

        dataModel.put(varName, mixedList);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);

        List<Map<String, Object>> mixedListExpectedDumpValue = new ArrayList<Map<String, Object>>(mixedList.size());

        Map<String, Object> myStringExpectedDumpValue = new HashMap<String, Object>();
        myStringExpectedDumpValue.put(Key.TYPE.toString(), Type.STRING);
        myStringExpectedDumpValue.put(Key.VALUE.toString(), myString);
        mixedListExpectedDumpValue.add(myStringExpectedDumpValue);

        Map<String, Object> myIntExpectedDumpValue = new HashMap<String, Object>();
        myIntExpectedDumpValue.put(Key.TYPE.toString(), Type.NUMBER);
        myIntExpectedDumpValue.put(Key.VALUE.toString(), myInt);
        mixedListExpectedDumpValue.add(myIntExpectedDumpValue);

        Map<String, Object> myBoolExpectedDumpValue = new HashMap<String, Object>();
        myBoolExpectedDumpValue.put(Key.TYPE.toString(), Type.BOOLEAN);
        myBoolExpectedDumpValue.put(Key.VALUE.toString(), myBool);
        mixedListExpectedDumpValue.add(myBoolExpectedDumpValue);

        Map<String, Object> myListExpectedDumpValue = new HashMap<String, Object>();
        myListExpectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myListItemsExpectedDumpValue = new ArrayList<Map<String, Object>>(myList.size());
        for (String animal : myList) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), animal);
            myListItemsExpectedDumpValue.add(itemDump);
        }
        myListExpectedDumpValue.put(Key.VALUE.toString(), myListItemsExpectedDumpValue);
        mixedListExpectedDumpValue.add(myListExpectedDumpValue);

        expectedDumpValue.put(Key.VALUE.toString(), mixedListExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpNumberSet() {

        String varName = "oddNums";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Set<Integer> myIntSet = new HashSet<Integer>();
        for (int i = 0; i <= 10; i++) {
            if (i % 2 == 1) {
                myIntSet.add(i);
            }
        }
        dataModel.put(varName, myIntSet);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myIntSetExpectedDumpValue = new ArrayList<Map<String, Object>>(myIntSet.size());
        for (int i : myIntSet) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.NUMBER);
            itemDump.put(Key.VALUE.toString(), i);
            myIntSetExpectedDumpValue.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myIntSetExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpSimpleCollection() {

        String varName = "oddNums";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Set<Integer> odds = new HashSet<Integer>();
        for (int i = 0; i <= 10; i++) {
            if (i % 2 == 1) {
                odds.add(i);
            }
        }
        TemplateCollectionModel myCollection = new SimpleCollection(odds);
        dataModel.put(varName, myCollection);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.COLLECTION);
        List<Map<String, Object>> myCollectionExpectedDumpValue = new ArrayList<Map<String, Object>>(odds.size());
        for (int i : odds) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.NUMBER);
            itemDump.put(Key.VALUE.toString(), i);
            myCollectionExpectedDumpValue.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myCollectionExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpCollectionModel() {

        String varName = "oddNums";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Set<Integer> odds = new HashSet<Integer>();
        for (int i = 0; i <= 10; i++) {
            if (i % 2 == 1) {
                odds.add(i);
            }
        }
        TemplateCollectionModel myCollection = new CollectionModel(odds, new BeansWrapper());
        dataModel.put(varName, myCollection);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.COLLECTION);
        List<Map<String, Object>> myCollectionExpectedDumpValue = new ArrayList<Map<String, Object>>(odds.size());
        for (int i : odds) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.NUMBER);
            itemDump.put(Key.VALUE.toString(), i);
            myCollectionExpectedDumpValue.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myCollectionExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpCollectionAndSequenceModel() {

        String varName = "oddNums";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Set<Integer> odds = new HashSet<Integer>();
        for (int i = 0; i <= 10; i++) {
            if (i % 2 == 1) {
                odds.add(i);
            }
        }
        TemplateCollectionModel coll = new CollectionModel(odds, new BeansWrapper());
        TemplateCollectionModel myCollection = new CollectionAndSequence(coll);
        dataModel.put(varName, myCollection);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myCollectionExpectedDumpValue = new ArrayList<Map<String, Object>>(odds.size());
        for (int i : odds) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.NUMBER);
            itemDump.put(Key.VALUE.toString(), i);
            myCollectionExpectedDumpValue.add(itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), myCollectionExpectedDumpValue);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        test(varName, dataModel, expectedDump);
    }

    @Test
    public void dumpStringToStringMap() {

        String varName = "capitals";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Map<String, String> myMap = new HashMap<String, String>();
        myMap.put("Albany", "New York");
        myMap.put("St. Paul", "Minnesota");
        myMap.put("Austin", "Texas");
        myMap.put("Sacramento", "California");
        myMap.put("Richmond", "Virginia");
        dataModel.put(varName, myMap);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.HASH_EX);
        SortedMap<String, Object> myMapExpectedDump = new TreeMap<String, Object>();

        for (String key : myMap.keySet()) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), myMap.get(key));
            myMapExpectedDump.put(key, itemDump);
        }
        expectedDumpValue.put(Key.VALUE.toString(), (myMapExpectedDump));

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        Map<String, Object> dump = getDump(varName, dataModel);
        assertEquals(expectedDump, dump);

        // Test the sorting of the map
        List<String> expectedKeys = new ArrayList<String>(myMapExpectedDump.keySet());
        @SuppressWarnings("unchecked")
        Map<String, Object> actualDumpValue = (Map<String, Object>) dump.get(varName);
        @SuppressWarnings("unchecked")
        SortedMap<String, Object> myMapActualDump = (SortedMap<String, Object>) actualDumpValue
                .get(Key.VALUE.toString());
        List<String> actualKeys = new ArrayList<String>(myMapActualDump.keySet());
        assertEquals(expectedKeys, actualKeys);
    }

    @Test
    public void dumpStringToObjectMap() {

        String varName = "stuff";
        Map<String, Object> dataModel = new HashMap<String, Object>();

        Map<String, Object> mixedMap = new HashMap<String, Object>();

        String myString = "apples";
        mixedMap.put("myString", myString);

        boolean myBool = true;
        mixedMap.put("myBoolean", myBool);

        int myInt = 4;
        mixedMap.put("myNumber", myInt);

        Date myDate = new Date();
        mixedMap.put("myDate", myDate);

        List<String> myList = new ArrayList<String>();
        myList.add("apples");
        myList.add("bananas");
        myList.add("oranges");
        mixedMap.put("myList", myList);

        Map<String, String> myMap = new HashMap<String, String>();
        myMap.put("Great Expectations", "Charles Dickens");
        myMap.put("Pride and Prejudice", "Jane Austen");
        myMap.put("Middlemarch", "George Eliot");
        myMap.put("Jude the Obscure", "Thomas Hardy");
        mixedMap.put("myMap", myMap);

        dataModel.put(varName, mixedMap);

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), Type.HASH_EX);
        SortedMap<String, Object> mixedMapExpectedDump = new TreeMap<String, Object>();

        Map<String, Object> myStringExpectedDump = new HashMap<String, Object>();
        myStringExpectedDump.put(Key.TYPE.toString(), Type.STRING);
        myStringExpectedDump.put(Key.VALUE.toString(), myString);
        mixedMapExpectedDump.put("myString", myStringExpectedDump);

        Map<String, Object> myBooleanExpectedDump = new HashMap<String, Object>();
        myBooleanExpectedDump.put(Key.TYPE.toString(), Type.BOOLEAN);
        myBooleanExpectedDump.put(Key.VALUE.toString(), myBool);
        mixedMapExpectedDump.put("myBoolean", myBooleanExpectedDump);

        Map<String, Object> myIntExpectedDump = new HashMap<String, Object>();
        myIntExpectedDump.put(Key.TYPE.toString(), Type.NUMBER);
        myIntExpectedDump.put(Key.VALUE.toString(), myInt);
        mixedMapExpectedDump.put("myNumber", myIntExpectedDump);

        Map<String, Object> myDateExpectedDump = new HashMap<String, Object>();
        myDateExpectedDump.put(Key.TYPE.toString(), Type.DATE);
        myDateExpectedDump.put(Key.DATE_TYPE.toString(), DateType.UNKNOWN);
        myDateExpectedDump.put(Key.VALUE.toString(), myDate);
        mixedMapExpectedDump.put("myDate", myDateExpectedDump);

        Map<String, Object> myListExpectedDump = new HashMap<String, Object>();
        myListExpectedDump.put(Key.TYPE.toString(), Type.SEQUENCE);
        List<Map<String, Object>> myListItemsExpectedDump = new ArrayList<Map<String, Object>>(myList.size());
        for (String item : myList) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), item);
            myListItemsExpectedDump.add(itemDump);
        }
        myListExpectedDump.put(Key.VALUE.toString(), myListItemsExpectedDump);
        mixedMapExpectedDump.put("myList", myListExpectedDump);

        Map<String, Object> myMapExpectedDump = new HashMap<String, Object>();
        myMapExpectedDump.put(Key.TYPE.toString(), Type.HASH_EX);
        SortedMap<String, Object> myMapItemsExpectedDump = new TreeMap<String, Object>();
        for (String key : myMap.keySet()) {
            Map<String, Object> itemDump = new HashMap<String, Object>();
            itemDump.put(Key.TYPE.toString(), Type.STRING);
            itemDump.put(Key.VALUE.toString(), myMap.get(key));
            myMapItemsExpectedDump.put(key, itemDump);
        }
        myMapExpectedDump.put(Key.VALUE.toString(), myMapItemsExpectedDump);
        mixedMapExpectedDump.put("myMap", myMapExpectedDump);

        expectedDumpValue.put(Key.VALUE.toString(), mixedMapExpectedDump);

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        Map<String, Object> dump = getDump(varName, dataModel);
        assertEquals(expectedDump, dump);

        // Test the sorting of the outer map        
        List<String> expectedDumpValueKeys = new ArrayList<String>(mixedMapExpectedDump.keySet());
        @SuppressWarnings("unchecked")
        Map<String, Object> actualDumpValue = (Map<String, Object>) dump.get(varName);
        @SuppressWarnings("unchecked")
        SortedMap<String, Object> mixedMapActualDump = (SortedMap<String, Object>) actualDumpValue
                .get(Key.VALUE.toString());
        List<String> actualDumpValueKeys = new ArrayList<String>(mixedMapActualDump.keySet());
        assertEquals(expectedDumpValueKeys, actualDumpValueKeys);

        // Test the sorting of the inner map
        List<String> myMapItemsExpectedDumpKeys = new ArrayList<String>(myMapItemsExpectedDump.keySet());
        @SuppressWarnings("unchecked")
        Map<String, Object> myMapActualDump = (Map<String, Object>) mixedMapActualDump.get("myMap");
        @SuppressWarnings("unchecked")
        SortedMap<String, Object> myMapItemsActualDump = (SortedMap<String, Object>) myMapActualDump
                .get(Key.VALUE.toString());
        List<String> myMapItemsActualDumpKeys = new ArrayList<String>(myMapItemsActualDump.keySet());
        assertEquals(myMapItemsExpectedDumpKeys, myMapItemsActualDumpKeys);

    }

    @Test
    public void dumpObjectWithExposeNothingWrapper() {
        dumpObject(BeansWrapper.EXPOSE_NOTHING);
    }

    @Test
    public void dumpObjectWithExposePropertiesOnlyWrapper() {
        dumpObject(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
    }

    @Test
    public void dumpObjectWithExposeSafeWrapper() {
        dumpObject(BeansWrapper.EXPOSE_SAFE);
    }

    @Test
    public void dumpObjectWithExposeAllWrapper() {
        dumpObject(BeansWrapper.EXPOSE_ALL);
    }

    /////////////////////////// Private test classes and helper methods ///////////////////////////

    private void test(String varName, Map<String, Object> dataModel, Map<String, Object> expectedDump) {
        Map<String, Object> dump = getDump(varName, dataModel);
        assertEquals(expectedDump, dump);
    }

    private void dumpObject(int exposureLevel) {

        String varName = "employee";
        Map<String, Object> dataModel = new HashMap<String, Object>();
        BeansWrapper wrapper = new BeansWrapper();
        wrapper.setExposureLevel(exposureLevel);
        Employee employee = getEmployee();
        try {
            dataModel.put("employee", wrapper.wrap(employee));
        } catch (TemplateModelException e) {
            // logging is suppressed, so what do we do here?
        }

        Map<String, Object> expectedDumpValue = new HashMap<String, Object>();
        expectedDumpValue.put(Key.TYPE.toString(), employee.getClass().getName());
        expectedDumpValue.put(Key.VALUE.toString(), getJohnDoeExpectedDump(exposureLevel));

        Map<String, Object> expectedDump = new HashMap<String, Object>();
        expectedDump.put(varName, expectedDumpValue);

        testObjectDump(varName, dataModel, expectedDump);
    }

    private void testObjectDump(String varName, Map<String, Object> dataModel, Map<String, Object> expectedDump) {

        Map<String, Object> dump = getDump(varName, dataModel);
        assertEquals(expectedDump, dump);

        // Test the sorting of the properties
        @SuppressWarnings("unchecked")
        Map<String, Object> expectedVarDump = (Map<String, Object>) expectedDump.get(varName);
        @SuppressWarnings("unchecked")
        Map<String, Object> expectedValueDump = (Map<String, Object>) expectedVarDump.get(Key.VALUE.toString());
        @SuppressWarnings("unchecked")
        SortedMap<String, Object> expectedPropertyDump = (SortedMap<String, Object>) expectedValueDump
                .get(Key.PROPERTIES.toString());
        List<String> expectedPropertyDumpKeys = new ArrayList<String>(expectedPropertyDump.keySet());

        @SuppressWarnings("unchecked")
        Map<String, Object> actualVarDump = (Map<String, Object>) dump.get(varName);
        @SuppressWarnings("unchecked")
        Map<String, Object> actualValueDump = (Map<String, Object>) actualVarDump.get(Key.VALUE.toString());
        @SuppressWarnings("unchecked")
        SortedMap<String, Object> actualPropertyDump = (SortedMap<String, Object>) actualValueDump
                .get(Key.PROPERTIES.toString());
        List<String> actualPropertyDumpKeys = new ArrayList<String>(actualPropertyDump.keySet());

        assertEquals(expectedPropertyDumpKeys, actualPropertyDumpKeys);

    }

    private Map<String, Object> getDump(String varName, Map<String, Object> dataModel) {
        try {
            Environment env = template.createProcessingEnvironment(dataModel, new StringWriter());
            return new DumpDirective().getTemplateVariableDump(varName, env);
        } catch (Exception e) {
            fail(e.getMessage());
            return null;
        }
    }

    private class HelplessMethod implements TemplateMethodModel {

        @Override
        public Object exec(List arg0) throws TemplateModelException {
            return null;
        }
    }

    private class HelpfulMethod implements TemplateMethodModel {

        @Override
        public Object exec(List arg0) throws TemplateModelException {
            return null;
        }

        public Map<String, Object> help(String name) {
            return getMethodHelp(name);
        }
    }

    private class MethodWithStringHelp implements TemplateMethodModel {

        @Override
        public Object exec(List arg0) throws TemplateModelException {
            return null;
        }

        public String help(String name) {
            return "help";
        }
    }

    private class MethodWithStringStringMapHelp implements TemplateMethodModel {

        @Override
        public Object exec(List arg0) throws TemplateModelException {
            return null;
        }

        public Map<String, String> help(String name) {
            return new HashMap<String, String>();
        }
    }

    private class HelplessDirective implements TemplateDirectiveModel {

        @Override
        public void execute(Environment arg0, Map arg1, TemplateModel[] arg2, TemplateDirectiveBody arg3)
                throws TemplateException, IOException {
        }
    }

    private class HelpfulDirective implements TemplateDirectiveModel {

        @Override
        public void execute(Environment arg0, Map arg1, TemplateModel[] arg2, TemplateDirectiveBody arg3)
                throws TemplateException, IOException {
        }

        public Map<String, Object> help(String name) {
            return getDirectiveHelp(name);
        }
    }

    private class DirectiveWithStringHelp implements TemplateDirectiveModel {

        @Override
        public void execute(Environment arg0, Map arg1, TemplateModel[] arg2, TemplateDirectiveBody arg3)
                throws TemplateException, IOException {
        }

        public String help(String name) {
            return "help";
        }
    }

    private class DirectiveWithStringStringMapHelp implements TemplateDirectiveModel {

        @Override
        public void execute(Environment arg0, Map arg1, TemplateModel[] arg2, TemplateDirectiveBody arg3)
                throws TemplateException, IOException {
        }

        public Map<String, String> help(String name) {
            return new HashMap<String, String>();
        }
    }

    private Map<String, Object> getDirectiveHelp(String name) {
        Map<String, Object> map = new HashMap<String, Object>();

        map.put("effect", "Dump the contents of a template variable.");

        map.put("comments",
                "Sequences (lists and arrays) are enclosed in square brackets. Hashes are enclosed in curly braces.");

        Map<String, String> params = new HashMap<String, String>();
        params.put("var", "name of variable to dump");
        map.put("parameters", params);

        List<String> examples = new ArrayList<String>();
        examples.add("<@" + name + " var=\"urls\" />");
        map.put("examples", examples);

        return map;
    }

    private Map<String, Object> getMethodHelp(String name) {
        Map<String, Object> map = new HashMap<String, Object>();

        map.put("returns", "The square of the argument");

        List<String> params = new ArrayList<String>();
        params.add("Integer to square");
        map.put("parameters", params);

        List<String> examples = new ArrayList<String>();
        examples.add(name + "(4)");
        map.put("examples", examples);

        return map;
    }

    public static class Employee {

        private static int count = 0;

        private String firstName;
        private String lastName;
        private String nickname;
        private Date birthdate;
        private boolean married;
        private int id;
        private String middleName;
        private List<String> favoriteColors;
        // private Map<String, String> degrees;
        private Employee supervisor;
        private float salary;

        Employee(String firstName, String lastName, int id, Date birthdate) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.middleName = null; // test a null value
            this.birthdate = birthdate;
            this.married = true;
            this.id = id;
            this.nickname = "";
            this.favoriteColors = new ArrayList<String>();
            count++;
        }

        protected void setSupervisor(Employee supervisor) {
            this.supervisor = supervisor;
        }

        void setSalary(float salary) {
            this.salary = salary;
        }

        public void setNickname(String nickname) {
            this.nickname = nickname;
        }

        public void setFavoriteColors(String... colors) {
            for (String color : colors) {
                favoriteColors.add(color);
            }
        }

        //        void setDegrees(Map<String, String> degrees) {
        //            this.degrees = degrees;
        //        }

        float getSalary() {
            return salary;
        }

        public static int getEmployeeCount() {
            return count;
        }

        /*  Public accessor methods for templates */

        public String getFullName() {
            return firstName + " " + lastName;
        }

        public String getName(String which) {
            return which == "first" ? firstName : lastName;
        }

        public String getMiddleName() {
            return middleName;
        }

        public String getNickname() {
            return nickname;
        }

        public Date getBirthdate() {
            return birthdate;
        }

        public int getId() {
            return id;
        }

        public boolean isMarried() {
            return married;
        }

        @Deprecated
        public int getFormerId() {
            return id % 10000;
        }

        public Employee getSupervisor() {
            return supervisor;
        }

        public Employee boss() {
            return supervisor;
        }

        public List<String> getFavoriteColors() {
            return favoriteColors;
        }

        //        public Map<String, String> getDegrees() {
        //            return degrees;
        //        }

        public String familyName() {
            return lastName;
        }
    }

    private Employee getEmployee() {

        Calendar c = Calendar.getInstance();
        c.set(1982, Calendar.MAY, 5);
        c = DateUtils.truncate(c, Calendar.DATE);
        Employee jdoe = new Employee("John", "Doe", 34523, c.getTime());
        jdoe.setFavoriteColors("blue", "green");
        jdoe.setSalary(65000);

        //        Map<String, String> degrees = new HashMap<String, String>();
        //        degrees.put("BA", "Mathematics");
        //        degrees.put("MS", "Computer Science");
        //        jdoe.setDegrees(degrees);

        c.clear();
        c.set(1975, Calendar.OCTOBER, 25);
        c = DateUtils.truncate(c, Calendar.DATE);
        Employee jsmith = new Employee("Jane", "Smith", 78234, c.getTime());
        jsmith.setFavoriteColors("red", "orange");

        jdoe.setSupervisor(jsmith);

        return jdoe;
    }

    private Map<String, Object> getJohnDoeExpectedDump(int exposureLevel) {

        Map<String, Object> expectedDump = new HashMap<String, Object>();

        Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
        supervisorExpectedDump.put(Key.TYPE.toString(), "freemarker.ext.dump.DumpDirectiveTest$Employee");
        supervisorExpectedDump.put(Key.VALUE.toString(), getJaneSmithExpectedDump(exposureLevel));

        // Properties
        SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();

        if (exposureLevel < BeansWrapper.EXPOSE_NOTHING) {

            Map<String, Object> birthdateExpectedDump = new HashMap<String, Object>();
            birthdateExpectedDump.put(Key.TYPE.toString(), Type.DATE);
            birthdateExpectedDump.put(Key.DATE_TYPE.toString(), DateType.UNKNOWN);
            Calendar c = Calendar.getInstance();
            c.set(1982, Calendar.MAY, 5);
            c = DateUtils.truncate(c, Calendar.DATE);
            birthdateExpectedDump.put(Key.VALUE.toString(), c.getTime());
            propertiesExpectedDump.put("birthdate", birthdateExpectedDump);

            Map<String, Object> fullNameExpectedDump = new HashMap<String, Object>();
            fullNameExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            fullNameExpectedDump.put(Key.VALUE.toString(), "John Doe");
            propertiesExpectedDump.put("fullName", fullNameExpectedDump);

            Map<String, Object> idExpectedDump = new HashMap<String, Object>();
            idExpectedDump.put(Key.TYPE.toString(), Type.NUMBER);
            idExpectedDump.put(Key.VALUE.toString(), 34523);
            propertiesExpectedDump.put("id", idExpectedDump);

            Map<String, Object> nicknameExpectedDump = new HashMap<String, Object>();
            nicknameExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            nicknameExpectedDump.put(Key.VALUE.toString(), "");
            propertiesExpectedDump.put("nickname", nicknameExpectedDump);

            Map<String, Object> middleNameExpectedDump = new HashMap<String, Object>();
            middleNameExpectedDump.put(Key.VALUE.toString(), Value.NULL.toString());
            propertiesExpectedDump.put("middleName", middleNameExpectedDump);

            Map<String, Object> marriedExpectedDump = new HashMap<String, Object>();
            marriedExpectedDump.put(Key.TYPE.toString(), Type.BOOLEAN);
            marriedExpectedDump.put(Key.VALUE.toString(), true);
            propertiesExpectedDump.put("married", marriedExpectedDump);

            propertiesExpectedDump.put("supervisor", supervisorExpectedDump);

            Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
            favoriteColorsExpectedDump.put(Key.TYPE.toString(), Type.SEQUENCE);
            List<Map<String, Object>> favoriteColorListExpectedDump = new ArrayList<Map<String, Object>>();
            Map<String, Object> color1ExpectedDump = new HashMap<String, Object>();
            color1ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            color1ExpectedDump.put(Key.VALUE.toString(), "blue");
            favoriteColorListExpectedDump.add(color1ExpectedDump);
            Map<String, Object> color2ExpectedDump = new HashMap<String, Object>();
            color2ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            color2ExpectedDump.put(Key.VALUE.toString(), "green");
            favoriteColorListExpectedDump.add(color2ExpectedDump);
            favoriteColorsExpectedDump.put(Key.VALUE.toString(), favoriteColorListExpectedDump);
            propertiesExpectedDump.put("favoriteColors", favoriteColorsExpectedDump);

            // This test fails, don't know why
            //            Map<String, Object> degreesExpectedDump = new HashMap<String, Object>();
            //            degreesExpectedDump.put(Key.TYPE.toString(), Type.HASH);
            //            Map<String, Map<String, Object>> degreeMapExpectedDump = new HashMap<String, Map<String, Object>>();
            //            Map<String, Object> degree1ExpectedDump = new HashMap<String, Object>();
            //            degree1ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            //            degree1ExpectedDump.put(Key.VALUE.toString(), "Mathematics");
            //            degreeMapExpectedDump.put("BA", degree1ExpectedDump);
            //            Map<String, Object> degree2ExpectedDump = new HashMap<String, Object>();
            //            degree2ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            //            degree2ExpectedDump.put(Key.VALUE.toString(), "Computer Science");
            //            degreeMapExpectedDump.put("MS", degree2ExpectedDump);
            //            degreesExpectedDump.put(Key.VALUE.toString(), degreeMapExpectedDump);
            //            propertiesExpectedDump.put("degrees", degreesExpectedDump);

        }

        expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);

        // Methods       
        SortedMap<String, Object> methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Doe");
        if (!methodDump.isEmpty()) {
            methodDump.put("boss()", supervisorExpectedDump);
        }
        expectedDump.put(Key.METHODS.toString(), methodDump);

        return expectedDump;
    }

    private SortedMap<String, Object> getEmployeeMethodsExpectedDump(int exposureLevel, String familyName) {

        SortedMap<String, Object> expectedDump = new TreeMap<String, Object>();

        if (exposureLevel <= BeansWrapper.EXPOSE_SAFE) {

            Map<String, Object> nameExpectedDump = new HashMap<String, Object>();
            nameExpectedDump.put(Key.TYPE.toString(), "String");
            expectedDump.put("getName(String)", nameExpectedDump);

            expectedDump.put("setFavoriteColors(Strings)", Collections.emptyMap());

            expectedDump.put("setNickname(String)", Collections.emptyMap());

            Map<String, Object> familyNameExpectedDump = new HashMap<String, Object>();
            familyNameExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            familyNameExpectedDump.put(Key.VALUE.toString(), familyName);
            expectedDump.put("familyName()", familyNameExpectedDump);

            Map<String, Object> employeeCountExpectedDump = new HashMap<String, Object>();
            employeeCountExpectedDump.put(Key.TYPE.toString(), Type.NUMBER);
            employeeCountExpectedDump.put(Key.VALUE.toString(), Employee.getEmployeeCount());
            expectedDump.put("getEmployeeCount()", employeeCountExpectedDump);
        }

        return expectedDump;
    }

    private Map<String, Object> getJaneSmithExpectedDump(int exposureLevel) {

        Map<String, Object> expectedDump = new HashMap<String, Object>();

        Map<String, Object> supervisorExpectedDump = new HashMap<String, Object>();
        supervisorExpectedDump.put(Key.VALUE.toString(), Value.NULL.toString());

        SortedMap<String, Object> propertiesExpectedDump = new TreeMap<String, Object>();

        // Properties 
        if (exposureLevel < BeansWrapper.EXPOSE_NOTHING) {

            Map<String, Object> birthdateExpectedDump = new HashMap<String, Object>();
            birthdateExpectedDump.put(Key.TYPE.toString(), Type.DATE);
            birthdateExpectedDump.put(Key.DATE_TYPE.toString(), DateType.UNKNOWN);
            Calendar c = Calendar.getInstance();
            c.set(1975, Calendar.OCTOBER, 25);
            c = DateUtils.truncate(c, Calendar.DATE);
            birthdateExpectedDump.put(Key.VALUE.toString(), c.getTime());
            propertiesExpectedDump.put("birthdate", birthdateExpectedDump);

            Map<String, Object> fullNameExpectedDump = new HashMap<String, Object>();
            fullNameExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            fullNameExpectedDump.put(Key.VALUE.toString(), "Jane Smith");
            propertiesExpectedDump.put("fullName", fullNameExpectedDump);

            Map<String, Object> idExpectedDump = new HashMap<String, Object>();
            idExpectedDump.put(Key.TYPE.toString(), Type.NUMBER);
            idExpectedDump.put(Key.VALUE.toString(), 78234);
            propertiesExpectedDump.put("id", idExpectedDump);

            Map<String, Object> nicknameExpectedDump = new HashMap<String, Object>();
            nicknameExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            nicknameExpectedDump.put(Key.VALUE.toString(), "");
            propertiesExpectedDump.put("nickname", nicknameExpectedDump);

            Map<String, Object> middleNameExpectedDump = new HashMap<String, Object>();
            middleNameExpectedDump.put(Key.VALUE.toString(), Value.NULL.toString());
            propertiesExpectedDump.put("middleName", middleNameExpectedDump);

            Map<String, Object> marriedExpectedDump = new HashMap<String, Object>();
            marriedExpectedDump.put(Key.TYPE.toString(), Type.BOOLEAN);
            marriedExpectedDump.put(Key.VALUE.toString(), true);
            propertiesExpectedDump.put("married", marriedExpectedDump);

            propertiesExpectedDump.put("supervisor", supervisorExpectedDump);

            Map<String, Object> favoriteColorsExpectedDump = new HashMap<String, Object>();
            favoriteColorsExpectedDump.put(Key.TYPE.toString(), Type.SEQUENCE);
            List<Map<String, Object>> favoriteColorListExpectedDump = new ArrayList<Map<String, Object>>();
            Map<String, Object> color1ExpectedDump = new HashMap<String, Object>();
            color1ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            color1ExpectedDump.put(Key.VALUE.toString(), "red");
            favoriteColorListExpectedDump.add(color1ExpectedDump);
            Map<String, Object> color2ExpectedDump = new HashMap<String, Object>();
            color2ExpectedDump.put(Key.TYPE.toString(), Type.STRING);
            color2ExpectedDump.put(Key.VALUE.toString(), "orange");
            favoriteColorListExpectedDump.add(color2ExpectedDump);
            favoriteColorsExpectedDump.put(Key.VALUE.toString(), favoriteColorListExpectedDump);
            propertiesExpectedDump.put("favoriteColors", favoriteColorsExpectedDump);

            //            Map<String, Object> degreesExpectedDump = new HashMap<String, Object>();
            //            degreesExpectedDump.put(Key.VALUE.toString(), Value.NULL.toString());
            //            propertiesExpectedDump.put("degrees", degreesExpectedDump);            
        }
        expectedDump.put(Key.PROPERTIES.toString(), propertiesExpectedDump);

        // Methods
        SortedMap<String, Object> methodDump = getEmployeeMethodsExpectedDump(exposureLevel, "Smith");
        if (!methodDump.isEmpty()) {
            methodDump.put("boss()", supervisorExpectedDump);
        }
        expectedDump.put(Key.METHODS.toString(), methodDump);

        return expectedDump;
    }

}