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

radu pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly-js-provider.git


The following commit(s) were added to refs/heads/master by this push:
     new 27356b3  SLING-12635 - JS Use Scripts should only be read on-demand
27356b3 is described below

commit 27356b32ef40cd2f466a1a7fb275f259c3dee510
Author: Radu Cotescu <[email protected]>
AuthorDate: Mon Jan 27 14:18:16 2025 +0100

    SLING-12635 - JS Use Scripts should only be read on-demand
    
    * added a test to show that the stream is already read when the
    DependencyResolver solves the ScriptNameAwareReader
    * added a test to show that the stream is already read when the
    SlyBindingsValuesProvider initialises the ScriptNameAwareReader;
    the reader needs to be read only when the JsEnvironment needs to
    compile/evaluate a script
    * read all scripts lazily, only when they really need to be loaded/reloaded
---
 pom.xml                                            |  26 +++-
 .../scripting/sightly/js/impl/JsEnvironment.java   |  13 +-
 .../js/impl/jsapi/SlyBindingsValuesProvider.java   |  61 +++++----
 .../sightly/js/impl/use/DependencyResolver.java    | 105 +++++++---------
 .../impl/jsapi/SlyBindingsValuesProviderTest.java  |  93 ++++++++++++++
 .../js/impl/use/DependencyResolverTest.java        | 138 +++++++++++++++++++++
 6 files changed, 336 insertions(+), 100 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4eab4b6..1e3244e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -134,12 +134,6 @@
             <version>3.5</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>2.4</version>
-            <scope>provided</scope>
-        </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
@@ -154,6 +148,26 @@
             <version>1.7.7.1_1</version>
             <scope>provided</scope>
         </dependency>
+
+        <!-- JUnit -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>5.11.3</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>5.11.3</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>5.11.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
index 8e36e8a..577d603 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/JsEnvironment.java
@@ -18,6 +18,8 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.js.impl;
 
+import java.io.Closeable;
+
 import javax.script.Bindings;
 import javax.script.Compilable;
 import javax.script.ScriptContext;
@@ -25,7 +27,6 @@ import javax.script.ScriptEngine;
 import javax.script.ScriptException;
 import javax.script.SimpleScriptContext;
 
-import org.apache.commons.io.IOUtils;
 import org.apache.sling.api.scripting.LazyBindings;
 import org.apache.sling.scripting.core.ScriptNameAwareReader;
 import org.apache.sling.scripting.sightly.SightlyException;
@@ -129,10 +130,18 @@ public class JsEnvironment {
             } catch (ScriptException e) {
                 throw new SightlyException(e);
             } finally {
-                IOUtils.closeQuietly(reader);
+                closeQuietly(reader);
             }
         });
     }
 
+    private void closeQuietly(Closeable closeable) {
+        try {
+            closeable.close();
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
 
 }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
index ba1314d..8bb98d0 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProvider.java
@@ -21,7 +21,6 @@ package org.apache.sling.scripting.sightly.js.impl.jsapi;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
@@ -32,7 +31,6 @@ import javax.script.Bindings;
 import javax.script.ScriptEngine;
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.commons.io.IOUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.scripting.LazyBindings;
@@ -90,13 +88,13 @@ public class SlyBindingsValuesProvider {
                         " dependency chain."
 
         )
-        String[] org_apache_sling_scripting_sightly_js_bindings() default 
"sightly:" + SlyBindingsValuesProvider.SLING_NS_PATH;
+        String[] org_apache_sling_scripting_sightly_js_bindings() default 
SlyBindingsValuesProvider.SLING_NS_PATH;
 
     }
 
     public static final String SCR_PROP_JS_BINDING_IMPLEMENTATIONS = 
"org.apache.sling.scripting.sightly.js.bindings";
 
-    public static final String SLING_NS_PATH = 
"/libs/sling/sightly/js/internal/sly.js";
+    public static final String SLING_NS_PATH = 
"sightly:/libs/sling/sightly/js/internal/sly.js";
     public static final String Q_PATH = 
"/libs/sling/sightly/js/3rd-party/q.js";
 
     private static final String REQ_NS = 
