/* * 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.ide.test.impl; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Arrays; import org.apache.sling.ide.eclipse.ui.nav.JcrContentContentProvider; import org.apache.sling.ide.eclipse.ui.nav.model.JcrNode; import org.apache.sling.ide.eclipse.ui.nav.model.SyncDir; import org.apache.sling.ide.test.impl.helpers.DisableDebugStatusHandlers; import org.apache.sling.ide.test.impl.helpers.ProjectAdapter; import org.apache.sling.ide.test.impl.helpers.TemporaryProject; import org.apache.sling.ide.util.PathUtil; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.Path; import org.junit.Before; import org.junit.Rule; import org.junit.Test; public class JcrContentContentProviderTest { @Rule public TemporaryProject projectRule = new TemporaryProject(); @Rule public DisableDebugStatusHandlers disableDebugHandlers = new DisableDebugStatusHandlers(); private IProject contentProject; private ProjectAdapter project; @Before public void prepareProject() throws Exception { contentProject = projectRule.getProject(); project = new ProjectAdapter(contentProject); project.addNatures("org.eclipse.wst.common.project.facet.core.nature"); // install content facet project.installFacet("sling.content", "1.0"); } @Test public void listChildrenInNestedStructure() throws Exception { // create .content.xml structure InputStream contentXml = getClass().getResourceAsStream("content-nested-structure.xml"); project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/test-root/en.xml"), contentXml); // directly create the root node SyncDir syncDirNode = new SyncDir((IFolder) contentProject.findMember("jcr_root")); // assertions assertIsNavigableAndHasNoChildren(syncDirNode, "/content/test-root/en/message"); assertIsNavigableAndHasNoChildren(syncDirNode, "/content/test-root/en/error"); assertIsNavigableAndHasNoChildren(syncDirNode, "/content/test-root/en/warning"); } @Test public void listChildrenWithNestedContentXmlInEscapedDir() throws Exception { // create .content.xml structure project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/.content.xml"), getClass() .getResourceAsStream("sling-folder-nodetype.xml")); project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/_sling_stuff/.content.xml"), getClass() .getResourceAsStream("nt-unstructured-nodetype.xml")); // directly create the root node SyncDir syncDirNode = new SyncDir((IFolder) contentProject.findMember("jcr_root")); // assertion assertIsNavigableAndHasNoChildren(syncDirNode, "/content/sling:stuff"); } @Test public void listChildrenWhenContentXmlIsBroken() throws Exception { // create .content.xml structure project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/.content.xml"), new ByteArrayInputStream( "invalid".getBytes())); project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/child1.txt"), new ByteArrayInputStream( "hello, world".getBytes())); project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/child2.txt"), new ByteArrayInputStream( "hello, world".getBytes())); // directly create the root node SyncDir syncDirNode = new SyncDir((IFolder) contentProject.findMember("jcr_root")); // assertions assertIsNavigableAndHasNoChildren(syncDirNode, "/content/child1.txt"); assertIsNavigableAndHasNoChildren(syncDirNode, "/content/child2.txt"); } @Test public void listChildrenOnNtFolderIncludedUnderJcrContentNode() throws Exception { // create .content.xml structure project.createOrUpdateFile(Path.fromPortableString("jcr_root/content/.content.xml"), getClass().getResourceAsStream("nt-unstructured-with-folder-child.xml")); // TODO - rename xml file project.ensureDirectoryExists(Path.fromPortableString("jcr_root/content/_jcr_content/first-folder/second-folder")); // directly create the root node SyncDir syncDirNode = new SyncDir((IFolder) contentProject.findMember("jcr_root")); // assertion assertIsNavigableAndHasNoChildren(syncDirNode, "/content/jcr:content/first-folder/second-folder"); } @Test public void listChildrenOnSyncDirIgnoresWebInfAndMetaInf() throws Exception { project.ensureDirectoryExists(Path.fromPortableString("jcr_root/WEB-INF")); project.ensureDirectoryExists(Path.fromPortableString("jcr_root/META-INF")); project.ensureDirectoryExists(Path.fromPortableString("jcr_root/content")); // directly create the root node SyncDir syncDirNode = new SyncDir((IFolder) contentProject.findMember("jcr_root")); // assertion Object[] children = new JcrContentContentProvider().getChildren(syncDirNode); assertThat(children.length, equalTo(1)); JcrNode child = (JcrNode) children[0]; assertThat(child.getName(), equalTo("content")); } /** * Asserts that the specified <tt>nodePath</tt> is reachable from the <tt>startNode</tt> * * <p>It further asserts that there are no children beyond the <tt>nodePath</tt>, i.e. it * is and endpoint</p> * * @param startNode the node to start from * @param nodePath the path that is reachable and an endpoint */ private void assertIsNavigableAndHasNoChildren(SyncDir startNode, String nodePath) { JcrContentContentProvider contentProvider = new JcrContentContentProvider(); if ( nodePath.charAt(0) == '/') { nodePath = nodePath.substring(1); } String[] pathElements = nodePath.split("/"); JcrNode current = startNode; segments: for ( int i = 0 ; i < pathElements.length ; i++ ) { String expectedChildName = pathElements[i]; Object[] children = contentProvider.getChildren(current); for ( Object child : children ) { JcrNode childNode = (JcrNode) child; // childNode.getName() does not seem to be usable here, so relying on the path String childName = PathUtil.getName(childNode.getJcrPath()); if ( childName.equals(expectedChildName)) { current = childNode; continue segments; } } fail("Unable to navigate to '" + nodePath + "'. " + " No child named '"+ expectedChildName +"'found for node at " + current.getJcrPath() + ", children: " + Arrays.toString(children)); } Object[] children = contentProvider.getChildren(current); if ( children.length != 0 ) { fail("Unexpected children for node at '" + current.getJcrPath() + "' : " + Arrays.toString(children)); } } }