You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:17:28 UTC

[sling-org-apache-sling-testing-hamcrest] 08/18: SLING-5508 provide additional matchers for resource children and for resource names

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.hamcrest-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-hamcrest.git

commit faadad45a31097e8698db8b27115080947853313
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Wed Feb 10 12:24:08 2016 +0000

    SLING-5508 provide additional matchers for resource children and for resource names
    
    add some basic tests for all matchers, refactor the matcher classes to allow to easier reuse those for some other purposes
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/hamcrest@1729585 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  28 ++++-
 .../apache/sling/hamcrest/ResourceMatchers.java    |  81 +++++++++++--
 .../hamcrest/matchers/ResourceChildrenMatcher.java |  54 ++++++---
 .../hamcrest/matchers/ResourceNameMatcher.java     |  49 ++++++++
 ...Matcher.java => ResourcePropertiesMatcher.java} |  11 +-
 .../testing/hamcrest/ResourceMatchersTest.java     | 133 +++++++++++++++++++++
 6 files changed, 322 insertions(+), 34 deletions(-)

diff --git a/pom.xml b/pom.xml
index b457bf2..2198373 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
     <dependencies>
         <dependency>
             <groupId>org.hamcrest</groupId>
-            <artifactId>hamcrest-core</artifactId>
+            <artifactId>hamcrest-library</artifactId>
             <version>1.3</version>
             <scope>provided</scope>
         </dependency>
@@ -52,5 +52,31 @@
             <version>2.4.0</version>
             <scope>provided</scope>
         </dependency>
+        
+        <!-- testing dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+            <version>1.6.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.resourceresolver-mock</artifactId>
+            <version>1.1.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.logging-mock</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
+        
     </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/hamcrest/ResourceMatchers.java b/src/main/java/org/apache/sling/hamcrest/ResourceMatchers.java
index dea43d8..9a3fad6 100644
--- a/src/main/java/org/apache/sling/hamcrest/ResourceMatchers.java
+++ b/src/main/java/org/apache/sling/hamcrest/ResourceMatchers.java
@@ -16,15 +16,19 @@
  */
 package org.apache.sling.hamcrest;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.hamcrest.matchers.ResourceChildrenMatcher;
-import org.apache.sling.hamcrest.matchers.ResourceMatcher;
+import org.apache.sling.hamcrest.matchers.ResourceNameMatcher;
+import org.apache.sling.hamcrest.matchers.ResourcePropertiesMatcher;
 import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
 
 /**
  * A collection of <tt>Matcher</tt>s that work on the Resource API level
@@ -35,7 +39,7 @@ public final class ResourceMatchers {
     /**
      * Matches resources which have amongst their children the specified <tt>children</tt>.
      * 
-     * Child resources not contained in the specified <tt>children</tt> are not validated.
+     * Child resources not contained in the specified <tt>children</tt> are not validated. The order of the children does not matter.
      * 
      * <pre>
      * assertThat(resource, hasChildren('child1', 'child2'));
@@ -45,10 +49,53 @@ public final class ResourceMatchers {
      * @return a matcher instance
      */
     public static Matcher<Resource> hasChildren(String... children) {
-        return new ResourceChildrenMatcher(Arrays.asList(children));
+        return new ResourceChildrenMatcher(Arrays.asList(children), false, false);
     }
     
     /**
+     * Matches resources which have exactly the children with the names given in <tt>children</tt>. The order is validated as well.
+     * 
+     * <pre>
+     * assertThat(resource, containsChildren('child1', 'child2'));
+     * </pre>
+     * 
+     * @param children the expected children, not <code>null</code> or empty
+     * @return a matcher instance
+     */
+    public static Matcher<Resource> containsChildren(String... children) {
+        return new ResourceChildrenMatcher(Arrays.asList(children), true, true);
+    }
+    
+    
+    /**
+     * Matches resources which have exactly the children with the names given in <tt>children</tt>. The order is not validated.
+     * 
+     * <pre>
+     * assertThat(resource, containsChildren('child1', 'child2'));
+     * </pre>
+     * 
+     * @param children the expected children, not <code>null</code> or empty
+     * @return a matcher instance
+     */
+    public static Matcher<Resource> containsChildrenInAnyOrder(String... children) {
+        return new ResourceChildrenMatcher(Arrays.asList(children), true, false);
+    }
+    
+    /**
+     * Matches only if the resource has the given name
+     * 
+     * <pre>
+     * assertThat(resource, hasName('resource1'));
+     * </pre>
+     * 
+     * @param name the resources name, not <code>null</code> or empty
+     * @return a matcher instance
+     */
+    public static Matcher<Resource> resourceWithName(String name) {
+        return new ResourceNameMatcher(name);
+    }
+
+    /**
      * Matches resources with a resource type set to the specified <tt>resourceType</tt>
      * 
      * <pre>
@@ -58,7 +105,7 @@ public final class ResourceMatchers {
      * @return a matcher instance
      */
     public static Matcher<Resource> resourceOfType(String resourceType) {
-        return new ResourceMatcher(Collections.<String, Object> singletonMap(ResourceResolver.PROPERTY_RESOURCE_TYPE, resourceType));
+        return new ResourcePropertiesMatcher(Collections.<String, Object> singletonMap(ResourceResolver.PROPERTY_RESOURCE_TYPE, resourceType));
     }
 
     /**
@@ -73,13 +120,33 @@ public final class ResourceMatchers {
      * assertThat(resource, resourceWithProps(expectedProperties));
      * </pre>
      * 
-     * @param resourceType the resource type to match
+     * @param properties the properties to match
      * @return a matcher instance
      */    
     public static Matcher<Resource> resourceWithProps(Map<String, Object> properties) {
-        return new ResourceMatcher(properties);
+        return new ResourcePropertiesMatcher(properties);
     }