SlyBindingsValuesProvider.class.getCanonicalName();
@@ -145,12 +143,12 @@ public class SlyBindingsValuesProvider {
 
     @Activate
     protected void activate(Configuration configuration) {
-        String[] factories = PropertiesUtil.toStringArray(
+        String[] configuredFactories = PropertiesUtil.toStringArray(
                 configuration.org_apache_sling_scripting_sightly_js_bindings(),
                 new String[]{SLING_NS_PATH}
         );
-        scriptPaths = new LinkedHashMap<>(factories.length);
-        for (String f : factories) {
+        scriptPaths = new LinkedHashMap<>(configuredFactories.length);
+        for (String f : configuredFactories) {
             String[] parts = f.split(":");
             if (parts.length == 2) {
                 scriptPaths.put(parts[0], parts[1]);
@@ -197,24 +195,24 @@ public class SlyBindingsValuesProvider {
         if (resource == null) {
             throw new SightlyException("Sly namespace loader could not find 
the following script: " + path);
         }
-        try {
-            AsyncContainer container =
-                    jsEnvironment.runScript(
-                            new ScriptNameAwareReader(
-                                    new 
StringReader(IOUtils.toString(resource.adaptTo(InputStream.class), 
StandardCharsets.UTF_8)),
-                                    resource.getPath()
-                            ),
-                            createBindings(bindings, resource.getPath()),
-                            new LazyBindings()
-                    );
-            Object obj = container.getResult();
-            if (!(obj instanceof Function)) {
-                throw new SightlyException("Script " + path + " was expected 
to return a function.");
-            }
-            return (Function) obj;
-        } catch (IOException e) {
-            throw new SightlyException("Cannot read script " + path + " .");
+        InputStream inputStream = resource.adaptTo(InputStream.class);
+        if (inputStream == null) {
+            throw new SightlyException("Sly namespace loader could not read 
the following script: " + path);
         }
+        AsyncContainer container =
+                jsEnvironment.runScript(
+                        new ScriptNameAwareReader(
+                                new InputStreamReader(inputStream, 
StandardCharsets.UTF_8),
+                                resource.getPath()
+                        ),
+                        createBindings(bindings, resource.getPath()),
+                        new LazyBindings()
+                );
+        Object obj = container.getResult();
+        if (!(obj instanceof Function)) {
+            throw new SightlyException("Script " + path + " was expected to 
return a function.");
+        }
+        return (Function) obj;
     }
 
     private Bindings createBindings(Bindings global, String factoryPath) {
@@ -268,14 +266,12 @@ public class SlyBindingsValuesProvider {
         Context context = Context.enter();
         context.initStandardObjects();
         context.setOptimizationLevel(9);
-        InputStream reader = null;
-        try {
-            Resource resource = resolver.getResource(Q_PATH);
-            if (resource == null) {
-                LOGGER.warn("Could not load Q library at path: " + Q_PATH);
-                return null;
-            }
-            reader = resource.adaptTo(InputStream.class);
+        Resource resource = resolver.getResource(Q_PATH);
+        if (resource == null) {
+            LOGGER.warn("Could not load Q library at path: " + Q_PATH);
+            return null;
+        }
+        try (InputStream reader = resource.adaptTo(InputStream.class)) {
             if (reader == null) {
                 LOGGER.warn("Could not read content of Q library");
                 return null;
@@ -285,7 +281,6 @@ public class SlyBindingsValuesProvider {
             LOGGER.error("Unable to compile the Q library at path " + Q_PATH + 
".", e);
         } finally {
             Context.exit();
-            IOUtils.closeQuietly(reader);
         }
         return null;
     }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
index bfca8c8..ed3bd66 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolver.java
@@ -19,15 +19,13 @@
 
 package org.apache.sling.scripting.sightly.js.impl.use;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.nio.charset.StandardCharsets;
-
 import javax.script.Bindings;
 import javax.script.ScriptEngine;
 
-import org.apache.commons.io.IOUtils;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
@@ -56,71 +54,60 @@ public class DependencyResolver {
         if (!Utils.isJsScript(dependency)) {
             throw new SightlyException("Only JS scripts are allowed as 
dependencies. Invalid dependency: " + dependency);
         }
-        ScriptNameAwareReader reader = null;
-        IOException ioException = null;
-        try {
-            // attempt to retrieve the dependency directly (as an absolute 
path or relative to the search paths)
-            Resource scriptResource = 
scriptingResourceResolver.getResource(dependency);
-            Resource caller = getCaller(bindings);
-            if (caller != null) {
-                Resource callerType = caller.getParent();
-                if (scriptResource == null && callerType != null) {
-                    SlingHttpServletRequest request = 
(SlingHttpServletRequest) bindings.get(SlingBindings.REQUEST);
-                    String driverType = 
request.getResource().getResourceType();
-                    Resource driver = 
scriptingResourceResolver.getResource(driverType);
-                    if (driver != null) {
-                        Resource hierarchyResource = 
getHierarchyResource(callerType, driver);
-                        while (hierarchyResource != null && scriptResource == 
null) {
-                            if (dependency.startsWith("..")) {
-                                // relative path
-                                String absolutePath = 
ResourceUtil.normalize(hierarchyResource.getPath() + "/" + dependency);
-                                if (StringUtils.isNotEmpty(absolutePath)) {
-                                    scriptResource = 
scriptingResourceResolver.getResource(absolutePath);
-                                }
-                            } else {
-                                scriptResource = 
hierarchyResource.getChild(dependency);
-                            }
-                            if (scriptResource == null) {
-                                String nextType = 
hierarchyResource.getResourceSuperType();
-                                if (nextType != null) {
-                                    hierarchyResource = 
scriptingResourceResolver.getResource(nextType);
-                                } else {
-                                    hierarchyResource = null;
-                                }
-                            }
-                        }
-                    }
-                    // cannot find a dependency relative to the resource type; 
locate it solely based on the caller
-                    if (scriptResource == null) {
+        // attempt to retrieve the dependency directly (as an absolute path or 
relative to the search paths)
+        Resource scriptResource = 
scriptingResourceResolver.getResource(dependency);
+        Resource caller = getCaller(bindings);
+        if (caller != null) {
+            Resource callerType = caller.getParent();
+            if (scriptResource == null && callerType != null) {
+                SlingHttpServletRequest request = (SlingHttpServletRequest) 
bindings.get(SlingBindings.REQUEST);
+                String driverType = request.getResource().getResourceType();
+                Resource driver = 
scriptingResourceResolver.getResource(driverType);
+                if (driver != null) {
+                    Resource hierarchyResource = 
getHierarchyResource(callerType, driver);
+                    while (hierarchyResource != null && scriptResource == 
null) {
                         if (dependency.startsWith("..")) {
                             // relative path
-                            String absolutePath = 
ResourceUtil.normalize(callerType.getPath() + "/" + dependency);
+                            String absolutePath = 
ResourceUtil.normalize(hierarchyResource.getPath() + "/" + dependency);
                             if (StringUtils.isNotEmpty(absolutePath)) {
                                 scriptResource = 
scriptingResourceResolver.getResource(absolutePath);
                             }
                         } else {
-                            scriptResource = callerType.getChild(dependency);
+                            scriptResource = 
hierarchyResource.getChild(dependency);
+                        }
+                        if (scriptResource == null) {
+                            String nextType = 
hierarchyResource.getResourceSuperType();
+                            if (nextType != null) {
+                                hierarchyResource = 
scriptingResourceResolver.getResource(nextType);
+                            } else {
+                                hierarchyResource = null;
+                            }
                         }
                     }
                 }
+                // cannot find a dependency relative to the resource type; 
locate it solely based on the caller
+                if (scriptResource == null) {
+                    if (dependency.startsWith("..")) {
+                        // relative path
+                        String absolutePath = 
ResourceUtil.normalize(callerType.getPath() + "/" + dependency);
+                        if (StringUtils.isNotEmpty(absolutePath)) {
+                            scriptResource = 
scriptingResourceResolver.getResource(absolutePath);
+                        }
+                    } else {
+                        scriptResource = callerType.getChild(dependency);
+                    }
+                }
             }
-            if (scriptResource == null) {
-                throw new SightlyException(String.format("Unable to load 
script dependency %s.", dependency));
-            }
-            InputStream scriptStream = 
scriptResource.adaptTo(InputStream.class);
-            if (scriptStream == null) {
-                throw new SightlyException(String.format("Unable to read 
script %s.", dependency));
-            }
-            reader = new ScriptNameAwareReader(new 
StringReader(IOUtils.toString(scriptStream, StandardCharsets.UTF_8)),
-                    scriptResource.getPath());
-            IOUtils.closeQuietly(scriptStream);
-        } catch (IOException e) {
-            ioException = e;
         }
-        if (ioException != null) {
-            throw new SightlyException(String.format("Unable to load script 
dependency %s.", dependency), ioException);
+        if (scriptResource == null) {
+            throw new SightlyException(String.format("Unable to load script 
dependency %s.", dependency));
+        }
+        InputStream scriptStream = scriptResource.adaptTo(InputStream.class);
+        if (scriptStream == null) {
+            throw new SightlyException(String.format("Unable to read script 
%s.", dependency));
         }
-        return reader;
+        return new ScriptNameAwareReader(new InputStreamReader(scriptStream, 
StandardCharsets.UTF_8),
+                scriptResource.getPath());
     }
 
     private Resource getCaller(Bindings bindings) {
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProviderTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProviderTest.java
new file mode 100644
index 0000000..974b5b6
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/js/impl/jsapi/SlyBindingsValuesProviderTest.java
@@ -0,0 +1,93 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.scripting.sightly.js.impl.jsapi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+import javax.script.Bindings;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.scripting.core.ScriptNameAwareReader;
+import org.apache.sling.scripting.sightly.js.impl.JsEnvironment;
+import org.apache.sling.scripting.sightly.js.impl.async.AsyncContainer;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mozilla.javascript.Function;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class SlyBindingsValuesProviderTest {
+
+    @Mock
+    private ResourceResolver resolver;
+
+    @Mock
+    private Resource scriptResource;
+
+    @Mock
+    private SlyBindingsValuesProvider.Configuration configuration;
+
+    @Mock
+    private JsEnvironment jsEnvironment;
+
+    @Mock
+    private AsyncContainer asyncContainer;
+
+    @Mock
+    private Function function;
+
+    private InputStream inputStream;
+
+    @BeforeEach
+    void setUp() {
+        String scriptPath = 
SlyBindingsValuesProvider.SLING_NS_PATH.split(":")[1];
+        inputStream = 
spy(Objects.requireNonNull(getClass().getResourceAsStream("/SLING-INF" + 
scriptPath)));
+        when(scriptResource.getPath()).thenReturn(scriptPath);
+        when(resolver.getResource(scriptPath)).thenReturn(scriptResource);
+        
when(scriptResource.adaptTo(InputStream.class)).thenReturn(inputStream);
+        when(asyncContainer.getResult()).thenReturn(function);
+        when(jsEnvironment.runScript(any(ScriptNameAwareReader.class), 
any(Bindings.class), any(Bindings.class))).thenReturn(asyncContainer);
+    }
+
+    @Test
+    void testResourceLoading_streamNotRead() throws IOException {
+        assertNotNull(inputStream);
+        SlyBindingsValuesProvider provider = new SlyBindingsValuesProvider();
+        provider.activate(configuration);
+        provider.initialise(resolver, jsEnvironment, new SlingBindings());
+        verify(inputStream, never()).read();
+        verify(inputStream, never()).read(any(byte[].class));
+        verify(inputStream, never()).read(any(byte[].class), anyInt(), 
anyInt());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolverTest.java
 
b/src/test/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolverTest.java
new file mode 100644
index 0000000..3a2e060
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/js/impl/use/DependencyResolverTest.java
@@ -0,0 +1,138 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.scripting.sightly.js.impl.use;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.scripting.core.ScriptNameAwareReader;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class DependencyResolverTest {
+
+    private static final String CALLER_PATH = "/libs/caller/caller.html";
+    private static final String SCRIPT_PATH = "/libs/caller/caller.js";
+
+    @Mock
+    private ResourceResolver scriptingResourceResolver;
+
+    @Mock
+    private Resource caller;
+
+    @Mock
+    private Resource callerParent;
+
+    @Mock
+    private Resource dependency;
+
+    @Mock
+    private Resource content;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    private DependencyResolver dependencyResolver;
+    private Bindings bindings;
+
+
+    @BeforeEach
+    void beforeEach() {
+        when(dependency.getPath()).thenReturn(SCRIPT_PATH);
+        when(caller.getParent()).thenReturn(callerParent);
+        
when(scriptingResourceResolver.getResource(CALLER_PATH)).thenReturn(caller);
+        
when(scriptingResourceResolver.getResource(SCRIPT_PATH)).thenReturn(dependency);
+        dependencyResolver = new DependencyResolver(scriptingResourceResolver);
+        bindings = new SlingBindings();
+        bindings.put(ScriptEngine.FILENAME, CALLER_PATH);
+        bindings.put(SlingBindings.REQUEST, request);
+    }
+
+    @Test
+    void testResourceLoading_streamNotRead() throws IOException {
+        InputStream stream = mock(InputStream.class);
+
+        // Configure the mock to return data and simulate EOF
+        byte[] mockData = "mocked content".getBytes();
+        AtomicInteger readCount = new AtomicInteger(0);
+
+        // Simulate reading data and EOF
+        when(stream.read(any(), anyInt(), anyInt())).thenAnswer(invocation -> {
+            int offset = invocation.getArgument(1);
+            int length = invocation.getArgument(2);
+
+            // Check if there's data left to read
+            if (readCount.get() >= mockData.length) {
+                return -1; // Simulate EOF
+            }
+
+            // Simulate reading from the data
+            int bytesRead = Math.min(length, mockData.length - 
readCount.get());
+            System.arraycopy(mockData, readCount.get(), 
invocation.getArgument(0), offset, bytesRead);
+            readCount.addAndGet(bytesRead);
+            return bytesRead;
+        });
+
+        when(stream.read()).thenAnswer(invocation -> {
+            // Simulate single-byte reads
+            if (readCount.get() >= mockData.length) {
+                return -1; // Simulate EOF
+            }
+            return (int) mockData[readCount.getAndIncrement()];
+        });
+
+        when(dependency.adaptTo(InputStream.class)).thenReturn(stream);
+
+        ScriptNameAwareReader reader = dependencyResolver.resolve(bindings, 
SCRIPT_PATH);
+
+        assertNotNull(reader);
+        assertEquals(SCRIPT_PATH, reader.getScriptName());
+
+
+        verify(stream, never()).read(any(), anyInt(), anyInt());
+        verify(stream, never()).read();
+        verify(stream, never()).close();
+    }
+
+
+}

Reply via email to