/* * 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.commons.json.sling; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Iterator; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.JSONObject; import org.apache.sling.testing.mock.sling.junit.SlingContext; import org.junit.Before; import org.junit.Rule; import org.junit.Test; public class ResourceTraversorTest { private static final String RESOURCE_NAME = "R"; private static final String ID = "id"; // Before revision 1744381 the tests would fail with this set to 20'000 private final int MANY = Integer.getInteger("sling.test.ResourceTraversor.count", 100000); private final int FEW = 5; private final int LEVELS = 3; private Resource root; @Rule public final SlingContext context = new SlingContext(); private void addChildren(Resource parent, int resourcesPerLevel, int nLevels) throws PersistenceException { for(int i=0; i < resourcesPerLevel; i++) { final String id = makePath(nLevels, i); final Resource child = parent.getResourceResolver().create(parent, id, null); ModifiableValueMap vm = child.adaptTo(ModifiableValueMap.class); vm.put(ID, id); child.getResourceResolver().commit(); if(nLevels > 1) { addChildren(child, resourcesPerLevel, nLevels - 1); } } } private static String makePath(int nLevels, int index) { return RESOURCE_NAME + "_" + nLevels + "_" + index; } private String describe(JSONObject o) { int maxKeys = 5; final StringBuilder b = new StringBuilder(); b.append("JSONOBject having "); final Iterator<String> k = o.keys(); int count = 0; if(!k.hasNext()) { b.append("no properties"); } while(k.hasNext()) { b.append(k.next()).append(","); if(++count >= maxKeys) { b.append("..."); break; } } return b.toString(); } @Before public void setup() { root = null; } public void createTree(int resourcesPerLevel, int depth) throws PersistenceException { root = context.resourceResolver().getResource("/"); addChildren(root, resourcesPerLevel, depth); } @Test public void collectNLevelsNoLimit() throws JSONException, PersistenceException { createTree(FEW, LEVELS); ResourceTraversor traversor = new ResourceTraversor(-1, Integer.MAX_VALUE, root, true); traversor.collectResources(); assertTraversalResult(root.getPath(), traversor.getJSONObject(), FEW, LEVELS); } @Test public void collectNLevelsWithLimit() throws JSONException, PersistenceException { createTree(FEW, LEVELS); final String [] ids = { "R_3_0", "R_3_1" }; final int limit = ids.length; ResourceTraversor traversor = new ResourceTraversor(-1, limit, root, true); traversor.collectResources(); final int expectedCount = limit + 1; assertEquals(expectedCount, traversor.getCount()); final JSONObject jso = traversor.getJSONObject(); for(String id : ids) { assertTrue("Expecting " + id + " on " + describe(jso), jso.has(id)); } } @Test public void collectWithLimitInChildren() throws JSONException, PersistenceException { createTree(2, 2); final String [] ids = { "R_2_0", "R_2_1" }; final int limit = ids.length; ResourceTraversor traversor = new ResourceTraversor(-1, limit, root, true); traversor.collectResources(); final int expectedCount = limit + 1; assertEquals(expectedCount, traversor.getCount()); final JSONObject jso = traversor.getJSONObject(); for(String id : ids) { assertTrue("Expecting " + id + " on " + describe(jso), jso.has(id)); } } @Test public void collectOneLevelNoLimit() throws JSONException, PersistenceException { createTree(MANY, 1); ResourceTraversor traversor = new ResourceTraversor(1, MANY * 10, root, true); traversor.collectResources(); assertTraversalResult(root.getPath(), traversor.getJSONObject(), MANY, 1); assertEquals(MANY, traversor.getCount()); } @Test public void collectOneLevelLimitIgnoredAtLevelOne() throws JSONException, PersistenceException { createTree(MANY, 1); ResourceTraversor traversor = new ResourceTraversor(1, 1, root, true); traversor.collectResources(); assertTraversalResult(root.getPath(), traversor.getJSONObject(), MANY, 1); assertEquals(MANY, traversor.getCount()); } void assertTraversalResult(String parentPath, JSONObject jso, int childrenPerLevel, int nLevels) throws JSONException { for(int i=0; i < childrenPerLevel; i++) { final String key = makePath(nLevels, i); assertTrue("Expecting " + key + " on " + describe(jso), jso.has(key)); final JSONObject child = jso.getJSONObject(key); assertTrue("Expecting property " + ID, child.has(ID)); assertEquals("Expecting value " + key, key, child.get(ID)); if(nLevels > 1) { assertTraversalResult(key, child, childrenPerLevel, nLevels - 1); } } int keysCount = 0; final Iterator<String> k = jso.keys(); while(k.hasNext()) { k.next(); keysCount++; } // Sling mocks add an extra property assertEquals("Expecting " + childrenPerLevel + " keys on " + describe(jso), childrenPerLevel + 1, keysCount); } }