-    
+
+    /**
+     * Matches resources which has the given name and at least the specified <tt>properties</tt> defined with matching values
+     * 
+     * <p>Values not declared in the the <tt>properties</tt> parameter are not validated.</p>
+     * <pre>
+     * Map<String, Object> expectedProperties = new HashMap<>();
+     * expectedProperties.put("jcr:title", "Node title");
+     * expectedProperties.put("jcr:text",  "Some long text");
+     * 
+     * assertThat(resource, resourceWithProps(expectedProperties));
+     * </pre>
+     * 
+     * @param name the expected name of the resource
+     * @param properties the properties to match
+     * @return a matcher instance
+     */
+    public static Matcher<Resource> resourceWithNameAndProps(String name, Map<String, Object> properties) {
+        return Matchers.allOf(new ResourceNameMatcher(name), new ResourcePropertiesMatcher(properties));
+    }
+
     private ResourceMatchers() {
         // prevent instantiation
     }
diff --git a/src/main/java/org/apache/sling/hamcrest/matchers/ResourceChildrenMatcher.java b/src/main/java/org/apache/sling/hamcrest/matchers/ResourceChildrenMatcher.java
index 4415a8c..afbb598 100644
--- a/src/main/java/org/apache/sling/hamcrest/matchers/ResourceChildrenMatcher.java
+++ b/src/main/java/org/apache/sling/hamcrest/matchers/ResourceChildrenMatcher.java
@@ -21,42 +21,60 @@ import java.util.List;
 
 import org.apache.sling.api.resource.Resource;
 import org.hamcrest.Description;
