// Path: api/src/main/java/com/ebuddy/cassandra/Path.java
// public interface Path {
// 
//     /** Return a new Path consisting of this Path concatenated with another Path. */
//     Path concat(Path other);
// 
//     /** Return a new Path consisting of this Path concatenated with the specified list indices as elements. */
//     Path withIndices(int... indices);
// 
//     /** Return a new Path consisting of this Path concatenated with the specified elements. */
//     Path withElements(String... elements);
// 
//     /** Get the encoded elements of this Path. */
//     Iterable<String> getElements();
// 
//     /**
//      * Returns the first element in this path, or null if this is an empty path.
//      */
//     String head();
// 
//     /**
//      * Returns the rest of the path after the head (first) element.
//      * If this is an empty path, throws IndexOutOfBoundsException,
//      * if this path has only one element, return an empty path,
//      * otherwise return a new path with elements starting after the head.
//      */
//     Path tail();
// 
//     /**
//      * Return a new Path consisting of the rest of the path elements of this path starting with the specified index.
//      * @param startIndex 0-based start index
//      * @return new Path
//      * @throws IndexOutOfBoundsException if path has insufficient size
//      */
//     Path tail(int startIndex);
// 
//     /**
//      * Return true if this path starts with the specified path.
//      */
//     boolean startsWith(Path path);
// 
//     /** Get the number of elements in this path. */
//     int size();
// 
//     /** Return true if this Path has zero elements. */
//     boolean isEmpty();
// }


import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ebuddy.cassandra.Path;
import com.google.common.collect.ImmutableMap;
        /////////////

        // output of only simple objects is equal to the input, but has strings as keys instead of Paths
        Map<String,Object> expectedResult = new HashMap<String,Object>();
        for (Map.Entry<Path,Object> entry : simpleObjects.entrySet()) {
            expectedResult.put(entry.getKey().head(), entry.getValue());
        }

        assertEquals(result, expectedResult);
    }

    @Test(groups = "unit")
    public void composeSimpleObjectsWithLongerPaths() throws Exception {
        Map<Path,Object> simpleObjects = new HashMap<Path,Object>();
        simpleObjects.put(DefaultPath.fromEncodedPathString("a%2F%40%23/b/c"), "");
        simpleObjects.put(DefaultPath.fromEncodedPathString("a%2F%40%23/b/d"), 42);
        simpleObjects.put(DefaultPath.fromEncodedPathString("d/e/f"), true);
        simpleObjects.put(DefaultPath.fromEncodedPathString("d/f/g"), false);
        simpleObjects.put(DefaultPath.fromEncodedPathString("j/k/l"), null);

        /////////////
        Object result = composer.compose(simpleObjects);
        /////////////

        Map<String,Object> expectedResult = getExpectedMapForComposeSimpleObjectWithLongerPaths();
        assertEquals(result, expectedResult);
    }

    @Test(groups = {"unit"})
    public void composeList() throws Exception {
// Path: api/src/main/java/com/ebuddy/cassandra/Path.java
// public interface Path {
// 
//     /** Return a new Path consisting of this Path concatenated with another Path. */
//     Path concat(Path other);
// 
//     /** Return a new Path consisting of this Path concatenated with the specified list indices as elements. */
//     Path withIndices(int... indices);
// 
//     /** Return a new Path consisting of this Path concatenated with the specified elements. */
//     Path withElements(String... elements);
// 
//     /** Get the encoded elements of this Path. */
//     Iterable<String> getElements();
// 
//     /**
//      * Returns the first element in this path, or null if this is an empty path.
//      */
//     String head();
// 
//     /**
//      * Returns the rest of the path after the head (first) element.
//      * If this is an empty path, throws IndexOutOfBoundsException,
//      * if this path has only one element, return an empty path,
//      * otherwise return a new path with elements starting after the head.
//      */
//     Path tail();
// 
//     /**
//      * Return a new Path consisting of the rest of the path elements of this path starting with the specified index.
//      * @param startIndex 0-based start index
//      * @return new Path
//      * @throws IndexOutOfBoundsException if path has insufficient size
//      */
//     Path tail(int startIndex);
// 
//     /**
//      * Return true if this path starts with the specified path.
//      */
//     boolean startsWith(Path path);
// 
//     /** Get the number of elements in this path. */
//     int size();
// 
//     /** Return true if this Path has zero elements. */
//     boolean isEmpty();
// }


// Path: core/src/test/java/com/ebuddy/cassandra/structure/ComposerTest.java
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ebuddy.cassandra.Path;
import com.google.common.collect.ImmutableMap;

        /////////////

        // output of only simple objects is equal to the input, but has strings as keys instead of Paths
        Map<String,Object> expectedResult = new HashMap<String,Object>();
        for (Map.Entry<Path,Object> entry : simpleObjects.entrySet()) {
            expectedResult.put(entry.getKey().head(), entry.getValue());
        }

        assertEquals(result, expectedResult);
    }

    @Test(groups = "unit")
    public void composeSimpleObjectsWithLongerPaths() throws Exception {
        Map<Path,Object> simpleObjects = new HashMap<Path,Object>();
        simpleObjects.put(DefaultPath.fromEncodedPathString("a%2F%40%23/b/c"), "");
        simpleObjects.put(DefaultPath.fromEncodedPathString("a%2F%40%23/b/d"), 42);
        simpleObjects.put(DefaultPath.fromEncodedPathString("d/e/f"), true);
        simpleObjects.put(DefaultPath.fromEncodedPathString("d/f/g"), false);
        simpleObjects.put(DefaultPath.fromEncodedPathString("j/k/l"), null);

        /////////////
        Object result = composer.compose(simpleObjects);
        /////////////

        Map<String,Object> expectedResult = getExpectedMapForComposeSimpleObjectWithLongerPaths();
        assertEquals(result, expectedResult);
    }

    @Test(groups = {"unit"})
    public void composeList() throws Exception {
        Map<Path,Object> simpleObjects = new HashMap<Path,Object>();