You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/02/15 14:56:51 UTC

svn commit: r153936 - in incubator/jackrabbit/trunk: applications/test/ src/test/org/apache/jackrabbit/init/ src/test/org/apache/jackrabbit/test/ src/test/org/apache/jackrabbit/test/api/

Author: mreutegg
Date: Tue Feb 15 05:56:44 2005
New Revision: 153936

URL: http://svn.apache.org/viewcvs?view=rev&rev=153936
Log:
Adding more test cases for package javax.jcr.

Added:
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java   (with props)
Modified:
    incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/TestAll.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/TestAll.java

Modified: incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties?view=diff&r1=153935&r2=153936
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties (original)
+++ incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties Tue Feb 15 05:56:44 2005
@@ -5,6 +5,11 @@
 # Stub implementation class
 javax.jcr.tck.repository_stub_impl=org.apache.jackrabbit.test.JackrabbitRepositoryStub
 
+# repository name
+org.apache.jackrabbit.repository.config=applications/test/repository.xml
+org.apache.jackrabbit.repository.name=repo
+org.apache.jackrabbit.repository.home=applications/test
+
 # credential configuration
 javax.jcr.tck.superuser.name=superuser
 javax.jcr.tck.superuser.pwd=
@@ -33,7 +38,25 @@
 # Test method: testName
 javax.jcr.tck.AddNodeTest.testName.nodename1=myname
 
-# QUERY CONFIGURATION
+# ==============================================================================
+# JAVAX.JCR CONFIGURATION
+# ==============================================================================
+
+# Test class: ItemDefTest
+javax.jcr.tck.ItemDefTest.testroot=/
+
+# Test class: ItemReadMethodsTest
+javax.jcr.tck.ItemReadMethodsTest.testroot=/
+
+# Test class: NodeReadMethodsTest
+javax.jcr.tck.NodeReadMethodsTest.testroot=/
+
+# Test class: PropertyTypeTest
+javax.jcr.tck.PropertyTypeTest.testroot=/
+
+# ==============================================================================
+# JAVAX.JCR.QUERY CONFIGURATION
+# ==============================================================================
 
 # Test class: SaveTest
 # Test method: testConstraintViolationException
@@ -64,7 +87,9 @@
 # Test class: SQLOrderByTest
 javax.jcr.tck.SQLOrderByTest.testroot=/testdata/query
 
-# VERSIONING CONFIGURATION
+# ==============================================================================
+# JAVAX.JCR.VERSIONING CONFIGURATION
+# ==============================================================================
 
 # nodetye that is versionable. if it is not, an attempt is made to create versionable nodes
 # by adding a mix:versionable mixin-type.
@@ -116,8 +141,3 @@
 # Test class: MergeNodeTest
 javax.jcr.tck.MergeNodeTest.nodetype=test:versionable
 