+import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+/**
+ * A matcher which matches if the given resource has at least the child resources with the names given in the constructor.
+ * Optionally it can match only if the resource's children match exactly the given child names.
+ * Also you can validate the order in case of exact matching.
+ *
+ */
 public class ResourceChildrenMatcher extends TypeSafeMatcher<Resource> {
-    
-    private final List<String> childNames;
-    
-    public ResourceChildrenMatcher(List<String> childNames) {
+
+    // this should be "Iterable<? extends Resource>" instead of "?" but cannot until https://github.com/hamcrest/JavaHamcrest/issues/107 is solved
+    private final Matcher<?> iterarableMatcher;
+
+    public ResourceChildrenMatcher(List<String> childNames, boolean exactMatch, boolean validateOrder) {
         if ( childNames == null || childNames.isEmpty() ) {
             throw new IllegalArgumentException("childNames is null or empty");
         }
-        
-        this.childNames = childNames;
+
+        if (!exactMatch && validateOrder) {
+            throw new IllegalArgumentException("Can only validate the order for exact matches");
+        }
+
+        List<Matcher<? super Resource>> resourceMatchers = new ArrayList<Matcher<? super Resource>>();
+        for (String childName : childNames) {
+            resourceMatchers.add(new ResourceNameMatcher(childName));
+        }
+
+        if (exactMatch) {
+            if (validateOrder) {
+                this.iterarableMatcher = org.hamcrest.collection.IsIterableContainingInOrder.contains(resourceMatchers);
+            } else {
+                this.iterarableMatcher = org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder(resourceMatchers);
+            }
+        } else {
+            this.iterarableMatcher = org.hamcrest.core.IsCollectionContaining.hasItems(resourceMatchers.toArray(new ResourceNameMatcher[0]));
+        }
     }
 
     @Override
     public void describeTo(Description description) {
-        description.appendText("Resource with children ").appendValueList("[", ",", "]", childNames);
+        iterarableMatcher.describeTo(description);
     }
 
     @Override
     protected boolean matchesSafely(Resource item) {
-        for ( String childName : childNames ) {
-            if ( item.getChild(childName) == null ) {
-                return false;
-            }
-        }
-        return true;
+        return iterarableMatcher.matches(item.getChildren());
     }
 
     @Override
     protected void describeMismatchSafely(Resource item, Description mismatchDescription) {
-        List<String> actualChildNames = new ArrayList<String>();
-        for (Resource child : item.getChildren()) {
-            actualChildNames.add(child.getName());
-        }
-        mismatchDescription.appendText("was Resource with children ").appendValueList("[", ",", "]", actualChildNames).appendText(" (resource: ").appendValue(item).appendText(")");
+        // the default would be something like ".. but item 0 was <Resource.toString()>"
+        // use the iterable matcher here instead
+        iterarableMatcher.describeMismatch(item.getChildren(), mismatchDescription);
     }
 
 }
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/hamcrest/matchers/ResourceNameMatcher.java b/src/main/java/org/apache/sling/hamcrest/matchers/ResourceNameMatcher.java
new file mode 100644
index 0000000..c67331a
--- /dev/null
+++ b/src/main/java/org/apache/sling/hamcrest/matchers/ResourceNameMatcher.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.hamcrest.matchers;
+
+import org.apache.sling.api.resource.Resource;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Matcher which matches whenever the name of the given resource is equal to the name given in the constructor.
+ *
+ */
+public class ResourceNameMatcher extends TypeSafeMatcher<Resource> {
+
+    private final String name;
+
+    public ResourceNameMatcher(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("Resource with name ").appendValue(name);
+    }
+
+    @Override
+    protected boolean matchesSafely(Resource resource) {
+        return name.equals(resource.getName());
+    }
+
+    @Override
+    protected void describeMismatchSafely(Resource resource, Description mismatchDescription) {
+        mismatchDescription.appendText("was Resource with name ").appendValue(resource.getName()).appendText(" (resource: ").appendValue(resource).appendText(")");
+    }
+}
diff --git a/src/main/java/org/apache/sling/hamcrest/matchers/ResourceMatcher.java b/src/main/java/org/apache/sling/hamcrest/matchers/ResourcePropertiesMatcher.java
similarity index 90%
rename from src/main/java/org/apache/sling/hamcrest/matchers/ResourceMatcher.java
rename to src/main/java/org/apache/sling/hamcrest/matchers/ResourcePropertiesMatcher.java
index 4f8ec2c..12a3888 100644
--- a/src/main/java/org/apache/sling/hamcrest/matchers/ResourceMatcher.java
+++ b/src/main/java/org/apache/sling/hamcrest/matchers/ResourcePropertiesMatcher.java
@@ -16,9 +16,6 @@
  */
 package org.apache.sling.hamcrest.matchers;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
@@ -26,12 +23,11 @@ import org.apache.sling.api.resource.ValueMap;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
 
-public class ResourceMatcher extends TypeSafeMatcher<Resource> {
+public class ResourcePropertiesMatcher extends TypeSafeMatcher<Resource> {
 
     private final Map<String, Object> properties;
 
-    public ResourceMatcher(Map<String, Object> properties) {
-
+    public ResourcePropertiesMatcher(Map<String, Object> properties) {
         if (properties == null || properties.isEmpty()) {
             throw new IllegalArgumentException("properties is null or empty");
         }
@@ -53,7 +49,6 @@ public class ResourceMatcher extends TypeSafeMatcher<Resource> {
                 return false;
             }
         }
-
         return true;
     }
 
@@ -61,7 +56,7 @@ public class ResourceMatcher extends TypeSafeMatcher<Resource> {
     protected void describeMismatchSafely(Resource item, Description mismatchDescription) {
         Map<String, Object> actualProperties = item.adaptTo(ValueMap.class);
         if (actualProperties == null) {
-            mismatchDescription.appendText("was Resource which does not expose a value map via adaptTo");
+            mismatchDescription.appendText("was Resource which does not expose a value map via adaptTo(ValueMap.class)");
             return;
         }
         mismatchDescription.appendText("was Resource with properties ").appendValueList("[", ",", "]", actualProperties.entrySet()).appendText(" (resource: ").appendValue(item).appendText(")");
diff --git a/src/test/java/org/apache/sling/testing/hamcrest/ResourceMatchersTest.java b/src/test/java/org/apache/sling/testing/hamcrest/ResourceMatchersTest.java
new file mode 100644
index 0000000..5ba2bd5
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/hamcrest/ResourceMatchersTest.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.testing.hamcrest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.resourceresolver.MockHelper;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ResourceMatchersTest {
+
+    @Rule
+    public final SlingContext context = new SlingContext();
+
+    @Test
+    public void testResourceOfType() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+        .resource("/resource").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "some/type").p("some other key", "some other value").commit();
+        
+        Resource resource = context.resourceResolver().getResource("/resource");
+        Assert.assertThat(resource, ResourceMatchers.resourceOfType("some/type"));
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceOfType("some/other/type")));
+    }
+
+    @Test
+    public void testResourceWithName() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+        .resource("/resource").commit();
+        
+        Resource resource = context.resourceResolver().getResource("/resource");
+        Assert.assertThat(resource, ResourceMatchers.resourceWithName("resource"));
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceWithName("some/other/name")));
+    }
+
+    @Test
+    public void testResourceWithProps() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+        .resource("/resource").p("key1", "value1").p("key2", "value2").p("key3", "value3").commit();
+        
+        Map<String, Object> expectedProperties = new HashMap<String, Object>();
+        expectedProperties.put("key1", "value1");
+        expectedProperties.put("key2", "value2");
+        
+        Resource resource = context.resourceResolver().getResource("/resource");
+        Assert.assertThat(resource, ResourceMatchers.resourceWithProps(expectedProperties));
+        // test existing key with not matching value
+        expectedProperties.put("key2", "value3"); 
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceWithProps(expectedProperties)));
+        
+        // test non-existing key
+        expectedProperties.clear();
+        expectedProperties.put("key4", "value4");
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceWithProps(expectedProperties)));
+    }
+
+    @Test
+    public void testHasChildren() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+          .resource("/parent").resource("child1")
+          .resource("/parent/child2").commit();
+        
+        Resource resource = context.resourceResolver().getResource("/parent");
+        Assert.assertThat(resource, ResourceMatchers.hasChildren("child1"));
+    }
+    
+    @Test
+    public void testResourceWithNameAndProps() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+        .resource("/resource").p("key1", "value1").p("key2", "value2").p("key3", "value3").commit();
+        
+        Map<String, Object> expectedProperties = new HashMap<String, Object>();
+        expectedProperties.put("key1", "value1");
+        expectedProperties.put("key2", "value2");
+        
+        Resource resource = context.resourceResolver().getResource("/resource");
+        Assert.assertThat(resource, ResourceMatchers.resourceWithNameAndProps("resource", expectedProperties));
+        
+        // test not matching name
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceWithNameAndProps("resource1", expectedProperties)));
+        
+        // test existing key with not matching value
+        expectedProperties.put("key2", "value3"); 
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.resourceWithNameAndProps("resource", expectedProperties)));
+    }
+
+    @Test
+    public void testContainsChildrenInAnyOrder() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+          .resource("/parent").resource("child1")
+          .resource("/parent/child2").commit();
+        
+        Resource resource = context.resourceResolver().getResource("/parent");
+        Assert.assertThat(resource, ResourceMatchers.containsChildrenInAnyOrder("child2", "child1"));
+        Assert.assertThat(resource, ResourceMatchers.containsChildrenInAnyOrder("child1", "child2"));
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.containsChildren("child2", "child3", "child1")));
+    }
+
+    @Test
+    public void testContainsChildren() throws PersistenceException {
+        MockHelper.create(context.resourceResolver())
+          .resource("/parent").resource("child1")
+          .resource("/parent/child2").commit();
+        
+        Resource resource = context.resourceResolver().getResource("/parent");
+        Assert.assertThat(resource, ResourceMatchers.containsChildren("child1", "child2"));
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.containsChildren("child2", "child1")));
+        Assert.assertThat(resource, Matchers.not(ResourceMatchers.containsChildren("child1", "child2", "child3")));
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.