SLING-8804 Mock SlingHttpServletRequest should follow same caching as SlingHttpServletRequest
diff --git a/src/main/java/org/apache/sling/servlethelpers/AdaptableUtil.java b/src/main/java/org/apache/sling/servlethelpers/AdaptableUtil.java
new file mode 100644
index 0000000..f7718cf
--- /dev/null
+++ b/src/main/java/org/apache/sling/servlethelpers/AdaptableUtil.java
@@ -0,0 +1,51 @@
+/*
+ * 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.servlethelpers;
+
+import java.lang.reflect.Field;
+
+import org.apache.sling.api.adapter.AdapterManager;
+import org.apache.sling.api.adapter.SlingAdaptable;
+
+final class AdaptableUtil {
+
+    public static <AdapterType> AdapterType adaptToWithoutCaching(Object adaptable, Class<AdapterType> type) {
+        AdapterManager adapterManager = getAdapterManager();
+        if (adapterManager == null) {
+            return null;
+        }
+        return adapterManager.getAdapter(adaptable, type);
+    }
+
+    /**
+     * Get adapter manager via reflection.
+     * @return Adapter manager instance
+     */
+    private static AdapterManager getAdapterManager() {
+        try {
+            Field adapterManagerStaticField = SlingAdaptable.class.getDeclaredField("ADAPTER_MANAGER");
+            adapterManagerStaticField.setAccessible(true);
+            return (AdapterManager)adapterManagerStaticField.get(null);
+        }
+        catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) {
+            throw new RuntimeException("Unable to get AdapterManager instance from SlingAdaptable via reflection.", ex);
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
index ffdb997..74d65e5 100644
--- a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
+++ b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequest.java
@@ -815,6 +815,11 @@
         this.authType = authType;
     }
 
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        return AdaptableUtil.adaptToWithoutCaching(this, type);
+    }
+
     // --- unsupported operations ---
 
     @Override
diff --git a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
index 9bba6f9..2f6d9f7 100644
--- a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
+++ b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
@@ -278,7 +278,12 @@
     public String geStatusMessage() {
         return this.getStatusMessage();
     }
-    
+
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        return AdaptableUtil.adaptToWithoutCaching(this, type);
+    }
+
     // --- unsupported operations ---
     @Override
     public String encodeRedirectUrl(String url) {
diff --git a/src/main/java/org/apache/sling/servlethelpers/package-info.java b/src/main/java/org/apache/sling/servlethelpers/package-info.java
index 8941ca5..2bbf9ae 100644
--- a/src/main/java/org/apache/sling/servlethelpers/package-info.java
+++ b/src/main/java/org/apache/sling/servlethelpers/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected Servlet-related Sling APIs.
  */
-@org.osgi.annotation.versioning.Version("1.6")
+@org.osgi.annotation.versioning.Version("1.7")
 package org.apache.sling.servlethelpers;
diff --git a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
index 843abd6..70ed9a3 100644
--- a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
+++ b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletRequestTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
@@ -39,6 +40,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
+import java.util.UUID;
 
 import javax.servlet.RequestDispatcher;
 import javax.servlet.http.Cookie;
@@ -46,16 +48,21 @@
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.CharEncoding;
+import org.apache.sling.api.adapter.AdapterManager;
+import org.apache.sling.api.adapter.SlingAdaptable;
 import org.apache.sling.api.request.RequestDispatcherOptions;
 import org.apache.sling.api.request.RequestParameter;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.servlets.HttpConstants;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MockSlingHttpServletRequestTest {
@@ -64,14 +71,22 @@
     private ResourceResolver resourceResolver;
     @Mock
     private Resource resource;
+    @Mock
+    private AdapterManager adapterManager;
 
     private MockSlingHttpServletRequest request;
 
     @Before
     public void setUp() throws Exception {
         request = new MockSlingHttpServletRequest(resourceResolver);
+        SlingAdaptable.setAdapterManager(adapterManager);
     }
-    
+
+    @After
+    public void tearDown() throws Exception {
+        SlingAdaptable.unsetAdapterManager(adapterManager);
+    }
+
     @Test
     public void testResourceResolver() {
         assertSame(resourceResolver, request.getResourceResolver());
@@ -504,5 +519,21 @@
         assertSame(resource, request.getRequestPathInfo().getSuffixResource());
     }
 
-    
+    @Test
+    public void testAdaptTo() {
+        when(adapterManager.getAdapter(request, String.class)).thenAnswer(new Answer<String>() {
+            @Override
+            public String answer(InvocationOnMock invocation) throws Throwable {
+                return UUID.randomUUID().toString();
+            }
+        });
+
+        // make sure adaptTo results are not cached; each invocation should produce a different result
+        String result1 = request.adaptTo(String.class);
+        assertNotNull(result1);
+
+        String result2 = request.adaptTo(String.class);
+        assertNotEquals(result1,  result2);
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
index 51c8df7..1800b22 100644
--- a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
+++ b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
@@ -21,28 +21,49 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.UUID;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.lang3.CharEncoding;
+import org.apache.sling.api.adapter.AdapterManager;
+import org.apache.sling.api.adapter.SlingAdaptable;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
 
+@RunWith(MockitoJUnitRunner.class)
 public class MockSlingHttpServletResponseTest {
 
     private MockSlingHttpServletResponse response;
 
+    @Mock
+    private AdapterManager adapterManager;
+
     @Before
     public void setUp() throws Exception {
         this.response = new MockSlingHttpServletResponse();
+        SlingAdaptable.setAdapterManager(adapterManager);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        SlingAdaptable.unsetAdapterManager(adapterManager);
     }
 
     @Test
@@ -200,4 +221,21 @@
         assertEquals(Locale.GERMAN, response.getLocale());
     }
 
+    @Test
+    public void testAdaptTo() {
+        when(adapterManager.getAdapter(response, String.class)).thenAnswer(new Answer<String>() {
+            @Override
+            public String answer(InvocationOnMock invocation) throws Throwable {
+                return UUID.randomUUID().toString();
+            }
+        });
+
+        // make sure adaptTo results are not cached; each invocation should produce a different result
+        String result1 = response.adaptTo(String.class);
+        assertNotNull(result1);
+
+        String result2 = response.adaptTo(String.class);
+        assertNotEquals(result1,  result2);
+    }
+
 }