Adding ExtraMatchers for new hamcrest matchers.

+ Adding ExtraMatchers.ordered(List<T>) that can give a human
  readable analysis of 2 List's and show the differences between
  each in a clear way.
diff --git a/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/ExtraMatchers.java b/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/ExtraMatchers.java
new file mode 100644
index 0000000..dc78d48
--- /dev/null
+++ b/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/ExtraMatchers.java
@@ -0,0 +1,53 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.toolchain.test;
+
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.matchers.IsOrderedCollectionContaining;
+
+/**
+ * Extra Matchers for the Junit Hamcrest users out there.
+ */
+public class ExtraMatchers
+{
+    /**
+     * Creates a matcher for {@link Iterable}s that matches when consecutive passes over the
+     * examined {@link Iterable} yield at least one item that is matched by the corresponding
+     * matcher from the specified <code>itemMatchers</code>. Whilst matching, each traversal of
+     * the examined {@link Iterable} will stop as soon as a matching item is found.
+     * <p>
+     * For example:
+     * 
+     * <pre>
+     * assertThat(Arrays.asList(&quot;foo&quot;,&quot;bar&quot;,&quot;baz&quot;),hasItems(endsWith(&quot;z&quot;),endsWith(&quot;o&quot;)))
+     * </pre>
+     * 
+     * @param itemMatchers
+     *            the matchers to apply to items provided by the examined {@link Iterable}
+     * @param <T>
+     *            the type
+     * @return the matcher
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static <T> org.hamcrest.Matcher<java.lang.Iterable<? super T>> ordered(List<T> itemMatchers)
+    {
+        return new IsOrderedCollectionContaining(itemMatchers);
+    }
+}
diff --git a/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/matchers/IsOrderedCollectionContaining.java b/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/matchers/IsOrderedCollectionContaining.java
new file mode 100644
index 0000000..deec92d
--- /dev/null
+++ b/jetty-test-helper/src/main/java/org/eclipse/jetty/toolchain/test/matchers/IsOrderedCollectionContaining.java
@@ -0,0 +1,148 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.toolchain.test.matchers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.SelfDescribing;
+
+/**
+ * @param <T> the type
+ */
+public class IsOrderedCollectionContaining<T> extends BaseMatcher<List<? super T>>
+{
+    private class MismatchDescription implements SelfDescribing
+    {
+        private final String id;
+        private final List<T> entries;
+        
+        public MismatchDescription(String id, List<T> entries)
+        {
+            this.id = id;
+            this.entries = entries;
+        }
+
+        @Override
+        public void describeTo(Description description)
+        {
+            description.appendText(String.format("%s Entries (size: %d)",id,entries.size()));
+            for (int i = 0; i < entries.size(); i++)
+            {
+                Object actualObj = entries.get(i);
+                char indicator = badEntries.contains(i)?'>':' ';
+                description.appendText(String.format("%n%s[%d] %s",indicator,i,actualObj==null?"<null>":actualObj.toString()));
+            }
+        }
+    }
+    
+    private final List<T> expectedList;
+    private String failureReason;
+    private List<Integer> badEntries = new ArrayList<>();
+    private IsOrderedCollectionContaining<T>.MismatchDescription actualFailureDescription;
+    private IsOrderedCollectionContaining<T>.MismatchDescription expectedFailureDescription;
+    
+    /**
+     * @param expectedList the expected list
+     */
+    public IsOrderedCollectionContaining(List<T> expectedList)
+    {
+        this.expectedList = expectedList;
+    }
+    
+    @Override
+    public boolean matches(Object collection)
+    {
+        if (collection == null)
+        {
+            failureReason = "is <null>";
+            return false;
+        }
+        
+        if(!(collection instanceof List))
+        {
+            failureReason = "is not an instance of " + List.class.getName();
+            return false;
+        }
+        
+        @SuppressWarnings("unchecked")
+        List<T> actualList = (List<T>)collection;
+        
+        // same size?
+        boolean sizeMismatch = expectedList.size() != actualList.size();
+
+        // test content
+        this.badEntries = new ArrayList<>();
+        int min = Math.min(expectedList.size(),actualList.size());
+        int max = Math.max(expectedList.size(),actualList.size());
+        for (int i = 0; i < min; i++)
+        {
+            if (!expectedList.get(i).equals(actualList.get(i)))
+            {
+                badEntries.add(i);
+            }
+        }
+        for (int i = min; i < max; i++)
+        {
+            badEntries.add(i);
+        }
+        
+        if (sizeMismatch || badEntries.size() > 0)
+        {
+            // build up detailed error message
+            
+            // The core failure reason
+            if (sizeMismatch)
+            {
+                this.failureReason = String.format("size mismatch: expected <%d> entries, but got <%d> entries instead",expectedList.size(),actualList.size());
+            }
+            else if (badEntries.size() > 0)
+            {
+                this.failureReason = String.format("<%d> entr%s not matched",badEntries.size(),badEntries.size()>1?"ies":"y");
+                this.actualFailureDescription = new MismatchDescription("Actual",actualList);
+                this.expectedFailureDescription = new MismatchDescription("Expected",expectedList);
+            }
+            
+            return false;
+        }
+        
+        return true;
+    }
+
+    // Describe Expectation (reason or entries)
+    @Override
+    public void describeTo(Description description)
+    {
+        description.appendDescriptionOf(this.expectedFailureDescription);
+    }
+    
+    // Describe Actual (entries)
+    @Override
+    public void describeMismatch(Object item, Description description)
+    {
+        description.appendText(this.failureReason);
+        if (this.actualFailureDescription != null)
+        {
+            description.appendText(System.lineSeparator());
+            description.appendDescriptionOf(this.actualFailureDescription);
+        }
+    }
+}
\ No newline at end of file
diff --git a/jetty-test-helper/src/test/java/org/eclipse/jetty/toolchain/test/ExtraMatchersTest.java b/jetty-test-helper/src/test/java/org/eclipse/jetty/toolchain/test/ExtraMatchersTest.java
new file mode 100644
index 0000000..cb6038e
--- /dev/null
+++ b/jetty-test-helper/src/test/java/org/eclipse/jetty/toolchain/test/ExtraMatchersTest.java
@@ -0,0 +1,65 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.toolchain.test;
+
+import static org.eclipse.jetty.toolchain.test.ExtraMatchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+@SuppressWarnings("javadoc")
+public class ExtraMatchersTest
+{
+    @Rule
+    public ExpectedException expectedThrowable = ExpectedException.none();
+    
+    @Test
+    public void testOrderedFail()
+    {
+        List<String> actual = Arrays.asList(new String[] { "avocado", "banana", "cherry" });
+        List<String> expected = Arrays.asList(new String[] { "apple", "banana", "cherry" });
+        
+        expectedThrowable.expect(AssertionError.class);
+        assertThat("Order", actual, ordered(expected));
+    }
+    
+    @Test
+    public void testOrderedSuccess()
+    {
+        List<String> actual = Arrays.asList(new String[] { "apple", "banana", "cherry" });
+        List<String> expected = Arrays.asList(new String[] { "apple", "banana", "cherry" });
+        
+        assertThat("Order", actual, ordered(expected));
+    }
+    
+    @Test
+    public void testOrderedMismatch()
+    {
+        List<String> actual = Arrays.asList(new String[] { "banana", "apple", "cherry" });
+        List<String> expected = Arrays.asList(new String[] { "apple", "banana", "cherry" });
+        
+        expectedThrowable.expect(AssertionError.class);
+        assertThat("Order", actual, ordered(expected));
+    }
+}