-
-# repository name
-org.apache.jackrabbit.repository.config=applications/test/repository.xml
-org.apache.jackrabbit.repository.name=repo
-org.apache.jackrabbit.repository.home=applications/test

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java?view=auto&rev=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java Tue Feb 15 05:56:44 2005
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.jackrabbit.init;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import java.util.StringTokenizer;
+import java.util.Calendar;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+/**
+ * Sets up test data required for level 1 node test cases.
+ */
+public class NodeTestData extends AbstractJCRTest {
+
+    /** Path pointing to the test root */
+    private static final String TEST_DATA_PATH = "testdata/node";
+
+    /** Resolved QName for nt:resource */
+    private String ntResource;
+
+    /** Resolved QName for jcr:encoding */
+    private String jcrEncoding;
+
+    /** Resolved QName for jcr:mimeType */
+    private String jcrMimeType;
+
+    /** Resolved QName for jcr:data */
+    private String jcrData;
+
+    /** Resolved QName for jcr:lastModified */
+    private String jcrLastModified;
+
+    /**
+     * Sets up the fixture for this test.
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        ntResource = superuser.getNamespacePrefix(NS_NT_URI) + ":resource";
+        jcrEncoding = superuser.getNamespacePrefix(NS_JCR_URI) + ":encoding";
+        jcrMimeType = superuser.getNamespacePrefix(NS_JCR_URI) + ":mimeType";
+        jcrData = superuser.getNamespacePrefix(NS_JCR_URI) + ":data";
+        jcrLastModified = superuser.getNamespacePrefix(NS_JCR_URI) + ":lastModified";
+    }
+
+    /**
+     * Creates two nodes under {@link #TEST_DATA_PATH}: one of type
+     * nt:resource and a second node referencing the first.
+     */
+    public void testFillInSearchData() throws RepositoryException, IOException {
+        if (superuser.getRootNode().hasNode(TEST_DATA_PATH)) {
+            // delete previous data
+            superuser.getRootNode().getNode(TEST_DATA_PATH).remove();
+            superuser.save();
+        }
+        // create nodes to testPath
+        StringTokenizer names = new StringTokenizer(TEST_DATA_PATH, "/");
+        Node dataRoot = superuser.getRootNode();
+        while (names.hasMoreTokens()) {
+            String name = names.nextToken();
+            if (!dataRoot.hasNode(name)) {
+                dataRoot = dataRoot.addNode(name, testNodeType);
+            } else {
+                dataRoot = dataRoot.getNode(name);
+            }
+        }
+
+        Node resource = dataRoot.addNode("myResource", ntResource);
+        resource.setProperty(jcrEncoding, "ISO-8859-1");
+        resource.setProperty(jcrMimeType, "text/plain");
+        ByteArrayOutputStream data = new ByteArrayOutputStream();
+        OutputStreamWriter writer = new OutputStreamWriter(data, "ISO-8859-1");
+        writer.write("Hello world.");
+        writer.close();
+        resource.setProperty(jcrData, new ByteArrayInputStream(data.toByteArray()));
+        resource.setProperty(jcrLastModified, Calendar.getInstance());
+        log.println("Adding node: " + resource.getPath());
+
+        Node resReference = dataRoot.addNode("reference");
+        resReference.setProperty("ref", resource);
+        log.println("Adding node: " + resReference.getPath());
+
+        superuser.save();
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/TestAll.java?view=diff&r1=153935&r2=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/TestAll.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/TestAll.java Tue Feb 15 05:56:44 2005
@@ -38,6 +38,7 @@
         TestSuite suite = new TestSuite("Setup data for tests");
 
         suite.addTestSuite(QueryTestData.class);
+        suite.addTestSuite(NodeTestData.class);
 
         return suite;
     }

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java?view=diff&r1=153935&r2=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/AbstractJCRTest.java Tue Feb 15 05:56:44 2005
@@ -233,10 +233,14 @@
         }
 
         if (isReadOnly) {
-            if (!superuser.getRootNode().hasNode(testPath)) {
+            if (testPath.length() == 0) {
+                // test root is the root node
+                testRootNode = superuser.getRootNode();
+            } else if (!superuser.getRootNode().hasNode(testPath)) {
                 fail("Workspace does not contain test data at: " + testRoot);
+            } else {
+                testRootNode = superuser.getRootNode().getNode(testPath);
             }
-            testRootNode = superuser.getRootNode().getNode(testPath);
         } else {
             Node root = superuser.getRootNode();
             if (root.hasNode(testPath)) {

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java?view=auto&rev=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java Tue Feb 15 05:56:44 2005
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.jackrabbit.test.api;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDef;
+import javax.jcr.nodetype.NodeDef;
+
+/**
+ * This test checks if item definitions with mandatory constraints are
+ * respected.
+ * <p/>
+ * If the default workspace does not contain a node with a node type definition
+ * that specifies a mandatory child node a {@link NotExecutableException} is
+ * thrown. If the default workspace does not contain a node with a node type
+ * definition that specifies a mandatory property a {@link NotExecutableException}
+ * is thrown.
+ *
+ * @test
+ * @sources ItemDefTest.java
+ * @executeClass org.apache.jackrabbit.test.api.ItemDefTest
+ * @keywords level1
+ */
+public class ItemDefTest extends AbstractJCRTest {
+
+    /** If <code>true</code> indicates that the test found a mandatory node */
+    private boolean foundMandatoryNode = false;
+
+    /** If <code>true</code> indicates that the test found a mandatory property */
+    private boolean foundMandatoryProperty = false;
+
+    /**
+     * Sets up the fixture for this test.
+     */
+    protected void setUp() throws Exception {
+        isReadOnly = true;
+        super.setUp();
+    }
+
+    /**
+     * Tests if a node's mandatory properties and nodes are legally set. The
+     * information which properties and nodes are mandatory is taken from the
+     * node's primary and mixin node types. This test runs recursively through
+     * the entire repository.
+     */
+    public void testIsMandatory() throws RepositoryException, NotExecutableException {
+        //Session session=superuser;
+        Session session = helper.getReadOnlySession();
+        Node root = session.getRootNode();
+        traverse(root);
+        if (!foundMandatoryNode) {
+            throw new NotExecutableException("Workspace does not contain any node with a mandatory child node definition");
+        }
+        if (!foundMandatoryProperty) {
+            throw new NotExecutableException("Workspace does not contain any node with a mandatory property definition");
+        }
+    }
+
+    /**
+     * Traverses the node hierarchy and applies {@link #checkMandatoryConstraint(javax.jcr.Node, javax.jcr.nodetype.NodeType)}
+     * to all descendant nodes of <code>parentNode</code>.
+     */
+    private void traverse(Node parentNode)
+            throws RepositoryException {
+
+        NodeIterator nodes = parentNode.getNodes();
+        while (nodes.hasNext()) {
+            Node node = nodes.nextNode();
+
+            NodeType primeType = node.getPrimaryNodeType();
+            checkMandatoryConstraint(node, primeType);
+
+            NodeType mixins[] = node.getMixinNodeTypes();
+            for (int i = 0; i < mixins.length; i++) {
+                checkMandatoryConstraint(node, mixins[i]);
+            }
+
+            traverse(node);
+        }
+    }
+
+    /**
+     * Checks if mandatory node / property definitions are respected.
+     */
+    private void checkMandatoryConstraint(Node node, NodeType type)
+            throws RepositoryException {
+
+        // test if node contains all mandatory properties of current type
+        PropertyDef propDefs[] = type.getPropertyDefs();
+        for (int i = 0; i < propDefs.length; i++) {
+            PropertyDef propDef = propDefs[i];
+
+            if (propDef.isMandatory()) {
+                foundMandatoryProperty = true;
+                String name = propDef.getName();
+
+                try {
+                    Property p = node.getProperty(name);
+                    if (propDef.isMultiple()) {
+                        // empty array fails
+                        assertFalse("A mandatory and multiple property " +
+                                "must not be empty.",
+                                p.getValues().length == 0);
+                    } else {
+                        // empty value fails
+                        assertNotNull("A mandatory property must have a value",
+                                p.getValue());
+                    }
+                } catch (PathNotFoundException e) {
+                    fail("Mandatory property " + name + " does not exist.");
+                }
+            }
+        }
+
+        // test if node contains all mandatory nodes of current type
+        NodeDef nodeDefs[] = type.getChildNodeDefs();
+        for (int i = 0; i < nodeDefs.length; i++) {
+            NodeDef nodeDef = nodeDefs[i];
+            if (nodeDef.isMandatory()) {
+                foundMandatoryNode = true;
+                try {
+                    node.getNode(nodeDef.getName());
+                } catch (PathNotFoundException e) {
+                    fail("Mandatory child " + nodeDef.getName() + " for " + node.getPath() + " does not exist.");
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemDefTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java?view=auto&rev=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java Tue Feb 15 05:56:44 2005
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.jackrabbit.test.api;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.Session;
+import javax.jcr.Item;
+import javax.jcr.Property;
+import javax.jcr.NodeIterator;
+import javax.jcr.Node;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.ItemNotFoundException;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests the 'read' methods specified in the {@link javax.jcr.Item} interface
+ * on a level 1 repository.
+ * <p/>
+ * The root node of the default workspace must have at least one child node,
+ * otherwise a {@link org.apache.jackrabbit.test.NotExecutableException} is
+ * thrown.
+ *
+ * @test
+ * @sources ItemReadMethodsTest.java
+ * @executeClass org.apache.jackrabbit.test.api.ItemReadMethodsTest
+ * @keywords level1
+ */
+public class ItemReadMethodsTest extends AbstractJCRTest {
+
+    /** Session to access the workspace */
+    private Session session;
+
+    /** The primary test item */
+    private Item item;
+
+    /** A child item of the primary test item */
+    private Item childItem;
+
+    /** A property of the primary test item */
+    private Property childProperty;
+
+    /**
+     * Sets up the fixture for this test.
+     */
+    protected void setUp() throws Exception {
+        isReadOnly = true;
+        super.setUp();
+
+        session = helper.getReadOnlySession();
+        item = session.getRootNode();
+
+        NodeIterator nodes = ((Node) item).getNodes();
+        try {
+            childItem = nodes.nextNode();
+        } catch (NoSuchElementException e) {
+            throw new NotExecutableException("Workspace does not have sufficient content to run this test.");
+        }
+
+        PropertyIterator properties = ((Node) item).getProperties();
+        try {
+            childProperty = properties.nextProperty();
+        } catch (NoSuchElementException e) {
+            fail("Any node must have at least one property set: jcr:primaryType");
+        }
+    }
+
+    /**
+     * Tests if getPath() returns the correct path.
+     */
+    public void testGetPath() throws RepositoryException {
+        String path = childItem.getPath();
+        String notation = "";
+
+        try {
+            // check for same named sibling of childItem
+            ((Node) item).getNode(childItem.getName() + "[2]");
+            notation = "[1]";
+        } catch (PathNotFoundException e) {
+        }
+
+        if (path.indexOf("[") != -1) {
+            notation = path.substring(path.indexOf("["));
+        }
+        assertEquals("getPath returns wrong result",
+                "/" + childItem.getName() + notation,
+                childItem.getPath());
+    }
+
+    /**
+     * Tests if getName() returns same as last name returned by getPath()
+     */
+    public void testGetName() throws RepositoryException {
+        assertEquals("getName() of root must be an empty string",
+                "",
+                item.getName());
+
+        // build name from path
+        String path = childItem.getPath();
+        String name = path.substring(path.lastIndexOf("/") + 1);
+        if (name.indexOf("[") != -1) {
+            name = name.substring(0, name.indexOf("["));
+        }
+        assertEquals("getName() must be the same as the last item in the path",
+                name,
+                childItem.getName());
+    }
+
+    /**
+     * Tests if getItem(x).getParent() is item itself
+     */
+    public void testGetParent() throws RepositoryException {
+        assertSame("getParent() of a child item must be the item itself.",
+                item, childItem.getParent());
+    }
+
+    /**
+     * Tests if getParent() of root throws an ItemNotFoundException
+     */
+    public void testGetParentOfRoot() throws RepositoryException {
+        try {
+            item.getParent();
+            fail("getParent() of root must throw an ItemNotFoundException.");
+        } catch (ItemNotFoundException e) {
+            // success
+        }
+    }
+
+    /**
+     * Tests if depth of root is 0 and depth of a sub item of root is 1
+     */
+    public void testGetDepth() throws RepositoryException {
+        assertEquals("getDepth() of root must be 0", 0, item.getDepth());
+        assertEquals("getDepth() of child item of root must be 1", 1,
+                childItem.getDepth());
+    }
+
+    /**
+     * Tests if getSession() is same as through which the Item was acquired
+     */
+    public void testGetSession() throws RepositoryException {
+        assertSame("getSession must return the Session through which " +
+                "the Item was acquired.",
+                item.getSession(),
+                session);
+    }
+
+    /**
+     * Tests if isNode() returns true if the Item is a node and false if it is a
+     * property
+     */
+    public void testIsNode() {
+        assertTrue("isNode() must return true if Item is a node.",
+                childItem.isNode());
+        assertFalse("isNode() must return false if Item is a property.",
+                childProperty.isNode());
+    }
+
+    /**
+     * Tests if isSame() returns true when retrieving an item through different
+     * sessions
+     */
+    public void testIsSame() throws RepositoryException {
+        assertFalse("isSame(Item item) must return false for different items.",
+                item.isSame(childItem));
+
+        // access same item (root) through different session
+        Item otherItem = helper.getReadOnlySession().getRootNode();
+        assertTrue("isSame(Item item) must return true for the same " +
+                "item retrieved through different sessions.",
+                item.isSame(otherItem));
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/ItemReadMethodsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java?view=auto&rev=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java Tue Feb 15 05:56:44 2005
@@ -0,0 +1,832 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.jackrabbit.test.api;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+import javax.jcr.RepositoryException;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyIterator;
+import javax.jcr.Property;
+import javax.jcr.Item;
+import javax.jcr.PropertyType;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ItemNotFoundException;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests the 'read' methods specified in the {@link javax.jcr.Node} interface
+ * on a level 1 repository.
+ * <p/>
+ * Most tests require at least one child node under the root node, otherwise
+ * a {@link org.apache.jackrabbit.test.NotExecutableException} is thrown.
+ *
+ * @test
+ * @sources NodeReadMethodsTest.java
+ * @executeClass org.apache.jackrabbit.test.api.NodeReadMethodsTest
+ * @keywords level1
+ */
+public class NodeReadMethodsTest extends AbstractJCRTest {
+
+    /**
+     * The root node of the default workspace
+     */
+    Node rootNode;
+
+    /**
+     * Sets up the fixture for this test.
+     */
+    protected void setUp() throws Exception {
+        isReadOnly = true;
+        super.setUp();
+        Session session = helper.getReadOnlySession();
+        rootNode = session.getRootNode();
+    }
+
+    /**
+     * Test if getNode(String relPath) returns the correct node and if a
+     * PathNotFoundException is thrown when Node at relPath does not exist
+     */
+    public void testGetNode()
+            throws NotExecutableException, RepositoryException {
+
+        StringBuffer notExistingPath = new StringBuffer("X");
+        NodeIterator nodes = rootNode.getNodes();
+        while (nodes.hasNext()) {
+            // build a path that for sure is not existing
+            // (":" of namespace prefix will be replaced later on)
+            notExistingPath.append(nodes.nextNode().getName());
+        }
+
+        try {
+            rootNode.getNode(notExistingPath.toString().replaceAll(":", ""));
+            fail("getNode(String relPath) must throw a PathNotFoundException" +
+                    "if no node exists at relPath");
+        } catch (PathNotFoundException e) {
+            // success
+        }
+
+        try {
+            NodeIterator nodes2 = rootNode.getNodes();
+            Node node = nodes2.nextNode();
+            assertSame(rootNode.getNode(node.getName()), node);
+        } catch (NoSuchElementException e) {
+            throw new NotExecutableException("Workspace does not have sufficient content for this test. Root node must have at least one child node.");
+        }
+    }
+
+    /**
+     * Test if all returned items are of type node.
+     */
+    public void testGetNodes() throws RepositoryException {
+        NodeIterator nodes = rootNode.getNodes();
+        while (nodes.hasNext()) {
+            Item item = (Item) nodes.next();
+            assertTrue("Item is not a node", item.isNode());
+        }
+    }
+
+    /**
+     * Test getNodes(String namePattern) with all possible patterns. Tested
+     * node: root - NotExecutableException is thrown when root node has no sub
+     * nodes.
+     */
+    public void testGetNodesNamePattern()
+            throws NotExecutableException, RepositoryException {
+
+        // get root node and build an ArrayList of its sub nodes
+        Node node = rootNode;
+        if (!node.hasNodes()) {
+            throw new NotExecutableException("Workspace does not have sufficient content for this test. Root node must have at least one child node.");
+        }
+        NodeIterator allNodesIt = node.getNodes();
+        ArrayList allNodes = new ArrayList();
+        while (allNodesIt.hasNext()) {
+            Node n = allNodesIt.nextNode();
+            allNodes.add(n);
+        }
+
+
+        // test if an empty NodeIterator is returned
+        // when the pattern is not matching any child node
+        String pattern0 = "";
+        NodeIterator nodes0 = node.getNodes(pattern0);
+        try {
+            nodes0.nextNode();
+            fail("An empty NodeIterator must be returned if pattern does" +
+                    "not match any child node.");
+        } catch (NoSuchElementException e) {
+            // success
+        }
+
+
+        // all further tests are using root's first sub node
+        Node firstNode = (Node) allNodes.get(0);
+
+
+        // test pattern "*"
+        String pattern1 = "*";
+        String assertString1 = "node.getNodes(\"" + pattern1 + "\"): ";
+        NodeIterator nodes1 = node.getNodes(pattern1);
+        int numOfNodes1 = 0;
+        // test if the number of found nodes is correct
+        while (nodes1.hasNext()) {
+            nodes1.nextNode();
+            numOfNodes1++;
+        }
+        assertEquals(assertString1 + "number of nodes found: ",
+                allNodes.size(),
+                numOfNodes1);
+
+
+        // test pattern "nodeName"
+        String pattern2 = firstNode.getName();
+        String assertString2 = "node.getNodes(\"" + pattern2 + "\"): ";
+        int numOfNodes2 = 0;
+        // test if the names of the found nodes are matching the pattern
+        NodeIterator nodes2 = node.getNodes(pattern2);
+        while (nodes2.hasNext()) {
+            Node n = nodes2.nextNode();
+            assertEquals(assertString2 + "name comparison failed: ",
+                    firstNode.getName(),
+                    n.getName());
+            numOfNodes2++;
+        }
+        // test if the number of found nodes is correct
+        int numExpected2 = 0;
+        for (int i = 0; i < allNodes.size(); i++) {
+            Node n = (Node) allNodes.get(i);
+            if (n.getName().equals(firstNode.getName())) {
+                numExpected2++;
+            }
+        }
+        assertEquals(assertString2 + "number of nodes found: ",
+                numExpected2,
+                numOfNodes2);
+
+
+        // test pattern "nodeName | nodeName"
+        String pattern3 = firstNode.getName() + " | " + firstNode.getName();
+        String assertString3 = "node.getNodes(\"" + pattern3 + "\"): ";
+        int numOfNodes3 = 0;
+        // test if the names of the found nodes are matching the pattern
+        NodeIterator nodes3 = node.getNodes(pattern3);
+        while (nodes3.hasNext()) {
+            Node n = nodes3.nextNode();
+            assertEquals(assertString2 + "name comparison failed: ",
+                    firstNode.getName(),
+                    n.getName());
+            numOfNodes3++;
+        }
+        // test if the number of found nodes is correct
+        int numExpected3 = 0;
+        for (int i = 0; i < allNodes.size(); i++) {
+            Node n = (Node) allNodes.get(i);
+            if (n.getName().equals(firstNode.getName())) {
+                numExpected3++;
+            }
+        }
+        assertEquals(assertString3 + "number of nodes found: ",
+                numExpected3,
+                numOfNodes3);
+
+
+        // test pattern "*odeNam*"
+        if (firstNode.getName().length() > 2) {
+            String name = firstNode.getName();
+            String shortenName = name.substring(1, name.length() - 1);
+            String pattern4 = "*" + shortenName + "*";
+            String assertString4 = "node.getNodes(\"" + pattern4 + "\"): ";
+            int numOfNodes4 = 0;
+            // test if the names of the found nodes are matching the pattern
+            NodeIterator nodes4 = node.getNodes(pattern4);
+            while (nodes4.hasNext()) {
+                Node n = nodes4.nextNode();
+                assertTrue(assertString4 + "name comparison failed: *" +
+                        shortenName + "* not found in " + n.getName(),
+                        n.getName().indexOf(shortenName) != -1);
+                numOfNodes4++;
+            }
+            // test if the number of found nodes is correct
+            int numExpected4 = 0;
+            for (int i = 0; i < allNodes.size(); i++) {
+                Node n = (Node) allNodes.get(i);
+                if (n.getName().indexOf(shortenName) != -1) {
+                    numExpected4++;
+                }
+            }
+            assertEquals(assertString4 + "number of nodes found: ",
+                    numExpected4,
+                    numOfNodes4);
+        }
+    }
+
+    /**
+     * Test if getProperty(String relPath) returns the correct node and if a
+     * PathNotFoundException is thrown when property at relPath does not exist
+     */
+    public void testGetProperty()
+            throws NotExecutableException, RepositoryException {
+        StringBuffer notExistingPath = new StringBuffer("X");
+        PropertyIterator properties = rootNode.getProperties();
+        while (properties.hasNext()) {
+            // build a path that for sure is not existing
+            // (":" of namespace prefix will be replaced later on)
+            notExistingPath.append(properties.nextProperty().getName());
+        }
+
+        try {
+            rootNode.getProperty(notExistingPath.toString().replaceAll(":", ""));
+            fail("getProperty(String relPath) must throw a " +
+                    "PathNotFoundException if no node exists at relPath");
+        } catch (PathNotFoundException e) {
+            // success
+        }
+
+        try {
+            PropertyIterator properties2 = rootNode.getProperties();
+            Property property = properties2.nextProperty();
+            assertSame(rootNode.getProperty(property.getName()), property);
+        } catch (NoSuchElementException e) {
+            fail("Root node must always have at least one property: jcr:primaryType");
+        }
+    }
+
+    /**
+     * Test if all returned items are of type node.
+     */
+    public void testGetProperties() throws RepositoryException {
+        PropertyIterator properties = rootNode.getProperties();
+        while (properties.hasNext()) {
+            Item item = (Item) properties.next();
+            assertFalse("Item is not a property", item.isNode());
+        }
+    }
+
+    /**
+     * Test getProperties(String namePattern) with all possible patterns. Tested
+     * node: root - a NotExecutableException is thrown when root node has no
+     * properties.
+     */
+    public void testGetPropertiesNamePattern()
+            throws NotExecutableException, RepositoryException {
+
+        // get root node and build an ArrayList of its sub nodes
+        Node node = rootNode;
+        if (!node.hasProperties()) {
+            fail("Root node must always have at least one property: jcr:primaryType");
+        }
+        PropertyIterator allPropertiesIt = node.getProperties();
+        ArrayList allProperties = new ArrayList();
+        StringBuffer notExistingPropertyName = new StringBuffer();
+        while (allPropertiesIt.hasNext()) {
+            Property p = allPropertiesIt.nextProperty();
+            allProperties.add(p);
+            notExistingPropertyName.append(p.getName() + "X");
+        }
+
+
+        // test that an empty NodeIterator is returned
+        // when the pattern is not matching any child node
+        String pattern0 = notExistingPropertyName.toString();
+        NodeIterator properties0 = node.getNodes(pattern0);
+        try {
+            properties0.nextNode();
+            fail("An empty NodeIterator must be returned if pattern does" +
+                    "not match any child node.");
+        } catch (NoSuchElementException e) {
+            // success
+        }
+
+        // all tests are running using root's first property
+        Property firstProperty = (Property) allProperties.get(0);
+
+        // test: getProperties("*")
+        String pattern1 = "*";
+        String assertString1 = "node.getProperties(\"" + pattern1 + "\"): ";
+        PropertyIterator properties1 = node.getProperties(pattern1);
+        int numOfProperties1 = 0;
+        while (properties1.hasNext()) {
+            properties1.nextProperty();
+            numOfProperties1++;
+        }
+        assertEquals(assertString1 + "number of properties found: ",
+                allProperties.size(),
+                numOfProperties1);
+
+        // test: getProperties("propertyName")
+        String pattern2 = firstProperty.getName();
+        String assertString2 = "node.getProperties(\"" + pattern2 + "\"): ";
+        int numOfProperties2 = 0;
+        // test if the names of the found properties are matching the pattern
+        PropertyIterator properties2 = node.getProperties(pattern2);
+        while (properties2.hasNext()) {
+            Property p = properties2.nextProperty();
+            assertEquals(assertString2 + "name comparison failed: ",
+                    firstProperty.getName(),
+                    p.getName());
+            numOfProperties2++;
+        }
+        // test if the number of found properties is correct
+        int numExpected2 = 0;
+        for (int i = 0; i < allProperties.size(); i++) {
+            Property p = (Property) allProperties.get(i);
+            if (p.getName().equals(firstProperty.getName())) {
+                numExpected2++;
+            }
+        }
+        assertEquals(assertString2 + "number of properties found: ",
+                numExpected2,
+                numOfProperties2);
+
+
+        // test: getProperties("propertyName | propertyName")
+        String pattern3 = firstProperty.getName() + " | " + firstProperty.getName();
+        String assertString3 = "node.getProperties(\"" + pattern3 + "\"): ";
+        int numOfProperties3 = 0;
+        // test if the names of the found properties are matching the pattern
+        PropertyIterator properties3 = node.getProperties(pattern3);
+        while (properties3.hasNext()) {
+            Property p = properties3.nextProperty();
+            assertEquals(assertString2 + "name comparison failed: ",
+                    firstProperty.getName(),
+                    p.getName());
+            numOfProperties3++;
+        }
+        // test if the number of found properties is correct
+        int numExpected3 = 0;
+        for (int i = 0; i < allProperties.size(); i++) {
+            Property p = (Property) allProperties.get(i);
+            if (p.getName().equals(firstProperty.getName())) {
+                numExpected3++;
+            }
+        }
+        assertEquals(assertString3 + "number of properties found: ",
+                numExpected3,
+                numOfProperties3);
+
+
+        // test: getProperties("*opertyNam*")
+        if (firstProperty.getName().length() > 2) {
+            String name = firstProperty.getName();
+            String shortenName = name.substring(1, name.length() - 1);
+            String pattern4 = "*" + shortenName + "*";
+            String assertString4 = "node.getProperties(\"" + pattern4 + "\"): ";
+            int numOfProperties4 = 0;
+            // test if the names of the found properties are matching the pattern
+            PropertyIterator properties4 = node.getProperties(pattern4);
+            while (properties4.hasNext()) {
+                Property p = properties4.nextProperty();
+                assertTrue(assertString4 + "name comparison failed: *" +
+                        shortenName + "* not found in " + p.getName(),
+                        p.getName().indexOf(shortenName) != -1);
+                numOfProperties4++;
+            }
+            // test if the number of found properties is correct
+            int numExpected4 = 0;
+            for (int i = 0; i < allProperties.size(); i++) {
+                Property p = (Property) allProperties.get(i);
+                if (p.getName().indexOf(shortenName) != -1) {
+                    numExpected4++;
+                }
+            }
+            assertEquals(assertString4 + "number of properties found: ",
+                    numExpected4,
+                    numOfProperties4);
+        }
+    }
+
+    /**
+     * Test if getPrimaryItem returns the primary item as defined in the primary
+     * node type. Therefor a node with a primary item is located recursively in
+     * the entire repository. A NotExecutableException is thrown when no such
+     * node is found.
+     */
+    public void testGetPrimaryItem()
+            throws NotExecutableException, RepositoryException {
+        Node node = locateNodeWithPrimaryItem(rootNode);
+        String primaryItemName = node.getPrimaryNodeType().getPrimaryItemName();
+
+        if (primaryItemName == null) {
+            throw new NotExecutableException("Workspace does not contain a node with primary item defined");
+        }
+
+        Item primaryItem = node.getPrimaryItem();
+        if (primaryItem.isNode()) {
+            assertSame(primaryItem, node.getNode(primaryItemName));
+        } else {
+            assertSame(primaryItem, node.getProperty(primaryItemName));
+        }
+    }
+
+    /**
+     * Test if getPrimaryItem does throw an ItemNotFoundException if the primary
+     * node type does not define a primary item. Therefor a node without a
+     * primary item is located recursively in the entire repository. A
+     * NotExecutableException is thrown when no such node is found.
+     */
+    public void testGetPrimaryItemItemNotFoundException()
+            throws NotExecutableException, RepositoryException {
+
+        Node node = locateNodeWithoutPrimaryItem(rootNode);
+
+        String primaryItemName = node.getPrimaryNodeType().getPrimaryItemName();
+
+        if (primaryItemName != null) {
+            throw new NotExecutableException("Workspace does not contain a node with primary item defined");
+        }
+
+        try {
+            node.getPrimaryItem();
+            fail("getPrimaryItem() must throw a ItemNotFoundException " +
+                    "if the primary node type does not define one");
+        } catch (ItemNotFoundException e) {
+            // success
+        }
+    }
+
+    /**
+     * Test if getIndex() returns the correct index. Therefor a node with same
+     * name sibling is located recursively in the entire repository. If no such
+     * node is found, the test checks if the rootNode returns 1
+     */
+    public void testGetIndex()
+            throws RepositoryException {
+
+        Node node = locateNodeWithSameNameSiblings(rootNode);
+
+        if (node == rootNode) {
+            assertEquals("getIndex() of a node without same name siblings " +
+                    "must return 1", node.getIndex(), 1);
+        } else {
+            NodeIterator nodes = node.getParent().getNodes(node.getName());
+            int i = 1;
+            while (nodes.hasNext()) {
+                assertEquals("getIndex() must return the correct index",
+                        nodes.nextNode().getIndex(),
+                        i);
+                i++;
+            }
+        }
+    }
+
+    public void testGetReferences()
+            throws NotExecutableException, RepositoryException {
+
+        Node node = locateNodeWithReference(rootNode);
+
+        if (node == rootNode) {
+            throw new NotExecutableException("Workspace does not contain a node with a reference property set");
+        }
+
+        PropertyIterator properties = node.getProperties();
+        while (properties.hasNext()) {
+            Property p = properties.nextProperty();
+            if (p.getType() == PropertyType.REFERENCE) {
+                Node referencedNode = p.getNode();
+                PropertyIterator refs = referencedNode.getReferences();
+                boolean referenceFound = false;
+                while (refs.hasNext()) {
+                    if (refs.nextProperty() == p) {
+                        referenceFound = true;
+                    }
+                }
+                assertTrue("Correct reference not found", referenceFound);
+            }
+        }
+    }
+
+    /**
+     * Test if getUUID() returns the string value of the property "jcr:uuid".
+     * Therefor a node of type "mix:referenceable" is located recursively in the
+     * entire repository. A NotExecutableException is thrown when no node of
+     * this type is found.
+     *
+     * @throws NotExecutableException
+     * @throws RepositoryException
+     */
+    public void testGetUUID()
+            throws NotExecutableException, RepositoryException {
+
+        // find a node of type mix:referenceable
+        Node node = locateReferenceableNode(rootNode);
+
+        if (!node.isNodeType(mixReferenceable)) {
+            throw new NotExecutableException("Workspace does not contain a referencable node");
+        }
+
+        try {
+            assertEquals("node.getUUID() does not match " +
+                    "node.getProperty(\"jcr:uuid\").getString()",
+                    node.getProperty("jcr:uuid").getString(), node.getUUID());
+        } catch (PathNotFoundException e) {
+            fail("Property UUID expected for " +
+                    "node of type \"" + mixReferenceable + "\"");
+        }
+    }
+
+    /**
+     * Test if getUUID() throws a UnsupportedRepositoryOperationException if
+     * Node is not referenceable
+     */
+    public void testGetUUIDOfNonReferenceableNode()
+            throws NotExecutableException, RepositoryException {
+
+        // find a node NOT of type mix:referenceable
+        Node node = locateNonReferenceableNode(rootNode);
+
+        if (node.isNodeType(mixReferenceable)) {
+            throw new NotExecutableException("Workspace does not contain a non referenceable node");
+        }
+
+        try {
+            node.getUUID();
+            fail("UnsupportedRepositoryOperationException expected");
+        } catch (UnsupportedRepositoryOperationException e) {
+            // success
+        }
+    }
+
+    /**
+     * Test if hasNode(String relPath) returns true if the required node exists
+     * and false if it doesn't. Tested node: root
+     */
+    public void testHasNode()
+            throws NotExecutableException, RepositoryException {
+
+        Node node = rootNode;
+
+        NodeIterator nodes = node.getNodes();
+        StringBuffer notExistingNodeName = new StringBuffer();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            assertTrue("hasNode(String relPath) returns false although " +
+                    "node at relPath is existing",
+                    node.hasNode(n.getName()));
+            notExistingNodeName.append(n.getName() + "X");
+        }
+        if (notExistingNodeName.equals("")) {
+            throw new NotExecutableException("Workspace does not have sufficient content for this test. Root node must have at least one child node.");
+        }
+
+        assertFalse("hasNode(String relPath) returns true although " +
+                "node at relPath is not existing",
+                node.hasNode(notExistingNodeName.toString()));
+    }
+
+    /**
+     * Test if hasNodes() returns true if any sub node exists or false if not.
+     * Tested node: root
+     */
+    public void testHasNodes() throws RepositoryException {
+        Node node = rootNode;
+        NodeIterator nodes = node.getNodes();
+
+        int i = 0;
+        while (nodes.hasNext()) {
+            nodes.nextNode();
+            i++;
+        }
+
+        if (i == 0) {
+            assertFalse("node.hasNodes() returns true although " +
+                    "no sub nodes existing",
+                    node.hasNodes());
+        } else {
+            assertTrue("node.hasNodes() returns false althuogh " +
+                    "sub nodes are existing",
+                    node.hasNodes());
+        }
+    }
+
+    /**
+     * Test if hasProperty(String relPath) returns true if a required property
+     * exists and false if it doesn't. Tested node: root
+     */
+    public void testHasProperty()
+            throws NotExecutableException, RepositoryException {
+
+        Node node = rootNode;
+
+        PropertyIterator properties = node.getProperties();
+        StringBuffer notExistingPropertyName = new StringBuffer();
+        while (properties.hasNext()) {
+            Property p = properties.nextProperty();
+            assertTrue("node.hasProperty(\"relPath\") returns false " +
+                    "although property at relPath is existing",
+                    node.hasProperty(p.getName()));
+            notExistingPropertyName.append(p.getName() + "X");
+        }
+        if (notExistingPropertyName.equals("")) {
+            fail("Root node must at least have one property: jcr:primaryType");
+        }
+
+        assertFalse("node.hasProperty(\"relPath\") returns true " +
+                "although property at relPath is not existing",
+                node.hasProperty(notExistingPropertyName.toString()));
+    }
+
+    /**
+     * Test if hasProperty() returns true if any property exists or false if
+     * not. Tested node: root
+     *
+     * @throws RepositoryException
+     */
+    public void testHasProperties() throws RepositoryException {
+        Node node = rootNode;
+        PropertyIterator properties = node.getProperties();
+
+        int i = 0;
+        while (properties.hasNext()) {
+            Property p = properties.nextProperty();
+            log.println(p.getName());
+            i++;
+        }
+
+        if (i == 0) {
+            assertFalse("Must return false when no properties exist",
+                    node.hasProperties());
+        } else {
+            assertTrue("Must return true when one or more properties exist",
+                    node.hasProperties());
+        }
+    }
+
+    //-----------------------< internal >---------------------------------------
+
+    /**
+     * Returns the first descendant of <code>node</code> which is of type
+     * mix:referencable.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node of type mix:referenceable
+     */
+    private Node locateReferenceableNode(Node node)
+            throws RepositoryException {
+
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            if (n.isNodeType(mixReferenceable)) {
+                return n;
+            } else {
+                Node returnedNode = locateReferenceableNode(n);
+                if (n != returnedNode) {
+                    return returnedNode;
+                }
+            }
+        }
+        // no node of type "mix:referenceable" found - return passed node
+        return node;
+    }
+
+    /**
+     * Returns the first descendant of <code>node</code> which is not of
+     * type mix:referenceable.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node which is not of type mix:referenceable
+     */
+    private Node locateNonReferenceableNode(Node node)
+            throws RepositoryException {
+
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            if (!n.isNodeType(mixReferenceable)) {
+                return n;
+            } else {
+                Node returnedNode = locateNonReferenceableNode(n);
+                if (n != returnedNode) {
+                    return returnedNode;
+                }
+            }
+        }
+        // all nodes are of type "mix:referenceable" - return passed node
+        return node;
+    }
+
+    /**
+     * Returns the first descendant of <code>node</code> which has a property
+     * of type {@link javax.jcr.PropertyType#REFERENCE} set.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node with a property of PropertType.REFERENCE
+     */
+    private Node locateNodeWithReference(Node node)
+            throws RepositoryException {
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            PropertyIterator properties = n.getProperties();
+            while (properties.hasNext()) {
+                Property p = properties.nextProperty();
+                if (p.getType() == PropertyType.REFERENCE) {
+                    return n;
+                }
+            }
+
+            Node returnedNode = locateNodeWithReference(n);
+            if (n != returnedNode) {
+                return returnedNode;
+            }
+        }
+        // no node of type "mix:referenceable" found - return passed node
+        return node;
+    }
+
+    /**
+     * Returns the first descendant of <code>node</code> which defines a
+     * primary item.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node with a primary item
+     */
+    private Node locateNodeWithPrimaryItem(Node node)
+            throws RepositoryException {
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            if (n.getPrimaryNodeType().getPrimaryItemName() != null) {
+                return n;
+            } else {
+                Node returnedNode = locateNodeWithPrimaryItem(n);
+                if (n != returnedNode) {
+                    return returnedNode;
+                }
+            }
+        }
+        // no node with primary item found - return passed node
+        return node;
+    }
+
+    /**
+     * Returns the first descendant of <code>node</code> which does not define
+     * a primary item.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node without a primary item
+     */
+    private Node locateNodeWithoutPrimaryItem(Node node)
+            throws RepositoryException {
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            if (n.getPrimaryNodeType().getPrimaryItemName() == null) {
+                return n;
+            } else {
+                Node returnedNode = locateNodeWithoutPrimaryItem(n);
+                if (n != returnedNode) {
+                    return returnedNode;
+                }
+            }
+        }
+        // no node with primary item found - return passed node
+        return node;
+    }
+
+    /**
+     * Returns the first descendant of <code>node</code> which has same
+     * name siblings.
+     * @param node <code>Node</code> to start traversal.
+     * @return first node with same name siblings
+     */
+    private Node locateNodeWithSameNameSiblings(Node node)
+            throws RepositoryException {
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node n = nodes.nextNode();
+            NodeIterator nodes2 = node.getNodes(n.getName());
+            int i = 0;
+            while (nodes2.hasNext()) {
+                nodes2.next();
+                i++;
+            }
+            if (i > 1) {
+                // node has same name siblings
+                return n;
+            } else {
+                Node returnedNode = locateNodeWithSameNameSiblings(n);
+                if (n != returnedNode) {
+                    return returnedNode;
+                }
+            }
+        }
+        // no node with same name siblings found - return passed node
+        return node;
+    }
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/NodeReadMethodsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java?view=auto&rev=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java Tue Feb 15 05:56:44 2005
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.jackrabbit.test.api;
+
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.PropertyIterator;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+
+/**
+ * Tests if the type of a property is set according to the node type as well
+ * as no property is of type UNDEFINED. This test runs recursively through
+ * the entire repository.
+ *
+ * @test
+ * @sources PropertyTypeTest.java
+ * @executeClass org.apache.jackrabbit.test.api.PropertyTypeTest
+ * @keywords level1
+ */
+public class PropertyTypeTest extends AbstractJCRTest {
+
+    /**
+     * Sets up the fixture for this test.
+     */
+    protected void setUp() throws Exception {
+        isReadOnly = true;
+        super.setUp();
+    }
+
+    /**
+     * Tests if the type of a property is set according to the node type as well
+     * as no property is of type UNDEFINED. This test runs recursively through
+     * the entire repository.
+     */
+    public void testType() throws RepositoryException {
+        Session session = helper.getReadOnlySession();
+        Node root = session.getRootNode();
+        typeCheckChildren(root);
+    }
+
+    private void typeCheckChildren(Node parentNode)
+            throws RepositoryException {
+
+        NodeIterator nodes = parentNode.getNodes();
+        while (nodes.hasNext()) {
+            Node node = nodes.nextNode();
+
+            PropertyIterator props = node.getProperties();
+            while (props.hasNext()) {
+                Property prop = props.nextProperty();
+                int reqType = prop.getDefinition().getRequiredType();
+                int type = PropertyType.UNDEFINED;
+                boolean isEmptyMultipleArray = false;
+
+                if (prop.getDefinition().isMultiple()) {
+                    if (prop.getValues().length > 0) {
+                        type = prop.getValues()[0].getType();
+                    } else {
+                        isEmptyMultipleArray = true;
+                    }
+                } else {
+                    type = prop.getValue().getType();
+                }
+
+                if (!isEmptyMultipleArray &&
+                        reqType != PropertyType.UNDEFINED) {
+
+                    assertFalse("The type of a property must not " +
+                            "be UNDEFINED",
+                            type == PropertyType.UNDEFINED);
+
+                    assertEquals("The type of a property has to match " +
+                            "the type of the property definition.",
+                            type,
+                            reqType);
+                }
+            }
+            typeCheckChildren(node);
+        }
+    }
+
+
+}
\ No newline at end of file

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyTypeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/TestAll.java?view=diff&r1=153935&r2=153936
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/TestAll.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/TestAll.java Tue Feb 15 05:56:44 2005
@@ -42,6 +42,10 @@
         suite.addTestSuite(RootNodeTest.class);
         suite.addTestSuite(NamespaceRegistryTest.class);
         suite.addTestSuite(ReferencesTest.class);
+        suite.addTestSuite(ItemDefTest.class);
+        suite.addTestSuite(ItemReadMethodsTest.class);
+        suite.addTestSuite(NodeReadMethodsTest.class);
+        suite.addTestSuite(PropertyTypeTest.class);
 
         return suite;
     }