Author: radu Date: Tue Nov 29 17:42:59 2016 New Revision: 1771928 URL: http://svn.apache.org/viewvc?rev=1771928&view=rev Log: SLING-6336 - Implement a ResourceResolverWrapper
* correctly wrap resources or resource iterators in the RRW * moved the RRW to the org.apache.sling.api.wrappers sub-package Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java Removed: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverWrapper.java Modified: sling/trunk/bundles/api/pom.xml sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java Modified: sling/trunk/bundles/api/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/pom.xml?rev=1771928&r1=1771927&r2=1771928&view=diff ============================================================================== --- sling/trunk/bundles/api/pom.xml (original) +++ sling/trunk/bundles/api/pom.xml Tue Nov 29 17:42:59 2016 @@ -83,6 +83,12 @@ <version>2.1.0</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> </dependencies> <build> Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java?rev=1771928&view=auto ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java (added) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java Tue Nov 29 17:42:59 2016 @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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.api.wrappers; + +import java.util.Iterator; + +import org.osgi.annotation.versioning.ConsumerType; + +/** + * Wrapper class for {@code Iterator}s, that forwards all method calls to the wrapped {@code Iterator}. + * + * @param <T> the type of objects this {@code Iterator} holds + */ +@ConsumerType +public class IteratorWrapper<T> implements Iterator<T> { + + private final Iterator<T> wrapped; + + /** + * Creates a wrapping iterator, delegating all method calls to the given {@code wrappedIterator}. + * + * @param wrappedIterator the wrapped iterator + */ + public IteratorWrapper(Iterator<T> wrappedIterator) { + this.wrapped = wrappedIterator; + } + + @Override + public boolean hasNext() { + return wrapped.hasNext(); + } + + @Override + public T next() { + return wrapped.next(); + } + + @Override + public void remove() { + wrapped.remove(); + } +} Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java?rev=1771928&view=auto ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java (added) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java Tue Nov 29 17:42:59 2016 @@ -0,0 +1,403 @@ +/******************************************************************************* + * 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.api.wrappers; + +import java.util.Iterator; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; + +import org.apache.sling.api.resource.LoginException; +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.api.resource.ResourceWrapper; +import org.osgi.annotation.versioning.ConsumerType; + +/** + * The {@code ResourceResolverWrapper} is a wrapper for any {@code ResourceResolver}, delegating all method calls to the wrapped resource + * resolver by default. Extensions of this class may overwrite any method to return different values as appropriate. + */ +@ConsumerType +public class ResourceResolverWrapper implements ResourceResolver { + + private ResourceResolver wrapped; + + /** + * Creates a new wrapper instance, delegating all calls to the given {@code resolver}. + * + * @param resolver the wrapped resource resolver + */ + public ResourceResolverWrapper(ResourceResolver resolver) { + wrapped = resolver; + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver. + * + * @param request The http servlet request object providing more hints at + * how to resolve the <code>absPath</code>. This parameter may be + * <code>null</code> in which case the implementation should use + * reasonable defaults. + * @param absPath The absolute path to be resolved to a resource. If this + * parameter is <code>null</code>, it is assumed to address the + * root of the resource tree. If the path is relative it is + * assumed relative to the root, that is a slash is prepended to + * the path before resolving it. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Resource resolve(@Nonnull HttpServletRequest request, @Nonnull String absPath) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(request, absPath)); + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver. + * + * @param absPath The absolute path to be resolved to a resource. If this + * parameter is <code>null</code>, it is assumed to address the + * root of the resource tree. If the path is relative it is + * assumed relative to the root, that is a slash is prepended to + * the path before resolving it. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Resource resolve(@Nonnull String absPath) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(absPath)); + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver. + * + * @param request The http servlet request object used to resolve the + * resource for. This must not be <code>null</code>. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Resource resolve(@Nonnull HttpServletRequest request) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(request)); + } + + @Nonnull + @Override + public String map(@Nonnull String resourcePath) { + return wrapped.map(resourcePath); + } + + @Override + public String map(@Nonnull HttpServletRequest request, @Nonnull String resourcePath) { + return wrapped.map(request, resourcePath); + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code getResource} on the wrapped resource resolver. + * + * @param path The absolute path to the resource object to be loaded. The + * path may contain relative path specifiers like <code>.</code> + * (current location) and <code>..</code> (parent location), + * which are resolved by this method. If the path is relative, + * that is the first character is not a slash, implementations + * are expected to apply a search path algorithm to resolve the + * relative path to a resource. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Override + public Resource getResource(@Nonnull String path) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.getResource(path)); + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code getResource} on the wrapped resource resolver. + * + * @param base The base {@link Resource} against which a relative path + * argument given by <code>path</code> is resolved. This + * parameter may be <code>null</code> if the <code>path</code> is + * known to be absolute. + * @param path The path to the resource object to be loaded. If the path is + * relative, i.e. does not start with a slash (<code>/</code>), + * the resource relative to the given <code>base</code> resource + * is returned. The path may contain relative path specifiers + * like <code>.</code> (current location) and <code>..</code> + * (parent location), which are resolved by this method. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Override + public Resource getResource(Resource base, @Nonnull String path) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.getResource(base, path)); + } + + @Nonnull + @Override + public String[] getSearchPath() { + return wrapped.getSearchPath(); + } + + /** + * Wraps and returns the {@code Iterator} obtained by calling {@code listChildren} on the wrapped resource resolver. + * + * @param parent The {@link Resource Resource} whose children are requested. + * @return a wrapped iterator obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Iterator<Resource> listChildren(@Nonnull Resource parent) { + return new ResourceIteratorWrapper(this, wrapped.listChildren(parent)); + } + + /** + * Wraps and returns the {@code Resource} obtained by calling {@code getParent} on the wrapped resource resolver. + * + * @param child The {@link Resource Resource} whose parent is requested. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Override + public Resource getParent(@Nonnull Resource child) { + return ResourceResolverResourceWrapper.wrap(this, wrapped.getParent(child)); + } + + /** + * Wraps and returns the {@code Iterable} obtained by calling {@code getChildren} on the wrapped resource resolver. + * + * @param parent The {@link Resource Resource} whose children are requested. + * @return a wrapped iterable obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Iterable<Resource> getChildren(@Nonnull final Resource parent) { + final ResourceResolverWrapper resourceResolverWrapper = this; + return new Iterable<Resource>() { + @Override + public Iterator<Resource> iterator() { + return new ResourceIteratorWrapper(resourceResolverWrapper, wrapped.getChildren(parent).iterator()); + } + }; + } + + /** + * Wraps and returns the {@code Iterator} obtained by calling {@code findResources} on the wrapped resource resolver. + * + * @param query The query string to use to find the resources. + * @param language The language in which the query is formulated. The + * language should always be specified. However for + * compatibility with older version, if no language + * is specified, "xpath" is used. + * @return a wrapped iterator obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Iterator<Resource> findResources(@Nonnull String query, String language) { + return new ResourceIteratorWrapper(this, wrapped.findResources(query, language)); + } + + @Nonnull + @Override + public Iterator<Map<String, Object>> queryResources(@Nonnull String query, String language) { + return wrapped.queryResources(query, language); + } + + @Override + public boolean hasChildren(@Nonnull Resource resource) { + return wrapped.hasChildren(resource); + } + + /** + * Wraps and returns the {@code ResourceResolver} obtained by calling {@code clone} on the wrapped resource resolver. + * + * @param authenticationInfo The map or credential data to overlay the + * original credential data with for the creation of a new + * resource resolver. This may be <code>null</code> in which case + * the same credential data is used as was used to create this + * instance. + * @return a wrapped resource resolver + */ + @Nonnull + @Override + public ResourceResolver clone(Map<String, Object> authenticationInfo) throws LoginException { + ResourceResolver toWrap = wrapped.clone(authenticationInfo); + return new ResourceResolverWrapper(toWrap); + } + + @Override + public boolean isLive() { + return wrapped.isLive(); + } + + @Override + public void close() { + wrapped.close(); + } + + @Override + public String getUserID() { + return wrapped.getUserID(); + } + + @Nonnull + @Override + public Iterator<String> getAttributeNames() { + return wrapped.getAttributeNames(); + } + + @Override + public Object getAttribute(@Nonnull String name) { + return wrapped.getAttribute(name); + } + + @Override + public void delete(@Nonnull Resource resource) throws PersistenceException { + wrapped.delete(resource); + } + + /** + * Wraps the {@code Resource} obtained by calling {@code create} on the wrapped resource resolver. + * + * @param parent The parent resource + * @param name The name of the child resource - this is a plain name, not a path! + * @param properties Optional properties for the resource + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Nonnull + @Override + public Resource create(@Nonnull Resource parent, @Nonnull String name, Map<String, Object> properties) throws PersistenceException { + return ResourceResolverResourceWrapper.wrap(this, wrapped.create(parent, name, properties)); + } + + @Override + public void revert() { + wrapped.revert(); + } + + @Override + public void commit() throws PersistenceException { + wrapped.commit(); + } + + @Override + public boolean hasChanges() { + return wrapped.hasChanges(); + } + + @Override + public String getParentResourceType(Resource resource) { + return wrapped.getParentResourceType(resource); + } + + @Override + public String getParentResourceType(String resourceType) { + return wrapped.getParentResourceType(resourceType); + } + + @Override + public boolean isResourceType(Resource resource, String resourceType) { + return wrapped.isResourceType(resource, resourceType); + } + + @Override + public void refresh() { + wrapped.refresh(); + } + + /** + * Wraps the {@code Resource} obtained by calling {@code copy} on the wrapped resource resolver. + * + * @param srcAbsPath the path of the resource to be copied. + * @param destAbsPath the location to which the resource at + * <code>srcAbsPath</code> is to be copied. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Override + public Resource copy(String srcAbsPath, String destAbsPath) throws PersistenceException { + return ResourceResolverResourceWrapper.wrap(this, wrapped.copy(srcAbsPath, destAbsPath)); + } + + /** + * Wraps the {@code Resource} obtained by calling {@code move} on the wrapped resource resolver. + * + * @param srcAbsPath the path of the resource to be moved. + * @param destAbsPath the location to which the resource at + * <code>srcAbsPath</code> is to be moved. + * @return a wrapped resource obtained through the wrapped resource resolver + */ + @Override + public Resource move(String srcAbsPath, String destAbsPath) throws PersistenceException { + return ResourceResolverResourceWrapper.wrap(this, wrapped.move(srcAbsPath, destAbsPath)); + } + + @Override + public <AdapterType> AdapterType adaptTo(@Nonnull Class<AdapterType> type) { + return wrapped.adaptTo(type); + } + + /** + * {@code ResourceWrapper} that overwrites the {@link #getResourceResolver()} to return the {@link ResourceResolverWrapper}. + */ + private static class ResourceResolverResourceWrapper extends ResourceWrapper { + + private final ResourceResolverWrapper resolver; + + /** + * Creates a new wrapper instance delegating all method calls to the given {@code resource}. + * + * @param resolver the wrapping resource resolver + * @param resource the wrapped resource + */ + ResourceResolverResourceWrapper(ResourceResolverWrapper resolver, Resource resource) { + super(resource); + this.resolver = resolver; + } + + /** + * Returns the wrapping resource resolver from which this resource was obtained. + * + * @return the wrapping resource resolver + */ + @Override + public ResourceResolver getResourceResolver() { + return resolver; + } + + private static Resource wrap(ResourceResolverWrapper resolver, Resource resource) { + if (resource != null) { + return new ResourceResolverResourceWrapper(resolver, resource); + } + return null; + } + } + + /** + * {@code IteratorWrapper} that wraps every returned {@code Resource} with the {@code ResourceResolverResourceWrapper}. + * + * @see ResourceResolverResourceWrapper + */ + private static class ResourceIteratorWrapper extends IteratorWrapper<Resource> { + + private final ResourceResolverWrapper resolver; + + public ResourceIteratorWrapper(ResourceResolverWrapper resolver, Iterator<Resource> wrappedIterator) { + super(wrappedIterator); + this.resolver = resolver; + } + + @Override + public Resource next() { + return ResourceResolverResourceWrapper.wrap(resolver, super.next()); + } + } +} Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java?rev=1771928&r1=1771927&r2=1771928&view=diff ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java (original) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java Tue Nov 29 17:42:59 2016 @@ -17,7 +17,7 @@ * under the License. */ -@Version("2.5.0") +@Version("2.6.0") package org.apache.sling.api.wrappers; import org.osgi.annotation.versioning.Version; Added: sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java?rev=1771928&view=auto ============================================================================== --- sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java (added) +++ sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java Tue Nov 29 17:42:59 2016 @@ -0,0 +1,431 @@ +/******************************************************************************* + * 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.api.wrappers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceWrapper; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class ResourceResolverWrapperTest { + + private static final String PATH = "path"; + private static final String MAPPED_PATH = "mappedPath"; + private static final String[] searchPaths = {"/apps", "/libs"}; + private static final String QUERY = "query"; + private static final String LANGUAGE = "language"; + private static final String USER = "user"; + private static final String ATTR_NAME = "attrName"; + private ResourceResolver wrappedResolver; + private ResourceResolverWrapper underTest; + + @Before + public void setUp() throws Exception { + wrappedResolver = mock(ResourceResolver.class); + when(wrappedResolver.getSearchPath()).thenReturn(searchPaths); + underTest = new ResourceResolverWrapper(wrappedResolver); + } + + @Test + public void testResolve() throws Exception { + final HttpServletRequest request = mock(HttpServletRequest.class); + final Resource resource = mock(Resource.class); + when(resource.getPath()).thenReturn(PATH); + when(wrappedResolver.resolve(request, PATH)).thenReturn(resource); + final Resource result = underTest.resolve(request, PATH); + + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(resource.getPath(), result.getPath()); + verify(wrappedResolver).resolve(request, PATH); + } + + @Test + public void testResolve1() throws Exception { + final Resource resource = mock(Resource.class); + when(resource.getPath()).thenReturn(PATH); + when(wrappedResolver.resolve(PATH)).thenReturn(resource); + final Resource result = underTest.resolve(PATH); + + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(resource.getPath(), result.getPath()); + verify(wrappedResolver).resolve(PATH); + } + + @Test + public void testResolve2() throws Exception { + final HttpServletRequest request = mock(HttpServletRequest.class); + final Resource resource = mock(Resource.class); + when(resource.getPath()).thenReturn(PATH); + when(wrappedResolver.resolve(request)).thenReturn(resource); + final Resource result = underTest.resolve(request); + + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(resource.getPath(), result.getPath()); + verify(wrappedResolver).resolve(request); + } + + @Test + public void testMap() throws Exception { + when(wrappedResolver.map(PATH)).thenReturn(MAPPED_PATH); + + assertEquals(MAPPED_PATH, underTest.map(PATH)); + verify(wrappedResolver).map(PATH); + } + + @Test + public void testMap1() throws Exception { + final HttpServletRequest request = mock(HttpServletRequest.class); + when(wrappedResolver.map(request, PATH)).thenReturn(MAPPED_PATH); + + assertEquals(MAPPED_PATH, underTest.map(request, PATH)); + verify(wrappedResolver).map(request, PATH); + } + + @Test + public void testGetResource() throws Exception { + final Resource resource = mock(Resource.class); + when(resource.getPath()).thenReturn(PATH); + when(wrappedResolver.getResource(PATH)).thenReturn(resource); + + final Resource result = underTest.getResource(PATH); + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(resource.getPath(), result.getPath()); + verify(wrappedResolver).getResource(PATH); + } + + @Test + public void testGetResource1() throws Exception { + final Resource parent = mock(Resource.class); + final Resource resource = mock(Resource.class); + when(resource.getPath()).thenReturn(PATH); + when(wrappedResolver.getResource(parent, PATH)).thenReturn(resource); + + final Resource result = underTest.getResource(parent, PATH); + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(resource.getPath(), result.getPath()); + verify(wrappedResolver).getResource(parent, PATH); + } + + @Test + public void testGetSearchPath() throws Exception { + assertArrayEquals(searchPaths, underTest.getSearchPath()); + verify(wrappedResolver).getSearchPath(); + } + + @Test + public void testListChildren() throws Exception { + final Resource parent = mock(Resource.class); + final List<Resource> children = new ArrayList<>(1); + final Resource child = mock(Resource.class); + when(child.getPath()).thenReturn(PATH); + children.add(child); + when(wrappedResolver.listChildren(parent)).thenAnswer(new Answer<Iterator<Resource>>() { + @Override + public Iterator<Resource> answer(InvocationOnMock invocationOnMock) throws Throwable { + return children.iterator(); + } + }); + + int index = 0; + Iterator<Resource> wrappedIterator = underTest.listChildren(parent); + assertTrue(wrappedIterator instanceof IteratorWrapper); + while (wrappedIterator.hasNext()) { + Resource result = wrappedIterator.next(); + assertTrue(result instanceof ResourceWrapper); + assertEquals(PATH, result.getPath()); + index++; + } + assertEquals(1, index); + verify(wrappedResolver).listChildren(parent); + } + + @Test + public void testGetParent() throws Exception { + final Resource parent = mock(Resource.class); + final Resource child = mock(Resource.class); + when(parent.getPath()).thenReturn(PATH); + when(wrappedResolver.getParent(child)).thenReturn(parent); + + Resource result = underTest.getParent(child); + assertTrue(result instanceof ResourceWrapper); + assertEquals(parent.getPath(), result.getPath()); + verify(wrappedResolver).getParent(child); + } + + @Test + public void testGetChildren() throws Exception { + final Resource parent = mock(Resource.class); + final List<Resource> children = new ArrayList<>(1); + final Resource child = mock(Resource.class); + when(child.getPath()).thenReturn(PATH); + children.add(child); + when(wrappedResolver.getChildren(parent)).thenReturn(children); + int index = 0; + Iterable<Resource> iterable = underTest.getChildren(parent); + for (Resource result : iterable) { + assertTrue(result instanceof ResourceWrapper); + assertEquals(PATH, result.getPath()); + index++; + } + assertEquals(1, index); + verify(wrappedResolver).getChildren(parent); + } + + @Test + public void testFindResources() throws Exception { + final List<Resource> children = new ArrayList<>(1); + final Resource child = mock(Resource.class); + when(child.getPath()).thenReturn(PATH); + children.add(child); + when(wrappedResolver.findResources(QUERY, LANGUAGE)).thenAnswer(new Answer<Iterator<Resource>>() { + @Override + public Iterator<Resource> answer(InvocationOnMock invocationOnMock) throws Throwable { + return children.iterator(); + } + }); + + int index = 0; + final Iterator<Resource> wrappedIterator = underTest.findResources(QUERY, LANGUAGE); + assertTrue(wrappedIterator instanceof IteratorWrapper); + while (wrappedIterator.hasNext()) { + Resource result = wrappedIterator.next(); + assertTrue(result instanceof ResourceWrapper); + assertEquals(PATH, result.getPath()); + index++; + } + assertEquals(1, index); + verify(wrappedResolver).findResources(QUERY, LANGUAGE); + } + + @Test + public void testQueryResources() throws Exception { + final Map<String, Object> expected = mock(Map.class); + final List<Map<String, Object>> list = new ArrayList<>(); + list.add(expected); + when(wrappedResolver.queryResources(QUERY, LANGUAGE)).thenReturn(list.iterator()); + + int index = 0; + final Iterator<Map<String, Object>> iterator = underTest.queryResources(QUERY, LANGUAGE); + Map<String, Object> result = null; + while (iterator.hasNext()) { + result = iterator.next(); + index++; + } + assertEquals(expected, result); + assertEquals(1, index); + verify(wrappedResolver).queryResources(QUERY, LANGUAGE); + } + + @Test + public void testHasChildren() throws Exception { + final Resource resource = mock(Resource.class); + when(wrappedResolver.hasChildren(resource)).thenReturn(true); + + assertTrue(underTest.hasChildren(resource)); + verify(wrappedResolver).hasChildren(resource); + } + + @Test + public void testClone() throws Exception { + final Map<String, Object> authenticationInfo = mock(Map.class); + final ResourceResolver clone = mock(ResourceResolver.class); + when(wrappedResolver.clone(authenticationInfo)).thenReturn(clone); + + final ResourceResolver result = underTest.clone(authenticationInfo); + assertTrue(result instanceof ResourceResolverWrapper); + assertNotEquals(result, underTest); + verify(wrappedResolver).clone(authenticationInfo); + } + + @Test + public void testIsLive() throws Exception { + when(wrappedResolver.isLive()).thenReturn(true); + assertTrue(underTest.isLive()); + verify(wrappedResolver).isLive(); + } + + @Test + public void testClose() throws Exception { + underTest.close(); + verify(wrappedResolver).close(); + } + + @Test + public void testGetUserID() throws Exception { + when(wrappedResolver.getUserID()).thenReturn(USER); + assertEquals(USER, underTest.getUserID()); + verify(wrappedResolver).getUserID(); + } + + @Test + public void testGetAttributeNames() throws Exception { + final Iterator<String> attributeNames = mock(Iterator.class); + when(wrappedResolver.getAttributeNames()).thenReturn(attributeNames); + + assertEquals(attributeNames, underTest.getAttributeNames()); + verify(wrappedResolver).getAttributeNames(); + } + + @Test + public void testGetAttribute() throws Exception { + final Object obj = mock(Object.class); + when(wrappedResolver.getAttribute(ATTR_NAME)).thenReturn(obj); + + assertEquals(obj, underTest.getAttribute(ATTR_NAME)); + verify(wrappedResolver).getAttribute(ATTR_NAME); + } + + @Test + public void testDelete() throws Exception { + final Resource toDelete = mock(Resource.class); + underTest.delete(toDelete); + verify(wrappedResolver).delete(toDelete); + } + + @Test + public void testCreate() throws Exception { + final Resource parent = mock(Resource.class); + final String name = "aName"; + final Map<String, Object> properties = new HashMap<String, Object>(){{ + put("jcr:primaryType", "nt:unstructured"); + }}; + final Resource expected = mock(Resource.class); + when(expected.getParent()).thenReturn(parent); + when(expected.getName()).thenReturn(name); + when(wrappedResolver.create(parent, name, properties)).thenReturn(expected); + + final Resource result = underTest.create(parent, name, properties); + assertTrue(result instanceof ResourceWrapper); + assertEquals(parent, result.getParent()); + assertEquals(name, result.getName()); + verify(wrappedResolver).create(parent, name, properties); + } + + @Test + public void testRevert() throws Exception { + underTest.revert(); + verify(wrappedResolver).revert(); + } + + @Test + public void testCommit() throws Exception { + underTest.commit(); + verify(wrappedResolver).commit(); + } + + @Test + public void testHasChanges() throws Exception { + when(wrappedResolver.hasChanges()).thenReturn(true); + assertTrue(underTest.hasChanges()); + verify(wrappedResolver).hasChanges(); + } + + @Test + public void testGetParentResourceType() throws Exception { + final String rt = "rt"; + final Resource resource = mock(Resource.class); + when(wrappedResolver.getParentResourceType(resource)).thenReturn(rt); + + assertEquals(rt, underTest.getParentResourceType(resource)); + verify(wrappedResolver).getParentResourceType(resource); + } + + @Test + public void testGetParentResourceType1() throws Exception { + final String rt = "rt"; + final String rtt = "rtt"; + when(wrappedResolver.getParentResourceType(rt)).thenReturn(rtt); + + assertEquals(rtt, underTest.getParentResourceType(rt)); + verify(wrappedResolver).getParentResourceType(rt); + } + + @Test + public void testIsResourceType() throws Exception { + final Resource resource = mock(Resource.class); + final String rt = "rt"; + when(wrappedResolver.isResourceType(resource, rt)).thenReturn(true); + + assertTrue(underTest.isResourceType(resource, rt)); + verify(wrappedResolver).isResourceType(resource, rt); + } + + @Test + public void testRefresh() throws Exception { + underTest.refresh(); + verify(wrappedResolver).refresh(); + } + + @Test + public void testCopy() throws Exception { + final String source = "source"; + final String destination = "destination"; + final Resource expected = mock(Resource.class); + when(expected.getPath()).thenReturn(destination); + when(wrappedResolver.copy(source, destination)).thenReturn(expected); + + final Resource result = underTest.copy(source, destination); + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(destination, result.getPath()); + verify(wrappedResolver).copy(source, destination); + } + + @Test + public void testMove() throws Exception { + final String source = "source"; + final String destination = "destination"; + final Resource expected = mock(Resource.class); + when(expected.getPath()).thenReturn(destination); + when(wrappedResolver.move(source, destination)).thenReturn(expected); + + final Resource result = underTest.move(source, destination); + assertTrue(result instanceof ResourceWrapper); + assertEquals(underTest, result.getResourceResolver()); + assertEquals(destination, result.getPath()); + verify(wrappedResolver).move(source, destination); + } + + @Test + public void testAdaptTo() throws Exception { + List list = mock(List.class); + when(wrappedResolver.adaptTo(List.class)).thenReturn(list); + + assertEquals(list, underTest.adaptTo(List.class)); + verify(wrappedResolver).adaptTo(List.class); + } +}