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

enorman pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-jcr-mock.git


The following commit(s) were added to refs/heads/master by this push:
     new b94162e  SLING-11813 MockNodeTypeManager mode that utilizes real node 
types (#16)
b94162e is described below

commit b94162e1f9e62f0d2d5a1769ad942b79b4f62319
Author: Eric Norman <[email protected]>
AuthorDate: Thu Apr 6 15:17:43 2023 -0700

    SLING-11813 MockNodeTypeManager mode that utilizes real node types (#16)
---
 .../sling/testing/mock/jcr/AbstractItem.java       |  13 +-
 .../mock/jcr/MockEventListenerIterator.java        |   2 +-
 .../sling/testing/mock/jcr/MockItemDefinition.java |  80 ++++++
 .../org/apache/sling/testing/mock/jcr/MockJcr.java |  30 +++
 .../apache/sling/testing/mock/jcr/MockNode.java    | 113 ++++++++-
 .../sling/testing/mock/jcr/MockNodeDefinition.java |  69 +++---
 .../mock/jcr/MockNodeDefinitionTemplate.java       |  91 +++++++
 .../sling/testing/mock/jcr/MockNodeType.java       | 187 ++++++++++++++-
 .../testing/mock/jcr/MockNodeTypeManager.java      | 148 ++++++++++--
 .../testing/mock/jcr/MockNodeTypeTemplate.java     | 183 ++++++++++++++
 .../sling/testing/mock/jcr/MockProperty.java       |  19 +-
 .../testing/mock/jcr/MockPropertyDefinition.java   |  74 ++++++
 .../mock/jcr/MockPropertyDefinitionTemplate.java   | 110 +++++++++
 .../mock/jcr/MockTemplateBuilderFactory.java       | 267 +++++++++++++++++++++
 .../sling/testing/mock/jcr/package-info.java       |   2 +-
 .../testing/mock/jcr/AbstractMockNodeTypeTest.java | 255 ++++++++++++++++++++
 .../mock/jcr/MockNodeOnlyRegisteredTypesTest.java  | 109 +++++++++
 .../sling/testing/mock/jcr/MockNodeTest.java       |  42 ++++
 .../testing/mock/jcr/MockNodeTypeAllModeTest.java  | 170 +++++++++++++
 .../mock/jcr/MockNodeTypeManagerAllModeTest.java   | 164 +++++++++++++
 .../testing/mock/jcr/MockNodeTypeManagerTest.java  | 217 +++++++++++++++++
 .../sling/testing/mock/jcr/MockNodeTypeTest.java   | 260 ++++++++++++++++++++
 .../sling/testing/mock/jcr/MockPropertyTest.java   |  45 +++-
 .../testing/mock/jcr/MockQueryManagerTest.java     |   2 -
 .../sling/testing/mock/jcr/test_nodetypes.cnd      | 178 ++++++++++++++
 25 files changed, 2743 insertions(+), 87 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/AbstractItem.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/AbstractItem.java
index 563f613..898c541 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/AbstractItem.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/AbstractItem.java
@@ -22,7 +22,6 @@ import java.util.Objects;
 
 import javax.jcr.Item;
 import javax.jcr.ItemNotFoundException;
-import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -37,7 +36,7 @@ abstract class AbstractItem implements Item {
     protected final ItemData itemData;
     private final Session session;
 
-    public AbstractItem(final ItemData itemData, final Session session) {
+    protected AbstractItem(final ItemData itemData, final Session session) {
         this.itemData = itemData;
         this.session = session;
     }
@@ -84,7 +83,7 @@ abstract class AbstractItem implements Item {
         String absolutePath = relativePath;
         // ensure the path is absolute and normalized
         if (!StringUtils.startsWith(absolutePath, "/")) {
-            absolutePath = getPath() + "/" + absolutePath; // NOPMD
+            absolutePath = getPath() + "/" + absolutePath; // NOPMD NOSONAR
         }
         return ResourceUtil.normalize(absolutePath);
     }
@@ -107,12 +106,6 @@ abstract class AbstractItem implements Item {
         }
     }
 
-    // --- unsupported operations ---
-    @Override
-    public void accept(final ItemVisitor visitor) throws RepositoryException {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public boolean isSame(final Item otherItem) throws RepositoryException {
         boolean same = false;
@@ -136,6 +129,8 @@ abstract class AbstractItem implements Item {
         return same;
     }
 
+    // --- unsupported operations ---
+
     @Override
     public void refresh(final boolean keepChanges) throws RepositoryException {
         throw new UnsupportedOperationException();
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockEventListenerIterator.java
 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockEventListenerIterator.java
index d0859cd..b159c5c 100644
--- 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockEventListenerIterator.java
+++ 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockEventListenerIterator.java
@@ -27,7 +27,7 @@ import 
org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
 
 class MockEventListenerIterator extends RangeIteratorAdapter implements 
EventListenerIterator {
 
-    public MockEventListenerIterator(Collection collection) {
+    public MockEventListenerIterator(Collection<EventListener> collection) {
         super(collection);
     }
 
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockItemDefinition.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockItemDefinition.java
new file mode 100644
index 0000000..6ec1ec3
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockItemDefinition.java
@@ -0,0 +1,80 @@
+/*
+ * 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.testing.mock.jcr;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+
+/**
+ *
+ */
+abstract class MockItemDefinition implements ItemDefinition {
+    protected String name;
+    protected boolean autoCreated;
+    protected boolean mandatory;
+    protected int opv;
+    protected boolean protectedStatus;
+    protected String declaringNodeTypeName;
+    protected NodeTypeManager ntMgr;
+
+    protected MockItemDefinition(String declaringNodeTypeName, NodeTypeManager 
ntMgr) {
+        super();
+        this.declaringNodeTypeName = declaringNodeTypeName;
+        this.ntMgr = ntMgr;
+    }
+
+    @Override
+    public NodeType getDeclaringNodeType() {
+        NodeType nt = null;
+        if (ntMgr != null && this.declaringNodeTypeName != null) {
+            try {
+                nt = ntMgr.getNodeType(this.declaringNodeTypeName);
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting declared node type 
failed.", e);
+            }
+        }
+        return nt;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public boolean isAutoCreated() {
+        return this.autoCreated;
+    }
+
+    @Override
+    public boolean isMandatory() {
+        return this.mandatory;
+    }
+
+    @Override
+    public int getOnParentVersion() {
+        return this.opv;
+    }
+
+    @Override
+    public boolean isProtected() {
+        return this.protectedStatus;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockJcr.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockJcr.java
index c9f0871..c16bb28 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockJcr.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockJcr.java
@@ -18,16 +18,23 @@
  */
 package org.apache.sling.testing.mock.jcr;
 
+import java.io.Reader;
 import java.util.List;
 
+import javax.jcr.NamespaceRegistry;
 import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
 import javax.jcr.query.QueryManager;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.commons.cnd.CompactNodeTypeDefReader;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.apache.sling.testing.mock.jcr.MockNodeTypeManager.ResolveMode;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.annotation.versioning.ConsumerType;
@@ -223,4 +230,27 @@ public final class MockJcr {
         }
     }
 
+    /**
+     * Reads and registers the node types from the reader that supplies the 
content
+     * in the compact node type definition format.  This will also change the 
mode of
+     * the MockNodeTypeManager to consider only the registered node types.
+     * 
+     * @param session session to load the node types into
+     * @param reader reader supplying the compact node type definition data
+     */
+    public static void loadNodeTypeDefs(@NotNull Session session, @NotNull 
Reader reader) throws ParseException, RepositoryException {
+        // inform the manager to only consider the registered node types
+        NodeTypeManager nodeTypeManager = 
session.getWorkspace().getNodeTypeManager();
+        
((MockNodeTypeManager)nodeTypeManager).setMode(ResolveMode.ONLY_REGISTERED);
+
+        MockTemplateBuilderFactory factory = new 
MockTemplateBuilderFactory(session);
+        CompactNodeTypeDefReader<NodeTypeTemplate, NamespaceRegistry> 
cndReader = 
+                new CompactNodeTypeDefReader<>(reader, "cnd input stream", 
factory);
+
+        List<NodeTypeTemplate> nodeTypeDefinitions = 
cndReader.getNodeTypeDefinitions();
+        for (NodeTypeTemplate nodeTypeDefinition : nodeTypeDefinitions) {
+            nodeTypeManager.registerNodeType(nodeTypeDefinition, true);
+        }
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockNode.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNode.java
index fc0cc65..56a88e7 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockNode.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockNode.java
@@ -29,6 +29,7 @@ import java.util.stream.Stream;
 import javax.jcr.Binary;
 import javax.jcr.Item;
 import javax.jcr.ItemNotFoundException;
+import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.PathNotFoundException;
@@ -42,6 +43,7 @@ import javax.jcr.lock.Lock;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
 import javax.jcr.version.Version;
 import javax.jcr.version.VersionHistory;
 
@@ -50,6 +52,7 @@ import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.ItemNameMatcher;
 import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
 import org.apache.jackrabbit.commons.iterator.PropertyIteratorAdapter;
+import org.apache.sling.testing.mock.jcr.MockNodeTypeManager.ResolveMode;
 
 
 /**
@@ -69,11 +72,40 @@ class MockNode extends AbstractItem implements Node {
     @Override
     public Node addNode(final String relPath, final String 
primaryNodeTypeName) throws RepositoryException {
         String path = makeAbsolutePath(relPath);
-        ItemData itemData = ItemData.newNode(path, new 
MockNodeType(primaryNodeTypeName));
+        NodeType nodeType = 
getSession().getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
+        ItemData itemData = ItemData.newNode(path, nodeType);
         Node node = new MockNode(itemData, getSession());
         getMockedSession().addItem(itemData);
         node.setProperty(JcrConstants.JCR_PRIMARYTYPE, primaryNodeTypeName);
 
+        if 
(((MockNodeTypeManager)getSession().getWorkspace().getNodeTypeManager()).isMode(ResolveMode.ONLY_REGISTERED))
 {
+            // auto-add any autocreated children
+            NodeDefinition[] childNodeDefinitions = 
nodeType.getChildNodeDefinitions();
+            if (childNodeDefinitions != null) {
+                for (NodeDefinition nodeDefinition : childNodeDefinitions) {
+                    if (nodeDefinition.isAutoCreated()) {
+                        String defaultPrimaryTypeName = 
nodeDefinition.getDefaultPrimaryTypeName();
+                        node.addNode(nodeDefinition.getName(), 
defaultPrimaryTypeName);
+                    }
+                }
+            }
+
+            // auto-add any autocreated properties
+            PropertyDefinition[] propDefinitions = 
nodeType.getPropertyDefinitions();
+            if (propDefinitions != null) {
+                for (PropertyDefinition propDefinition : propDefinitions) {
+                    if (propDefinition.isAutoCreated()) {
+                        Value[] defaultValues = 
propDefinition.getDefaultValues();
+                        if (propDefinition.isMultiple()) {
+                            node.setProperty(propDefinition.getName(), 
defaultValues);
+                        } else if (defaultValues.length > 0) {
+                            node.setProperty(propDefinition.getName(), 
defaultValues[0]);
+                        }
+                    }
+                }
+            }
+        }
+
         // special handling for some node types
         if (StringUtils.equals(primaryNodeTypeName, JcrConstants.NT_FILE)) {
             node.setProperty(JcrConstants.JCR_CREATED, Calendar.getInstance());
@@ -310,7 +342,7 @@ class MockNode extends AbstractItem implements Node {
      * @param itemData Item data
      * @throws RepositoryException
      */
-    private void addItem(ItemData itemData) throws RepositoryException {
+    private void addItem(ItemData itemData) {
         getMockedSession().addItem(itemData);
         this.itemData.setIsChanged(true);
     }
@@ -413,14 +445,52 @@ class MockNode extends AbstractItem implements Node {
 
     @Override
     public NodeDefinition getDefinition() throws RepositoryException {
-        return new MockNodeDefinition();
+        if 
(((MockNodeTypeManager)getSession().getWorkspace().getNodeTypeManager()).isMode(ResolveMode.MOCK_ALL))
 {
+            // for backward compatibility
+            return new MockNodeDefinition();
+        } else {
+            String nodeName = getName();
+            NodeDefinition nodeDef = findChildNodeDef(nodeName);
+            if (nodeDef == null) {
+                // try the wildcard def
+                nodeDef = findChildNodeDef("*");
+            }
+            return nodeDef;
+        }
+    }
+
+    protected NodeDefinition findChildNodeDef(String name) throws 
RepositoryException {
+        NodeDefinition nodeDef = null;
+        Node parent = getParent();
+        if (parent != null) {
+            // try the primary type
+            NodeType nt = parent.getPrimaryNodeType();
+            NodeDefinition[] childNodeDefinitions = 
nt.getChildNodeDefinitions();
+            nodeDef = Stream.of(childNodeDefinitions)
+                .filter(def -> name.equals(def.getName()))
+                .findFirst().orElse(null);
+            if (nodeDef == null) {
+                // try the mixins
+                NodeType[] mixinNodeTypes = parent.getMixinNodeTypes();
+                for (NodeType nodeType : mixinNodeTypes) {
+                    childNodeDefinitions = nodeType.getChildNodeDefinitions();
+                    nodeDef = Stream.of(childNodeDefinitions)
+                        .filter(def -> name.equals(def.getName()))
+                        .findFirst().orElse(null);
+                    if (nodeDef != null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return nodeDef;
     }
 
     @Override
     public void setPrimaryType(final String primaryNodeTypeName) throws 
RepositoryException {
         if (StringUtils.isNotBlank(primaryNodeTypeName)) {
-            // accept all node types like stated in the MockNodeTypeManager
-            this.itemData.setNodeType(new MockNodeType(primaryNodeTypeName));
+            NodeType nodeType = 
getSession().getWorkspace().getNodeTypeManager().getNodeType(primaryNodeTypeName);
+            this.itemData.setNodeType(nodeType);
             setProperty(JcrConstants.JCR_PRIMARYTYPE, primaryNodeTypeName);
         } else {
             throw new NoSuchNodeTypeException("Not accepting blank node 
types");
@@ -441,6 +511,35 @@ class MockNode extends AbstractItem implements Node {
                 ).toArray(Value[]::new);
                 this.setProperty(JcrConstants.JCR_MIXINTYPES, newValues);
             }
+            
+            if 
(((MockNodeTypeManager)getSession().getWorkspace().getNodeTypeManager()).isMode(ResolveMode.ONLY_REGISTERED))
 {
+                NodeType mixinNodeType = 
getSession().getWorkspace().getNodeTypeManager().getNodeType(mixinName);
+                // auto-add any autocreated children
+                NodeDefinition[] childNodeDefinitions = 
mixinNodeType.getChildNodeDefinitions();
+                if (childNodeDefinitions != null) {
+                    for (NodeDefinition nodeDefinition : childNodeDefinitions) 
{
+                        if (nodeDefinition.isAutoCreated()) {
+                            String defaultPrimaryTypeName = 
nodeDefinition.getDefaultPrimaryTypeName();
+                            addNode(nodeDefinition.getName(), 
defaultPrimaryTypeName);
+                        }
+                    }
+                }
+
+                // auto-add any autocreated properties
+                PropertyDefinition[] propDefinitions = 
mixinNodeType.getPropertyDefinitions();
+                if (propDefinitions != null) {
+                    for (PropertyDefinition propDefinition : propDefinitions) {
+                        if (propDefinition.isAutoCreated()) {
+                            Value[] defaultValues = 
propDefinition.getDefaultValues();
+                            if (propDefinition.isMultiple()) {
+                                setProperty(propDefinition.getName(), 
defaultValues);
+                            } else if (defaultValues.length > 0) {
+                                setProperty(propDefinition.getName(), 
defaultValues[0]);
+                            }
+                        }
+                    }
+                }
+            }
         } else {
             throw new NoSuchNodeTypeException("Not accepting blank mixin 
name");
         }
@@ -631,5 +730,9 @@ class MockNode extends AbstractItem implements Node {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public void accept(ItemVisitor visitor) throws RepositoryException {
+        visitor.visit(this);
+    }
 
 }
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinition.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinition.java
index 3311621..570c846 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinition.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinition.java
@@ -18,68 +18,69 @@
  */
 package org.apache.sling.testing.mock.jcr;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
 
 /**
  * Mock {@link NodeDefinition} implementation.
  */
-class MockNodeDefinition implements NodeDefinition {
-
-    @Override
-    public boolean isAutoCreated() {
-        return false;
-    }
+class MockNodeDefinition extends MockItemDefinition implements NodeDefinition {
+    protected String[] requiredPrimaryTypeNames;
+    protected String defaultPrimaryTypeName;
+    protected boolean allowSameNameSiblings;
 
-    @Override
-    public boolean isMandatory() {
-        return false;
+    public MockNodeDefinition() {
+        // for backward compatibility
+        this(null, null);
     }
-
-    @Override
-    public boolean isProtected() {
-        return false;
+    public MockNodeDefinition(String declaringNodeTypeName, NodeTypeManager 
ntMgr) {
+        super(declaringNodeTypeName, ntMgr);
     }
 
     @Override
     public boolean allowsSameNameSiblings() {
-        return false;
-    }
-
-    // --- unsupported operations ---
-    @Override
-    public NodeType getDeclaringNodeType() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getName() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getOnParentVersion() {
-        throw new UnsupportedOperationException();
+        return allowSameNameSiblings;
     }
 
     @Override
     public NodeType[] getRequiredPrimaryTypes() {
-        throw new UnsupportedOperationException();
+        List<NodeType> ntList = new ArrayList<>();
+        for (String name : this.requiredPrimaryTypeNames) {
+            try {
+                ntList.add(ntMgr.getNodeType(name));
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting required primary types 
failed.", e);
+            }
+        }
+        return ntList.toArray(new NodeType[ntList.size()]);
     }
 
     @Override
     public String[] getRequiredPrimaryTypeNames() {
-        throw new UnsupportedOperationException();
+        return this.requiredPrimaryTypeNames;
     }
 
     @Override
     public NodeType getDefaultPrimaryType() {
-        throw new UnsupportedOperationException();
+        NodeType nt = null;
+        if (this.defaultPrimaryTypeName != null) {
+            try {
+                nt = ntMgr.getNodeType(this.defaultPrimaryTypeName);
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting default primary type 
failed.", e);
+            }
+        }
+        return nt;
     }
 
     @Override
     public String getDefaultPrimaryTypeName() {
-        throw new UnsupportedOperationException();
+        return this.defaultPrimaryTypeName;
     }
 
 }
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinitionTemplate.java
 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinitionTemplate.java
new file mode 100644
index 0000000..65bd3b9
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeDefinitionTemplate.java
@@ -0,0 +1,91 @@
+/*
+ * 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.testing.mock.jcr;
+
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeTypeManager;
+
+/**
+ *
+ */
+class MockNodeDefinitionTemplate extends MockNodeDefinition implements 
NodeDefinitionTemplate {
+
+    public MockNodeDefinitionTemplate(String declaringNodeTypeName, 
NodeTypeManager ntMgr) {
+        // default ctor
+        super(declaringNodeTypeName, ntMgr);
+    }
+
+    public MockNodeDefinitionTemplate(String declaringNodeTypeName, 
NodeTypeManager ntMgr, NodeDefinition nodeDef) {
+        this(declaringNodeTypeName, ntMgr);
+        // copy ctor
+        this.name = nodeDef.getName();
+        this.autoCreated = nodeDef.isAutoCreated();
+        this.mandatory = nodeDef.isMandatory();
+        this.opv = nodeDef.getOnParentVersion();
+        this.protectedStatus = nodeDef.isProtected();
+        this.requiredPrimaryTypeNames = nodeDef.getRequiredPrimaryTypeNames();
+        this.defaultPrimaryTypeName = nodeDef.getDefaultPrimaryTypeName();
+        this.allowSameNameSiblings = nodeDef.allowsSameNameSiblings();
+    }
+
+    @Override
+    public void setName(String name) throws ConstraintViolationException {
+        this.name = name;
+    }
+
+    @Override
+    public void setAutoCreated(boolean autoCreated) {
+        this.autoCreated = autoCreated;
+    }
+
+    @Override
+    public void setMandatory(boolean mandatory) {
+        this.mandatory = mandatory;
+    }
+
+    @Override
+    public void setOnParentVersion(int opv) {
+        this.opv = opv;
+    }
+
+    @Override
+    public void setProtected(boolean protectedStatus) {
+        this.protectedStatus = protectedStatus;
+    }
+
+    @Override
+    public void setRequiredPrimaryTypeNames(String[] names) throws 
ConstraintViolationException {
+        this.requiredPrimaryTypeNames = names;
+    }
+
+    @Override
+    public void setDefaultPrimaryTypeName(String name) throws 
ConstraintViolationException {
+        this.defaultPrimaryTypeName = name;
+    }
+
+    @Override
+    public void setSameNameSiblings(boolean allowSameNameSiblings) {
+        this.allowSameNameSiblings = allowSameNameSiblings;
+    }
+
+    public void setDeclaringNodeType(String declaringNodeTypeName) {
+        this.declaringNodeTypeName = declaringNodeTypeName;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeType.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeType.java
index 3e25deb..38e7abe 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeType.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeType.java
@@ -18,24 +18,52 @@
  */
 package org.apache.sling.testing.mock.jcr;
 
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 import javax.jcr.nodetype.NodeDefinition;
 import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeDefinition;
 import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.PropertyDefinition;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.iterator.NodeTypeIteratorAdapter;
+import org.apache.sling.testing.mock.jcr.MockNodeTypeManager.ResolveMode;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Mock {@link NodeType} implementation.
  */
 class MockNodeType implements NodeType {
 
+    private final NodeTypeDefinition ntd;
     private final String name;
+    private final @Nullable NodeTypeManager ntMgr;
 
     public MockNodeType(final String name) {
+        this(name, null);
+    }
+
+    public MockNodeType(final String name, @Nullable NodeTypeManager ntMgr) {
+        this.ntd = null;
         this.name = name;
+        this.ntMgr = ntMgr;
+    }
+
+    public MockNodeType(NodeTypeDefinition ntd, @Nullable NodeTypeManager 
ntMgr) {
+        this.ntd = ntd;
+        this.name = ntd.getName();
+        this.ntMgr = ntMgr;
     }
 
     @Override
@@ -45,12 +73,20 @@ class MockNodeType implements NodeType {
 
     @Override
     public boolean isNodeType(final String nodeTypeName) {
-        // node type inheritance not supported
-        return this.name.equals(nodeTypeName);
+        boolean isNt = this.name.equals(nodeTypeName);
+        if (ntd != null && !isNt) {
+            // node type inheritance checking
+            NodeType[] supertypes = getSupertypes();
+            isNt = Stream.of(supertypes).anyMatch(nt -> 
nt.getName().equals(nodeTypeName));
+        }
+        return isNt;
     }
 
     @Override
     public boolean hasOrderableChildNodes() {
+        if (ntd != null) {
+            return ntd.hasOrderableChildNodes();
+        }
         // support only well-known built-in node type
         return StringUtils.equals(getName(), JcrConstants.NT_UNSTRUCTURED);
     }
@@ -84,41 +120,124 @@ class MockNodeType implements NodeType {
 
     @Override
     public NodeDefinition[] getChildNodeDefinitions() {
-        throw new UnsupportedOperationException();
+        Map<String, NodeDefinition> defsMap = new LinkedHashMap<>();
+        NodeType[] supertypes = getSupertypes();
+        for (NodeType nodeType : supertypes) {
+            NodeDefinition[] declaredChildNodeDefinitions = 
nodeType.getDeclaredChildNodeDefinitions();
+            if (declaredChildNodeDefinitions != null) {
+                for (NodeDefinition declaredChildNodeDefinition : 
declaredChildNodeDefinitions) {
+                    defsMap.put(declaredChildNodeDefinition.getName(), 
declaredChildNodeDefinition);
+                }
+            }
+        }
+        NodeDefinition[] declaredChildNodeDefinitions = 
getDeclaredChildNodeDefinitions();
+        if (declaredChildNodeDefinitions != null) {
+            for (NodeDefinition declaredChildNodeDefinition : 
declaredChildNodeDefinitions) {
+                defsMap.put(declaredChildNodeDefinition.getName(), 
declaredChildNodeDefinition);
+            }
+        }
+        return defsMap.values().toArray(new NodeDefinition[defsMap.size()]);
     }
 
     @Override
     public NodeDefinition[] getDeclaredChildNodeDefinitions() {
+        if (ntd != null) {
+            return ntd.getDeclaredChildNodeDefinitions();
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public PropertyDefinition[] getDeclaredPropertyDefinitions() {
+        if (ntd != null) {
+            return ntd.getDeclaredPropertyDefinitions();
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public NodeType[] getDeclaredSupertypes() {
+        if (ntd != null && ntMgr != null) {
+            String[] supertypeNames = ntd.getDeclaredSupertypeNames();
+            // lookup the NodeTypes from the manager
+            return Stream.of(supertypeNames).map(n -> {
+                try {
+                    return ntMgr.getNodeType(n);
+                } catch (RepositoryException e) {
+                    throw new RuntimeException("Getting declared supertype 
failed.", e);
+                }
+            }).toArray(NodeType[]::new);
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public String getPrimaryItemName() {
+        if (ntd != null) {
+            return ntd.getPrimaryItemName();
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public PropertyDefinition[] getPropertyDefinitions() {
-        throw new UnsupportedOperationException();
+        Map<String, PropertyDefinition> defsMap = new LinkedHashMap<>();
+        NodeType[] supertypes = getSupertypes();
+        for (NodeType nodeType : supertypes) {
+            PropertyDefinition[] declaredPropDefinitions = 
nodeType.getDeclaredPropertyDefinitions();
+            if (declaredPropDefinitions != null) {
+                for (PropertyDefinition declaredChildNodeDefinition : 
declaredPropDefinitions) {
+                    defsMap.put(declaredChildNodeDefinition.getName(), 
declaredChildNodeDefinition);
+                }
+            }
+        }
+        PropertyDefinition[] declaredPropDefinitions = 
getDeclaredPropertyDefinitions();
+        if (declaredPropDefinitions != null) {
+            for (PropertyDefinition declaredChildNodeDefinition : 
declaredPropDefinitions) {
+                defsMap.put(declaredChildNodeDefinition.getName(), 
declaredChildNodeDefinition);
+            }
+        }
+        return defsMap.values().toArray(new 
PropertyDefinition[defsMap.size()]);
+    }
+
+    /**
+     * Traverse up the supertypes to find all of them
+     * @param ntSet the set of found node types
+     */
+    private void loadSupertypes(NodeType nt, Set<NodeType> ntSet) {
+        if (!ntSet.contains(nt)) {
+            ntSet.add(nt);
+
+            // walk up the ancestors
+            NodeType[] supertypes = nt.getDeclaredSupertypes();
+            for (NodeType nodeType : supertypes) {
+                loadSupertypes(nodeType, ntSet);
+            }
+        }
     }
 
     @Override
     public NodeType[] getSupertypes() {
-        throw new UnsupportedOperationException();
+        Set<NodeType> ntSet = new LinkedHashSet<>();
+        NodeType[] supertypes = getDeclaredSupertypes();
+        for (NodeType nodeType : supertypes) {
+            loadSupertypes(nodeType, ntSet);
+        }
+        if (!isMixin() && ntMgr != null && 
!JcrConstants.NT_BASE.equals(getName())) {
+            try {
+                ntSet.add(ntMgr.getNodeType(JcrConstants.NT_BASE));
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting supertype failed.", e);
+            }
+        }
+        return ntSet.toArray(new NodeType[ntSet.size()]);
     }
 
     @Override
     public boolean isMixin() {
+        if (ntd != null) {
+            return ntd.isMixin();
+        }
         throw new UnsupportedOperationException();
     }
 
@@ -134,27 +253,81 @@ class MockNodeType implements NodeType {
 
     @Override
     public NodeTypeIterator getDeclaredSubtypes() {
-        throw new UnsupportedOperationException();
+        if (ntMgr != null && 
((MockNodeTypeManager)ntMgr).isMode(ResolveMode.MOCK_ALL)) {
+            throw new UnsupportedOperationException();
+        }
+        List<NodeType> subtypes = new ArrayList<>();
+        if (ntMgr != null) {
+            try {
+                NodeTypeIterator allNodeTypes = ntMgr.getAllNodeTypes();
+                while (allNodeTypes.hasNext()) {
+                    NodeType nextNodeType = allNodeTypes.nextNodeType();
+                    boolean issubtype = 
Stream.of(nextNodeType.getDeclaredSupertypes()).anyMatch(nt -> 
nt.getName().equals(getName()));
+                    if (issubtype) {
+                        subtypes.add(nextNodeType);
+                    }
+                }
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting declared subtype failed.", 
e);
+            }
+        }
+        return new NodeTypeIteratorAdapter(subtypes);
     }
 
     @Override
     public NodeTypeIterator getSubtypes() {
-        throw new UnsupportedOperationException();
+        if (ntMgr != null && 
((MockNodeTypeManager)ntMgr).isMode(ResolveMode.MOCK_ALL)) {
+            throw new UnsupportedOperationException();
+        }
+        List<NodeType> subtypes = new ArrayList<>();
+        if (ntMgr != null) {
+            try {
+                NodeTypeIterator allNodeTypes = ntMgr.getAllNodeTypes();
+                while (allNodeTypes.hasNext()) {
+                    NodeType nextNodeType = allNodeTypes.nextNodeType();
+                    boolean issubtype = 
Stream.of(nextNodeType.getSupertypes()).anyMatch(nt -> 
nt.getName().equals(getName()));
+                    if (issubtype) {
+                        subtypes.add(nextNodeType);
+                    }
+                }
+            } catch (RepositoryException e) {
+                throw new RuntimeException("Getting declared subtype failed.", 
e);
+            }
+        }
+        return new NodeTypeIteratorAdapter(subtypes);
     }
 
     @Override
     public String[] getDeclaredSupertypeNames() {
+        if (ntd != null) {
+            return ntd.getDeclaredSupertypeNames();
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean isAbstract() {
+        if (ntd != null) {
+            return ntd.isAbstract();
+        }
         throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean isQueryable() {
+        if (ntd != null) {
+            return ntd.isQueryable();
+        }
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("MockNodeType [name=");
+        builder.append(name);
+        builder.append("]");
+        return builder.toString();
+    }
+
 }
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManager.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManager.java
index 3373c57..2610ed0 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManager.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManager.java
@@ -18,87 +18,201 @@
  */
 package org.apache.sling.testing.mock.jcr;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
 import javax.jcr.nodetype.NodeDefinitionTemplate;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeExistsException;
 import javax.jcr.nodetype.NodeTypeIterator;
 import javax.jcr.nodetype.NodeTypeManager;
 import javax.jcr.nodetype.NodeTypeTemplate;
 import javax.jcr.nodetype.PropertyDefinitionTemplate;
 
+import org.apache.jackrabbit.commons.iterator.NodeTypeIteratorAdapter;
+
 /**
  * Mock {@link NodeTypeManager} implementation.
  */
 class MockNodeTypeManager implements NodeTypeManager {
+    private static final String NODETYPE_ALREADY_EXISTS = "%s already exists";
+    private static final String NODETYPE_DOES_NOT_EXISTS = "%s does not 
exists";
+    private Map<String, NodeType> registeredNTs = new HashMap<>();
+    private ResolveMode mode = ResolveMode.MOCK_ALL; // for backward 
compatibility
+
+    enum ResolveMode {
+        MOCK_ALL, // for backward compatibility
+        ONLY_REGISTERED
+    }
+
+    /**
+     * Sets how the node types are resolved
+     * 
+     * @param mode the mode to use
+     */
+    public void setMode(ResolveMode mode) {
+        this.mode = mode;
+    }
+
+    /**
+     * Checks if the ResolveMode matches the supplied value
+     * @param mode the value to check
+     * @return true if matches, false otherwise
+     */
+    public boolean isMode(ResolveMode mode) {
+        return this.mode.equals(mode);
+    }
 
     @Override
     public NodeType getNodeType(String nodeTypeName) throws 
RepositoryException {
-        // accept all node types and return a mock
-        return new MockNodeType(nodeTypeName);
+        NodeType nt = null;
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            // accept all node types and return a mock
+            nt = new MockNodeType(nodeTypeName, this);
+        } else {
+            if (registeredNTs.containsKey(nodeTypeName)) {
+                nt = registeredNTs.get(nodeTypeName);
+            }
+        }
+
+        if (nt == null) {
+            throw new 
NoSuchNodeTypeException(String.format(NODETYPE_DOES_NOT_EXISTS, nodeTypeName));
+        }
+        return nt;
     }
 
     @Override
     public boolean hasNodeType(String name) throws RepositoryException {
-        // accept all node types
-        return true;
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            // accept all node types (if equal)
+            return true;
+        }
+        return registeredNTs.containsKey(name);
     }
 
-    // --- unsupported operations ---
-
     @Override
     public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+
+        List<NodeType> mixins = registeredNTs.values().stream()
+                .collect(Collectors.toList());
+        return new NodeTypeIteratorAdapter(mixins);
     }
 
     @Override
     public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+
+        List<NodeType> notMixins = registeredNTs.values().stream()
+                .filter(nt -> !nt.isMixin())
+                .collect(Collectors.toList());
+        return new NodeTypeIteratorAdapter(notMixins);
     }
 
     @Override
     public NodeTypeIterator getMixinNodeTypes() throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+
+        List<NodeType> mixins = registeredNTs.values().stream()
+            .filter(NodeType::isMixin)
+            .collect(Collectors.toList());
+        return new NodeTypeIteratorAdapter(mixins);
     }
 
     @Override
     public NodeTypeTemplate createNodeTypeTemplate() throws 
RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        return new MockNodeTypeTemplate();
     }
 
     @Override
     public NodeTypeTemplate createNodeTypeTemplate(NodeTypeDefinition ntd) 
throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        return new MockNodeTypeTemplate(ntd, this);
     }
 
     @Override
     public NodeDefinitionTemplate createNodeDefinitionTemplate() throws 
RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        return new MockNodeDefinitionTemplate(null, this);
     }
 
     @Override
     public PropertyDefinitionTemplate createPropertyDefinitionTemplate() 
throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        return new MockPropertyDefinitionTemplate(null, this);
     }
 
     @Override
     public NodeType registerNodeType(NodeTypeDefinition ntd, boolean 
allowUpdate) throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        if (!allowUpdate && registeredNTs.containsKey(ntd.getName())) {
+            throw new 
NodeTypeExistsException(String.format(NODETYPE_ALREADY_EXISTS, ntd.getName()));
+        }
+        return registeredNTs.put(ntd.getName(), new MockNodeType(ntd, this));
     }
 
     @Override
     public NodeTypeIterator registerNodeTypes(NodeTypeDefinition[] ntds, 
boolean allowUpdate) throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        List<NodeType> registered = new ArrayList<>(); 
+        for (NodeTypeDefinition ntd : ntds) {
+            if (!allowUpdate && registeredNTs.containsKey(ntd.getName())) {
+                throw new 
NodeTypeExistsException(String.format(NODETYPE_ALREADY_EXISTS, ntd.getName()));
+            }
+            registered.add(registeredNTs.put(ntd.getName(), new 
MockNodeType(ntd, this)));
+        }
+        return new NodeTypeIteratorAdapter(registered);
     }
 
     @Override
     public void unregisterNodeType(String name) throws RepositoryException {
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        if (!registeredNTs.containsKey(name)) {
+            throw new 
NoSuchNodeTypeException(String.format(NODETYPE_DOES_NOT_EXISTS, name));
+        }
+        registeredNTs.remove(name);
     }
 
     @Override
     public void unregisterNodeTypes(String[] names) throws RepositoryException 
{
-        throw new UnsupportedOperationException();
+        if (ResolveMode.MOCK_ALL.equals(this.mode)) {
+            throw new UnsupportedOperationException();
+        }
+        for (String name : names) {
+            if (!registeredNTs.containsKey(name)) {
+                throw new 
NoSuchNodeTypeException(String.format(NODETYPE_DOES_NOT_EXISTS, name));
+            }
+        }
+        for (String name : names) {
+            registeredNTs.remove(name);
+        }
     }
 
 }
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTemplate.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTemplate.java
new file mode 100644
index 0000000..acaaec4
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTemplate.java
@@ -0,0 +1,183 @@
+/*
+ * 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.testing.mock.jcr;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
+
+/**
+ *
+ */
+class MockNodeTypeTemplate implements NodeTypeTemplate {
+
+    private String name;
+    private String[] superTypeNames;
+    private String primaryItemName;
+    private boolean abstractStatus;
+    private boolean queryable;
+    private boolean mixin;
+    private boolean orderableChildNodes;
+    private List<NodeDefinitionTemplate> nodeDefinitionTemplates;
+    private List<PropertyDefinitionTemplate> propertyDefinitionTemplates;
+
+    public MockNodeTypeTemplate() {
+        // default ctor
+    }
+
+    public MockNodeTypeTemplate(NodeTypeDefinition def, NodeTypeManager ntMgr) 
{
+        // copy ctor
+        this.name = def.getName();
+        this.superTypeNames = def.getDeclaredSupertypeNames();
+        this.primaryItemName = def.getPrimaryItemName();
+
+        this.abstractStatus = def.isAbstract();
+        mixin = def.isMixin();
+        queryable = def.isQueryable();
+        orderableChildNodes = def.hasOrderableChildNodes();
+
+        NodeDefinition[] nodeDefs = def.getDeclaredChildNodeDefinitions();
+        if (nodeDefs != null) {
+            List<NodeDefinitionTemplate> list = getNodeDefinitionTemplates();
+            for (NodeDefinition nodeDef : nodeDefs) {
+                list.add(new MockNodeDefinitionTemplate(name, ntMgr, nodeDef));
+            }
+        }
+        PropertyDefinition[] propDefs = def.getDeclaredPropertyDefinitions();
+        if (propDefs != null) {
+            List<PropertyDefinitionTemplate> list = 
getPropertyDefinitionTemplates();
+            for (PropertyDefinition propDef : propDefs) {
+                list.add(new MockPropertyDefinitionTemplate(name, ntMgr, 
propDef));
+            }
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String[] getDeclaredSupertypeNames() {
+        return superTypeNames;
+    }
+
+    @Override
+    public boolean isAbstract() {
+        return abstractStatus;
+    }
+
+    @Override
+    public boolean isMixin() {
+        return mixin;
+    }
+
+    @Override
+    public boolean hasOrderableChildNodes() {
+        return orderableChildNodes;
+    }
+
+    @Override
+    public boolean isQueryable() {
+        return queryable;
+    }
+
+    @Override
+    public String getPrimaryItemName() {
+        return primaryItemName;
+    }
+
+    @Override
+    public PropertyDefinition[] getDeclaredPropertyDefinitions() {
+        if (propertyDefinitionTemplates == null) {
+            return null; // NOSONAR
+        } else {
+            return propertyDefinitionTemplates.toArray(
+                    new 
PropertyDefinition[propertyDefinitionTemplates.size()]);
+        }
+    }
+
+    @Override
+    public NodeDefinition[] getDeclaredChildNodeDefinitions() {
+        if (nodeDefinitionTemplates == null) {
+            return null; // NOSONAR
+        } else {
+            return nodeDefinitionTemplates.toArray(
+                    new NodeDefinition[nodeDefinitionTemplates.size()]);
+        }
+    }
+
+    @Override
+    public void setName(String name) throws ConstraintViolationException {
+        this.name = name;
+    }
+
+    @Override
+    public void setDeclaredSuperTypeNames(String[] names) throws 
ConstraintViolationException {
+        this.superTypeNames = names;
+    }
+
+    @Override
+    public void setAbstract(boolean abstractStatus) {
+        this.abstractStatus = abstractStatus;
+    }
+
+    @Override
+    public void setMixin(boolean mixin) {
+        this.mixin = mixin;
+    }
+
+    @Override
+    public void setOrderableChildNodes(boolean orderable) {
+        this.orderableChildNodes = orderable;
+    }
+
+    @Override
+    public void setPrimaryItemName(String name) throws 
ConstraintViolationException {
+        this.primaryItemName = name;
+    }
+
+    @Override
+    public void setQueryable(boolean queryable) {
+        this.queryable = queryable;
+    }
+
+    @Override
+    public List<PropertyDefinitionTemplate> getPropertyDefinitionTemplates() {
+        if (propertyDefinitionTemplates == null) {
+            propertyDefinitionTemplates = new LinkedList<>();
+        }
+        return propertyDefinitionTemplates;
+    }
+
+    @Override
+    public List<NodeDefinitionTemplate> getNodeDefinitionTemplates() {
+        if (nodeDefinitionTemplates == null) {
+            nodeDefinitionTemplates = new LinkedList<>();
+        }
+        return nodeDefinitionTemplates;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/MockProperty.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockProperty.java
index 152bb37..ae2ab11 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/MockProperty.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/MockProperty.java
@@ -20,9 +20,11 @@ package org.apache.sling.testing.mock.jcr;
 
 import java.io.InputStream;
 import java.math.BigDecimal;
+import java.util.Arrays;
 import java.util.Calendar;
 
 import javax.jcr.Binary;
+import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
 import javax.jcr.Property;
 import javax.jcr.PropertyType;
@@ -71,11 +73,8 @@ class MockProperty extends AbstractItem implements Property {
         if (!this.itemData.isMultiple()) {
             throw new ValueFormatException("Property is single-valued.");
         }
-        Value[] valuesCopy = new Value[this.itemData.getValues().length];
-        for (int i = 0; i < this.itemData.getValues().length; i++) {
-            valuesCopy[i] = this.itemData.getValues()[i];
-        }
-        return valuesCopy;
+        final Value[] values = this.itemData.getValues();
+        return Arrays.copyOf(values, values.length);
     }
 
     @Override
@@ -92,10 +91,7 @@ class MockProperty extends AbstractItem implements Property {
         if (removePropertyIfValueNull(newValues)) {
             return;
         }
-        Value[] values = new Value[newValues.length];
-        for (int i = 0; i < newValues.length; i++) {
-            values[i] = newValues[i];
-        }
+        Value[] values =  Arrays.copyOf(newValues, newValues.length);
         this.itemData.setValues(values);
         this.itemData.setMultiple(true);
     }
@@ -282,6 +278,11 @@ class MockProperty extends AbstractItem implements 
Property {
         return new MockPropertyDefinition();
     }
 
+    @Override
+    public void accept(ItemVisitor visitor) throws RepositoryException {
+        visitor.visit(this);
+    }
+
     @Override
     public int hashCode() {
         return itemData.hashCode();
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinition.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinition.java
new file mode 100644
index 0000000..cc5ad90
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinition.java
@@ -0,0 +1,74 @@
+/*
+ * 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.testing.mock.jcr;
+
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+
+/**
+ *
+ */
+class MockPropertyDefinition extends MockItemDefinition implements 
PropertyDefinition {
+    protected int type;
+    protected String[] constraints;
+    protected Value[] defaultValues;
+    protected boolean multiple;
+    protected boolean fullTextSearchable;
+    protected boolean queryOrderable;
+    protected String[] queryOperators;
+
+    public MockPropertyDefinition(String declaringNodeTypeName, 
NodeTypeManager ntMgr) {
+        super(declaringNodeTypeName, ntMgr);
+    }
+
+    @Override
+    public int getRequiredType() {
+        return type;
+    }
+
+    @Override
+    public String[] getValueConstraints() {
+        return constraints;
+    }
+
+    @Override
+    public Value[] getDefaultValues() {
+        return defaultValues;
+    }
+
+    @Override
+    public boolean isMultiple() {
+        return multiple;
+    }
+
+    @Override
+    public String[] getAvailableQueryOperators() {
+        return queryOperators;
+    }
+
+    @Override
+    public boolean isFullTextSearchable() {
+        return fullTextSearchable;
+    }
+
+    @Override
+    public boolean isQueryOrderable() {
+        return queryOrderable;
+    }
+
+}
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinitionTemplate.java
 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinitionTemplate.java
new file mode 100644
index 0000000..b79939a
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockPropertyDefinitionTemplate.java
@@ -0,0 +1,110 @@
+/*
+ * 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.testing.mock.jcr;
+
+import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
+
+/**
+ *
+ */
+class MockPropertyDefinitionTemplate extends MockPropertyDefinition implements 
PropertyDefinitionTemplate {
+
+    public MockPropertyDefinitionTemplate(String declaringNodeTypeName, 
NodeTypeManager ntMgr) {
+        super(declaringNodeTypeName, ntMgr);
+    }
+
+    public MockPropertyDefinitionTemplate(String declaringNodeTypeName, 
NodeTypeManager ntMgr, PropertyDefinition propDef) {
+        this(declaringNodeTypeName, ntMgr);
+        // copy ctor
+        this.type = propDef.getRequiredType();
+        this.constraints = propDef.getValueConstraints();
+        this.defaultValues = propDef.getDefaultValues();
+        this.multiple = propDef.isMultiple();
+        this.fullTextSearchable = propDef.isFullTextSearchable();
+        this.queryOrderable = propDef.isQueryOrderable();
+        this.queryOperators = propDef.getAvailableQueryOperators();
+    }
+
+    @Override
+    public void setName(String name) throws ConstraintViolationException {
+        this.name = name;
+    }
+
+    @Override
+    public void setAutoCreated(boolean autoCreated) {
+        this.autoCreated = autoCreated;
+    }
+
+    @Override
+    public void setMandatory(boolean mandatory) {
+        this.mandatory = mandatory;
+    }
+
+    @Override
+    public void setOnParentVersion(int opv) {
+        this.opv = opv;
+    }
+
+    @Override
+    public void setProtected(boolean protectedStatus) {
+        this.protectedStatus = protectedStatus;
+    }
+
+    @Override
+    public void setRequiredType(int type) {
+        this.type = type;
+    }
+
+    @Override
+    public void setValueConstraints(String[] constraints) {
+        this.constraints = constraints;
+    }
+
+    @Override
+    public void setDefaultValues(Value[] defaultValues) {
+        this.defaultValues = defaultValues;
+    }
+
+    @Override
+    public void setMultiple(boolean multiple) {
+        this.multiple = multiple;
+    }
+
+    @Override
+    public void setAvailableQueryOperators(String[] operators) {
+        this.queryOperators = operators;
+    }
+
+    @Override
+    public void setFullTextSearchable(boolean fullTextSearchable) {
+        this.fullTextSearchable = fullTextSearchable;
+    }
+
+    @Override
+    public void setQueryOrderable(boolean queryOrderable) {
+        this.queryOrderable = queryOrderable;
+    }
+
+    public void setDeclaringNodeType(String declaringNodeTypeName) {
+        this.declaringNodeTypeName = declaringNodeTypeName;
+    }
+
+}
diff --git 
a/src/main/java/org/apache/sling/testing/mock/jcr/MockTemplateBuilderFactory.java
 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockTemplateBuilderFactory.java
new file mode 100644
index 0000000..da46612
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/testing/mock/jcr/MockTemplateBuilderFactory.java
@@ -0,0 +1,267 @@
+/*
+ * 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.testing.mock.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
+
+import org.apache.jackrabbit.commons.cnd.CompactNodeTypeDefReader;
+import org.apache.jackrabbit.commons.cnd.DefinitionBuilderFactory;
+import org.apache.jackrabbit.commons.cnd.TemplateBuilderFactory;
+
+
+/**
+ * This is a fork of the {@link TemplateBuilderFactory} that changes the 
implementation
+ * of {@link NodeDefinitionTemplateBuilder#setDeclaringNodeType(String)} 
+ * and {@link PropertyDefinitionTemplateBuilder#setDeclaringNodeType(String)} 
so the
+ * declaring node type is assigned to the template items instead of doing 
nothing.
+ * 
+ * This implementation of {@link DefinitionBuilderFactory} can be used with
+ * the {@link CompactNodeTypeDefReader} to produce node type definitions of 
type
+ * {@link NodeTypeTemplate} and a namespace map of type {@link 
NamespaceRegistry}.
+ * It uses {@link NodeTypeTemplateBuilder} for building node type definitions,
+ * {@link PropertyDefinitionTemplateBuilder} for building property 
definitions, and
+ * {@link NodeDefinitionTemplateBuilder} for building node definitions.
+ */
+class MockTemplateBuilderFactory extends 
DefinitionBuilderFactory<NodeTypeTemplate, NamespaceRegistry> {
+
+    private final NodeTypeManager nodeTypeManager;
+    private final ValueFactory valueFactory;
+    private NamespaceRegistry namespaceRegistry;
+
+    public MockTemplateBuilderFactory(NodeTypeManager nodeTypeManager, 
ValueFactory valueFactory,
+            NamespaceRegistry namespaceRegistry) {
+
+        this.nodeTypeManager = nodeTypeManager;
+        this.valueFactory = valueFactory;
+        this.namespaceRegistry = namespaceRegistry;
+    }
+
+    /**
+     * Creates a new <code>TemplateBuilderFactory</code> for the specified
+     * <code>Session</code>. This is equivalent to
+     * {@link #TemplateBuilderFactory(NodeTypeManager, ValueFactory, 
NamespaceRegistry)}
+     * where all parameters are obtained from the given session object and
+     * the workspace associated with it.
+     *
+     * @param session The repository session.
+     * @throws RepositoryException If an error occurs.
+     */
+    public MockTemplateBuilderFactory(Session session) throws 
RepositoryException {
+        this(session.getWorkspace().getNodeTypeManager(), 
session.getValueFactory(), session.getWorkspace().getNamespaceRegistry());
+    }
+
+    @Override
+    public AbstractNodeTypeDefinitionBuilder<NodeTypeTemplate> 
newNodeTypeDefinitionBuilder()
+            throws RepositoryException {
+        return new NodeTypeTemplateBuilder();
+    }
+
+    @Override
+    public void setNamespaceMapping(NamespaceRegistry namespaceRegistry) {
+        this.namespaceRegistry = namespaceRegistry;
+    }
+
+    @Override
+    public NamespaceRegistry getNamespaceMapping() {
+        return namespaceRegistry;
+    }
+
+    @Override
+    public void setNamespace(String prefix, String uri) {
+        try {
+            namespaceRegistry.registerNamespace(prefix, uri);
+        } catch (RepositoryException e) {
+            // ignore
+        }
+    }
+
+    public class NodeTypeTemplateBuilder extends 
AbstractNodeTypeDefinitionBuilder<NodeTypeTemplate> {
+        private final NodeTypeTemplate template;
+        private final List<String> supertypes = new ArrayList<>();
+
+        public NodeTypeTemplateBuilder() throws RepositoryException {
+            super();
+            template = nodeTypeManager.createNodeTypeTemplate();
+        }
+
+        @Override
+        public AbstractNodeDefinitionBuilder<NodeTypeTemplate> 
newNodeDefinitionBuilder()
+                throws RepositoryException {
+
+            return new NodeDefinitionTemplateBuilder(this);
+        }
+
+        @Override
+        public AbstractPropertyDefinitionBuilder<NodeTypeTemplate> 
newPropertyDefinitionBuilder()
+                throws RepositoryException {
+
+            return new PropertyDefinitionTemplateBuilder(this);
+        }
+
+        @Override
+        public NodeTypeTemplate build() throws ConstraintViolationException {
+            template.setMixin(super.isMixin);
+            template.setOrderableChildNodes(super.isOrderable);
+            template.setAbstract(super.isAbstract);
+            template.setQueryable(super.queryable);
+            template.setDeclaredSuperTypeNames(supertypes.toArray(new 
String[supertypes.size()]));
+            return template;
+        }
+
+        @Override
+        public void setName(String name) throws RepositoryException {
+            super.setName(name);
+            template.setName(name);
+        }
+
+        @Override
+        public void addSupertype(String name) {
+            supertypes.add(name);
+        }
+
+        @Override
+        public void setPrimaryItemName(String name) throws 
ConstraintViolationException {
+            template.setPrimaryItemName(name);
+        }
+
+    }
+
+    public class PropertyDefinitionTemplateBuilder extends
+            AbstractPropertyDefinitionBuilder<NodeTypeTemplate> {
+
+        private final NodeTypeTemplateBuilder ntd;
+        private final PropertyDefinitionTemplate template;
+        private final List<Value> values = new ArrayList<>();
+        private final List<String> constraints = new ArrayList<>();
+
+        public PropertyDefinitionTemplateBuilder(NodeTypeTemplateBuilder ntd)
+                throws RepositoryException {
+
+            super();
+            this.ntd = ntd;
+            template = nodeTypeManager.createPropertyDefinitionTemplate();
+        }
+
+        @Override
+        public void setName(String name) throws RepositoryException {
+            super.setName(name);
+            template.setName(name);
+        }
+
+        @Override
+        public void addDefaultValues(String value) throws ValueFormatException 
{
+            values.add(valueFactory.createValue(value, getRequiredType()));
+        }
+
+        @Override
+        public void addValueConstraint(String constraint) {
+            constraints.add(constraint);
+        }
+
+        @Override
+        public void setDeclaringNodeType(String name) {
+            if (template instanceof MockPropertyDefinitionTemplate) {
+                
((MockPropertyDefinitionTemplate)template).setDeclaringNodeType(name);
+            }
+        }
+
+        @Override
+        public void build() throws IllegalStateException {
+            template.setAutoCreated(super.autocreate);
+            template.setMandatory(super.isMandatory);
+            template.setOnParentVersion(super.onParent);
+            template.setProtected(super.isProtected);
+            template.setRequiredType(super.requiredType);
+            template.setValueConstraints(constraints.toArray(new 
String[constraints.size()]));
+            template.setDefaultValues(values.toArray(new 
Value[values.size()]));
+            template.setMultiple(super.isMultiple);
+            template.setAvailableQueryOperators(super.queryOperators);
+            template.setFullTextSearchable(super.fullTextSearchable);
+            template.setQueryOrderable(super.queryOrderable);
+
+            @SuppressWarnings("unchecked")
+            List<PropertyDefinitionTemplate> templates = 
ntd.template.getPropertyDefinitionTemplates();
+            templates.add(template);
+        }
+
+    }
+
+    public class NodeDefinitionTemplateBuilder extends 
AbstractNodeDefinitionBuilder<NodeTypeTemplate> {
+        private final NodeTypeTemplateBuilder ntd;
+        private final NodeDefinitionTemplate template;
+        private final List<String> requiredPrimaryTypes = new ArrayList<>();
+
+        public NodeDefinitionTemplateBuilder(NodeTypeTemplateBuilder ntd)
+                throws RepositoryException {
+
+            super();
+            this.ntd = ntd;
+            template = nodeTypeManager.createNodeDefinitionTemplate();
+        }
+
+        @Override
+        public void setName(String name) throws RepositoryException {
+            super.setName(name);
+            template.setName(name);
+        }
+
+        @Override
+        public void addRequiredPrimaryType(String name) {
+            requiredPrimaryTypes.add(name);
+        }
+
+        @Override
+        public void setDefaultPrimaryType(String name) throws 
ConstraintViolationException {
+            template.setDefaultPrimaryTypeName(name);
+        }
+
+        @Override
+        public void setDeclaringNodeType(String name) {
+            if (template instanceof MockNodeDefinitionTemplate) {
+                
((MockNodeDefinitionTemplate)template).setDeclaringNodeType(name);
+            }
+        }
+
+        @Override
+        public void build() throws ConstraintViolationException {
+            template.setAutoCreated(super.autocreate);
+            template.setMandatory(super.isMandatory);
+            template.setOnParentVersion(super.onParent);
+            template.setProtected(super.isProtected);
+            template.setRequiredPrimaryTypeNames(requiredPrimaryTypes
+                    .toArray(new String[requiredPrimaryTypes.size()]));
+            template.setSameNameSiblings(super.allowSns);
+
+            @SuppressWarnings("unchecked")
+            List<NodeDefinitionTemplate> templates = 
ntd.template.getNodeDefinitionTemplates();
+            templates.add(template);
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/testing/mock/jcr/package-info.java 
b/src/main/java/org/apache/sling/testing/mock/jcr/package-info.java
index d4d3b89..b14419d 100644
--- a/src/main/java/org/apache/sling/testing/mock/jcr/package-info.java
+++ b/src/main/java/org/apache/sling/testing/mock/jcr/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Mock implementation of selected JCR APIs.
  */
[email protected]("1.1.0")
[email protected]("1.2.0")
 package org.apache.sling.testing.mock.jcr;
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/AbstractMockNodeTypeTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/AbstractMockNodeTypeTest.java
new file mode 100644
index 0000000..37b8732
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/testing/mock/jcr/AbstractMockNodeTypeTest.java
@@ -0,0 +1,255 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ *
+ */
+public abstract class AbstractMockNodeTypeTest {
+    protected Session session;
+    protected NodeTypeManager nodeTypeManager;
+
+    @Before
+    public void setUp() throws RepositoryException, ParseException, 
IOException {
+        this.session = MockJcr.newSession();
+        loadNodeTypes();
+        nodeTypeManager = this.session.getWorkspace().getNodeTypeManager();
+    }
+
+    protected abstract void loadNodeTypes() throws ParseException, 
RepositoryException, IOException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#MockNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testMockNodeTypeString() {
+        MockNodeType mockNodeType = new MockNodeType(JcrConstants.NT_FOLDER);
+        assertEquals(JcrConstants.NT_FOLDER, mockNodeType.getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#MockNodeType(java.lang.String, 
javax.jcr.nodetype.NodeTypeManager)}.
+     */
+    @Test
+    public void testMockNodeTypeStringNodeTypeManager() {
+        MockNodeType mockNodeType = new MockNodeType(JcrConstants.NT_FOLDER, 
nodeTypeManager);
+        assertEquals(JcrConstants.NT_FOLDER, mockNodeType.getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#MockNodeType(javax.jcr.nodetype.NodeTypeDefinition,
 javax.jcr.nodetype.NodeTypeManager)}.
+     */
+    @Test
+    public void testMockNodeTypeNodeTypeDefinitionNodeTypeManager() {
+        NodeTypeDefinition mockNtd = Mockito.mock(NodeTypeDefinition.class);
+        Mockito.when(mockNtd.getName()).thenReturn(JcrConstants.NT_FOLDER);
+        MockNodeType mockNodeType = new MockNodeType(mockNtd, nodeTypeManager);
+        assertEquals(JcrConstants.NT_FOLDER, mockNodeType.getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getName()}.
+     */
+    @Test
+    public void testGetName() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertEquals(JcrConstants.NT_FOLDER, ntFolder.getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isNodeType(java.lang.String)}.
+     */
+    public abstract void testIsNodeType() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#hasOrderableChildNodes()}.
+     */
+    @Test
+    public void testHasOrderableChildNodes() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertFalse(ntFolder.hasOrderableChildNodes());
+
+        NodeType ntUnstructured = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertTrue(ntUnstructured.hasOrderableChildNodes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canAddChildNode(java.lang.String)}.
+     */
+    @Test
+    public void testCanAddChildNodeString() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canAddChildNode("child1"));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canAddChildNode(java.lang.String,
 java.lang.String)}.
+     */
+    @Test
+    public void testCanAddChildNodeStringString() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canAddChildNode("child1", JcrConstants.NT_UNSTRUCTURED));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canRemoveItem(java.lang.String)}.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    @Test
+    public void testCanRemoveItem() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canRemoveItem("child1"));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canSetProperty(java.lang.String, 
javax.jcr.Value)}.
+     */
+    @Test
+    public void testCanSetPropertyStringValue() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        Value value1 = ValueFactoryImpl.getInstance().createValue("value1");
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canSetProperty("prop1", value1));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canSetProperty(java.lang.String, 
javax.jcr.Value[])}.
+     */
+    @Test
+    public void testCanSetPropertyStringValueArray() throws 
RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        Value value1 = ValueFactoryImpl.getInstance().createValue("value1");
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canSetProperty("prop1", new Value[] {value1}));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getChildNodeDefinitions()}.
+     */
+    public abstract void testGetChildNodeDefinitions() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredChildNodeDefinitions()}.
+     */
+    public abstract void testGetDeclaredChildNodeDefinitions() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredPropertyDefinitions()}.
+     */
+    public abstract void testGetDeclaredPropertyDefinitions() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypes()}.
+     */
+    public abstract void testGetDeclaredSupertypes() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPrimaryItemName()}.
+     */
+    public abstract void testGetPrimaryItemName() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPropertyDefinitions()}.
+     */
+    public abstract void testGetPropertyDefinitions() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSupertypes()}.
+     */
+    public abstract void testGetSupertypes() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isMixin()}.
+     */
+    public abstract void testIsMixin() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canRemoveNode(java.lang.String)}.
+     */
+    @Test
+    public void testCanRemoveNode() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canRemoveNode("child1"));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#canRemoveProperty(java.lang.String)}.
+     */
+    @Test
+    public void testCanRemoveProperty() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_UNSTRUCTURED);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.canRemoveProperty("prop1"));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSubtypes()}.
+     */
+    public abstract void testGetDeclaredSubtypes() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSubtypes()}.
+     */
+    public abstract void testGetSubtypes() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypeNames()}.
+     */
+    public abstract void testGetDeclaredSupertypeNames() throws 
RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isAbstract()}.
+     */
+    public abstract void testIsAbstract() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isQueryable()}.
+     */
+    public abstract void testIsQueryable() throws RepositoryException;
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#toString()}.
+     */
+    @Test
+    public void testToString() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        String string = ntFolder.toString();
+        assertNotNull(string);
+        assertTrue(string.contains(JcrConstants.NT_FOLDER));
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeOnlyRegisteredTypesTest.java
 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeOnlyRegisteredTypesTest.java
new file mode 100644
index 0000000..63f2408
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeOnlyRegisteredTypesTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MockNodeOnlyRegisteredTypesTest {
+    protected Session session;
+    protected Node rootNode;
+    protected Node node1;
+
+    @Before
+    public void setUp() throws RepositoryException, IOException, 
ParseException {
+        this.session = MockJcr.newSession();
+        // load the node types and switch the nodetypemanager to 
ONLY_REGISTERED mode
+        try (Reader reader = new 
InputStreamReader(getClass().getResourceAsStream("test_nodetypes.cnd"))) {
+            MockJcr.loadNodeTypeDefs(this.session, reader);
+        }
+
+        this.rootNode = this.session.getRootNode();
+        this.node1 = this.rootNode.addNode("node1");
+    }
+
+    @Test
+    public void testAutocreatedItemsForPrimaryType() throws 
RepositoryException {
+        Node auto1 = this.node1.addNode("auto1", "nt:autocreatedChildAndProp");
+        assertTrue(auto1.hasProperty("prop1"));
+        assertTrue(auto1.hasProperty("prop2"));
+        assertTrue(auto1.hasNode("child1"));
+    }
+    @Test
+    public void testAutocreatedItemsForMixin() throws RepositoryException {
+        Node auto1 = this.node1.addNode("auto1");
+        auto1.addMixin("mix:autocreatedChildAndProp");
+        assertTrue(auto1.hasProperty("prop1"));
+        assertTrue(auto1.hasProperty("prop2"));
+        assertTrue(auto1.hasNode("child1"));
+    }
+
+    @Test
+    public void testGetDefinition() throws RepositoryException {
+        Node def1 = this.node1.addNode("def1", JcrConstants.NT_FOLDER);
+        NodeDefinition definition1 = def1.getDefinition();
+        assertNotNull(definition1);
+        assertEquals("*", definition1.getName());
+
+        Node def2 = this.node1.addNode("def2", "nt:autocreatedChildAndProp");
+        Node def2child1 = def2.getNode("child1");
+        assertNotNull(def2child1);
+        NodeDefinition definition2 = def2child1.getDefinition();
+        assertNotNull(definition2);
+        assertEquals("child1", definition2.getName());
+
+        Node def3 = this.node1.addNode("def3");
+        def3.addMixin("mix:autocreatedChildAndProp");
+        Node def3child1 = def3.getNode("child1");
+        assertNotNull(def3child1);
+        NodeDefinition definition3 = def3child1.getDefinition();
+        assertNotNull(definition3);
+        assertEquals("child1", definition3.getName());
+
+        NodeType def3child1DefaultPrimaryType = 
definition3.getDefaultPrimaryType();
+        assertNotNull(def3child1DefaultPrimaryType);
+        assertEquals(JcrConstants.NT_FOLDER, 
def3child1DefaultPrimaryType.getName());
+
+        // verify the child definition was defined in the primary type
+        NodeType mixAutoCreatedChildAndProp = 
this.session.getWorkspace().getNodeTypeManager().getNodeType("mix:autocreatedChildAndProp");
+        assertEquals(mixAutoCreatedChildAndProp, 
definition3.getDeclaringNodeType());
+
+        NodeType[] def3child1RequiredPrimaryTypes = 
definition3.getRequiredPrimaryTypes();
+        assertNotNull(def3child1RequiredPrimaryTypes);
+        assertEquals(1, def3child1RequiredPrimaryTypes.length);
+        assertEquals(JcrConstants.NT_BASE, 
def3child1RequiredPrimaryTypes[0].getName());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTest.java
index 3af6758..6fc055d 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTest.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -40,6 +41,7 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.util.TraversingItemVisitor;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.junit.Assert;
@@ -365,4 +367,44 @@ public class MockNodeTest extends AbstractItemTest {
         assertFalse(this.node1.isSame(otherNode1));
     }
 
+    @Test
+    public void testAccept() throws RepositoryException {
+        Node foo = this.session.getRootNode().addNode("foo");
+        foo.addNode("child100");
+        foo.addNode("child10");
+        foo.addNode("child1");
+
+        final List<String> leaveNodes = new ArrayList<>();
+        final List<String> leaveProperties = new ArrayList<>();
+        final List<String> enterNodes = new ArrayList<>();
+        final List<String> enterProperties = new ArrayList<>();
+        foo.accept(new TraversingItemVisitor() {
+            @Override
+            protected void leaving(Node node, int level) throws 
RepositoryException {
+                leaveNodes.add(node.getPath());
+            }
+
+            @Override
+            protected void leaving(Property property, int level) throws 
RepositoryException {
+                leaveProperties.add(property.getPath());
+            }
+
+            @Override
+            protected void entering(Node node, int level) throws 
RepositoryException {
+                enterNodes.add(node.getPath());
+            }
+
+            @Override
+            protected void entering(Property property, int level) throws 
RepositoryException {
+                enterProperties.add(property.getPath());
+            }
+        });
+
+        assertEquals(4, enterNodes.size());
+        assertEquals(4, leaveNodes.size());
+
+        assertEquals(4, enterProperties.size());
+        assertEquals(4, leaveProperties.size());
+    }
+
 }
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeAllModeTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeAllModeTest.java
new file mode 100644
index 0000000..2b28bbf
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeAllModeTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class MockNodeTypeAllModeTest extends AbstractMockNodeTypeTest {
+
+    @Override
+    protected void loadNodeTypes() throws ParseException, RepositoryException, 
IOException {
+        // don't load any nodetypes, defaults to the 
MockNodeTypeManager.ResolveMode.MOCK_ALL mode
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testIsNodeType() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertTrue(ntFolder.isNodeType(JcrConstants.NT_FOLDER));
+        // doesn't support inheritance so false is expected
+        assertFalse(ntFolder.isNodeType(JcrConstants.NT_BASE));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getChildNodeDefinitions()}.
+     */
+    @Test
+    public void testGetChildNodeDefinitions() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getChildNodeDefinitions());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredChildNodeDefinitions()}.
+     */
+    @Test
+    public void testGetDeclaredChildNodeDefinitions() throws 
RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getDeclaredChildNodeDefinitions());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredPropertyDefinitions()}.
+     */
+    @Test
+    public void testGetDeclaredPropertyDefinitions() throws 
RepositoryException {
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntBase.getDeclaredPropertyDefinitions());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypes()}.
+     */
+    @Test
+    public void testGetDeclaredSupertypes() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getDeclaredSupertypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPrimaryItemName()}.
+     */
+    @Test
+    public void testGetPrimaryItemName() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getPrimaryItemName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPropertyDefinitions()}.
+     */
+    @Test
+    public void testGetPropertyDefinitions() throws RepositoryException {
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntBase.getPropertyDefinitions());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSupertypes()}.
+     */
+    @Test
+    public void testGetSupertypes() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getSupertypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isMixin()}.
+     */
+    @Test
+    public void testIsMixin() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.isMixin());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSubtypes()}.
+     */
+    @Test
+    public void testGetDeclaredSubtypes() throws RepositoryException {
+        NodeType mixCreated = nodeTypeManager.getNodeType("mix:created");
+        assertThrows(UnsupportedOperationException.class, () -> 
mixCreated.getDeclaredSubtypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSubtypes()}.
+     */
+    @Test
+    public void testGetSubtypes() throws RepositoryException {
+        NodeType mixCreated = nodeTypeManager.getNodeType("mix:created");
+        assertThrows(UnsupportedOperationException.class, () -> 
mixCreated.getSubtypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypeNames()}.
+     */
+    @Test
+    public void testGetDeclaredSupertypeNames() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.getDeclaredSupertypeNames());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isAbstract()}.
+     */
+    @Test
+    public void testIsAbstract() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.isAbstract());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isQueryable()}.
+     */
+    @Test
+    public void testIsQueryable() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
ntFolder.isQueryable());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerAllModeTest.java
 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerAllModeTest.java
new file mode 100644
index 0000000..5c1e375
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerAllModeTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Tests the MockNodeTypeManager when in the MOCK_ALL mode
+ */
+public class MockNodeTypeManagerAllModeTest {
+
+    private static final String NT_INVALID = "nt:invalid";
+    protected Session session;
+    protected NodeTypeManager nodeTypeManager;
+
+    @Before
+    public void setUp() throws RepositoryException, ParseException, 
IOException {
+        this.session = MockJcr.newSession();
+        // don't load any nodetypes, defaults to the 
MockNodeTypeManager.ResolveMode.MOCK_ALL mode
+        nodeTypeManager = this.session.getWorkspace().getNodeTypeManager();
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testGetNodeType() throws RepositoryException {
+        NodeType nodeType = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertNotNull(nodeType);
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#hasNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testHasNodeType() throws RepositoryException {
+        assertTrue(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getAllNodeTypes()}.
+     */
+    @Test
+    public void testGetAllNodeTypes() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.getAllNodeTypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getPrimaryNodeTypes()}.
+     */
+    @Test
+    public void testGetPrimaryNodeTypes() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.getPrimaryNodeTypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getMixinNodeTypes()}.
+     */
+    @Test
+    public void testGetMixinNodeTypes() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.getMixinNodeTypes());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeTypeTemplate()}.
+     */
+    @Test
+    public void testCreateNodeTypeTemplate() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.createNodeTypeTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeTypeTemplate(javax.jcr.nodetype.NodeTypeDefinition)}.
+     */
+    @Test
+    public void testCreateNodeTypeTemplateNodeTypeDefinition() throws 
RepositoryException {
+        NodeTypeDefinition ntd = Mockito.mock(NodeTypeDefinition.class);
+        Mockito.when(ntd.getName()).thenReturn("nt:fake");
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.createNodeTypeTemplate(ntd));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeDefinitionTemplate()}.
+     */
+    @Test
+    public void testCreateNodeDefinitionTemplate() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.createNodeDefinitionTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createPropertyDefinitionTemplate()}.
+     */
+    @Test
+    public void testCreatePropertyDefinitionTemplate() throws 
RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.createPropertyDefinitionTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#registerNodeType(javax.jcr.nodetype.NodeTypeDefinition,
 boolean)}.
+     */
+    @Test
+    public void testRegisterNodeType() throws RepositoryException {
+        MockNodeTypeTemplate testDef = new MockNodeTypeTemplate();
+        testDef.setName(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.registerNodeType((NodeTypeDefinition) testDef, false));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#registerNodeTypes(javax.jcr.nodetype.NodeTypeDefinition[],
 boolean)}.
+     */
+    @Test
+    public void testRegisterNodeTypes() throws RepositoryException {
+        MockNodeTypeTemplate testDef1 = new MockNodeTypeTemplate();
+        testDef1.setName(JcrConstants.NT_FOLDER);
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.registerNodeTypes(new NodeTypeDefinition[] {testDef1}, false));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#unregisterNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testUnregisterNodeType() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.unregisterNodeType(NT_INVALID));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#unregisterNodeTypes(java.lang.String[])}.
+     */
+    @Test
+    public void testUnregisterNodeTypes() throws RepositoryException {
+        assertThrows(UnsupportedOperationException.class, () -> 
nodeTypeManager.unregisterNodeTypes(new String[] {NT_INVALID}));
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerTest.java
new file mode 100644
index 0000000..c1ae478
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeManagerTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeExistsException;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Tests the MockNodeTypeManager when in the ONLY_REGISTERED mode
+ *
+ */
+public class MockNodeTypeManagerTest {
+
+    private static final String NT_INVALID = "nt:invalid";
+    protected Session session;
+    protected NodeTypeManager nodeTypeManager;
+
+    @Before
+    public void setUp() throws RepositoryException, ParseException, 
IOException {
+        this.session = MockJcr.newSession();
+        try (Reader reader = new 
InputStreamReader(getClass().getResourceAsStream("test_nodetypes.cnd"))) {
+            MockJcr.loadNodeTypeDefs(this.session, reader);
+        }
+        nodeTypeManager = this.session.getWorkspace().getNodeTypeManager();
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testGetNodeType() throws RepositoryException {
+        NodeType nodeType = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertNotNull(nodeType);
+
+        assertThrows(NoSuchNodeTypeException.class, () -> 
nodeTypeManager.getNodeType(NT_INVALID));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#hasNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testHasNodeType() throws RepositoryException {
+        assertTrue(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getAllNodeTypes()}.
+     */
+    @Test
+    public void testGetAllNodeTypes() throws RepositoryException {
+        NodeTypeIterator allNodeTypes = nodeTypeManager.getAllNodeTypes();
+        assertTrue(allNodeTypes.hasNext());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getPrimaryNodeTypes()}.
+     */
+    @Test
+    public void testGetPrimaryNodeTypes() throws RepositoryException {
+        NodeTypeIterator primaryNodeTypes = 
nodeTypeManager.getPrimaryNodeTypes();
+        assertTrue(primaryNodeTypes.hasNext());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#getMixinNodeTypes()}.
+     */
+    @Test
+    public void testGetMixinNodeTypes() throws RepositoryException {
+        NodeTypeIterator mixinNodeTypes = nodeTypeManager.getMixinNodeTypes();
+        assertTrue(mixinNodeTypes.hasNext());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeTypeTemplate()}.
+     */
+    @Test
+    public void testCreateNodeTypeTemplate() throws RepositoryException {
+        assertNotNull(nodeTypeManager.createNodeTypeTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeTypeTemplate(javax.jcr.nodetype.NodeTypeDefinition)}.
+     */
+    @Test
+    public void testCreateNodeTypeTemplateNodeTypeDefinition() throws 
RepositoryException {
+        NodeTypeDefinition ntd = Mockito.mock(NodeTypeDefinition.class);
+        Mockito.when(ntd.getName()).thenReturn("nt:fake");
+        assertNotNull(nodeTypeManager.createNodeTypeTemplate(ntd));
+
+        NodeType ntFile = nodeTypeManager.getNodeType(JcrConstants.NT_FILE);
+        NodeTypeTemplate template2 = 
nodeTypeManager.createNodeTypeTemplate(ntFile);
+        assertNotNull(template2);
+        assertEquals(1, template2.getNodeDefinitionTemplates().size());
+
+        NodeType mixReferenceable = 
nodeTypeManager.getNodeType(JcrConstants.MIX_REFERENCEABLE);
+        NodeTypeTemplate template3 = 
nodeTypeManager.createNodeTypeTemplate(mixReferenceable);
+        assertNotNull(template3);
+        assertEquals(1, template3.getPropertyDefinitionTemplates().size());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createNodeDefinitionTemplate()}.
+     */
+    @Test
+    public void testCreateNodeDefinitionTemplate() throws RepositoryException {
+        assertNotNull(nodeTypeManager.createNodeDefinitionTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#createPropertyDefinitionTemplate()}.
+     */
+    @Test
+    public void testCreatePropertyDefinitionTemplate() throws 
RepositoryException {
+        assertNotNull(nodeTypeManager.createPropertyDefinitionTemplate());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#registerNodeType(javax.jcr.nodetype.NodeTypeDefinition,
 boolean)}.
+     */
+    @Test
+    public void testRegisterNodeType() throws RepositoryException {
+        MockNodeTypeTemplate testDef = new MockNodeTypeTemplate();
+        testDef.setName(JcrConstants.NT_FOLDER);
+
+        // update not allowed
+        assertThrows(NodeTypeExistsException.class, () -> 
nodeTypeManager.registerNodeType((NodeTypeDefinition) testDef, false));
+
+        // update allowed
+        nodeTypeManager.registerNodeType((NodeTypeDefinition) testDef, true);
+        assertTrue(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+
+        // create a new one
+        MockNodeTypeTemplate testDef2 = new MockNodeTypeTemplate();
+        testDef2.setName(NT_INVALID);
+        nodeTypeManager.registerNodeType((NodeTypeDefinition) testDef2, true);
+        assertTrue(nodeTypeManager.hasNodeType(NT_INVALID));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#registerNodeTypes(javax.jcr.nodetype.NodeTypeDefinition[],
 boolean)}.
+     */
+    @Test
+    public void testRegisterNodeTypes() throws RepositoryException {
+        MockNodeTypeTemplate testDef1 = new MockNodeTypeTemplate();
+        testDef1.setName(JcrConstants.NT_FOLDER);
+        MockNodeTypeTemplate testDef2 = new MockNodeTypeTemplate();
+        testDef2.setName(NT_INVALID);
+
+        // update not allowed
+        assertThrows(NodeTypeExistsException.class, () -> 
nodeTypeManager.registerNodeTypes(new NodeTypeDefinition[] {testDef1, 
testDef2}, false));
+
+        // update allowed
+        nodeTypeManager.registerNodeTypes(new NodeTypeDefinition[] {testDef1, 
testDef2}, true);
+        assertTrue(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+        assertTrue(nodeTypeManager.hasNodeType(NT_INVALID));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#unregisterNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testUnregisterNodeType() throws RepositoryException {
+        assertThrows(NoSuchNodeTypeException.class, () -> 
nodeTypeManager.unregisterNodeType(NT_INVALID));
+
+        nodeTypeManager.unregisterNodeType(JcrConstants.NT_FOLDER);
+        assertFalse(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeTypeManager#unregisterNodeTypes(java.lang.String[])}.
+     */
+    @Test
+    public void testUnregisterNodeTypes() throws RepositoryException {
+        assertThrows(NoSuchNodeTypeException.class, () -> 
nodeTypeManager.unregisterNodeTypes(new String[] {NT_INVALID}));
+
+        nodeTypeManager.unregisterNodeTypes(new String[] 
{JcrConstants.NT_FOLDER});
+        assertFalse(nodeTypeManager.hasNodeType(JcrConstants.NT_FOLDER));
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTest.java
new file mode 100644
index 0000000..b11b9fe
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockNodeTypeTest.java
@@ -0,0 +1,260 @@
+/*
+ * 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.testing.mock.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.stream.Stream;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class MockNodeTypeTest extends AbstractMockNodeTypeTest {
+
+    @Override
+    protected void loadNodeTypes() throws ParseException, RepositoryException, 
IOException {
+        try (Reader reader = new 
InputStreamReader(getClass().getResourceAsStream("test_nodetypes.cnd"))) {
+            MockJcr.loadNodeTypeDefs(this.session, reader);
+        }
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isNodeType(java.lang.String)}.
+     */
+    @Test
+    public void testIsNodeType() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertTrue(ntFolder.isNodeType(JcrConstants.NT_FOLDER));
+        assertTrue(ntFolder.isNodeType(JcrConstants.NT_BASE));
+
+        NodeType mixReferenceable = 
nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        assertFalse(mixReferenceable.isNodeType(JcrConstants.NT_FOLDER));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getChildNodeDefinitions()}.
+     */
+    @Test
+    public void testGetChildNodeDefinitions() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        NodeDefinition[] childNodeDefinitions = 
ntFolder.getChildNodeDefinitions();
+        assertEquals(1, childNodeDefinitions.length);
+        assertEquals("*", childNodeDefinitions[0].getName());
+
+        NodeType ntFile = nodeTypeManager.getNodeType(JcrConstants.NT_FILE);
+        childNodeDefinitions = ntFile.getChildNodeDefinitions();
+        assertEquals(1, childNodeDefinitions.length);
+        assertEquals(JcrConstants.JCR_CONTENT, 
childNodeDefinitions[0].getName());
+
+        // test inheritence from supertype
+        NodeType autocreatedChildAndPropExt = 
this.session.getWorkspace().getNodeTypeManager().getNodeType("nt:autocreatedChildAndPropExt");
+        childNodeDefinitions = 
autocreatedChildAndPropExt.getChildNodeDefinitions();
+        assertEquals(2, childNodeDefinitions.length);
+        assertTrue(Stream.of(childNodeDefinitions).anyMatch(cd -> 
"child1".equals(cd.getName())));
+        assertTrue(Stream.of(childNodeDefinitions).anyMatch(cd -> 
"child3".equals(cd.getName())));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredChildNodeDefinitions()}.
+     */
+    @Test
+    public void testGetDeclaredChildNodeDefinitions() throws 
RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        NodeDefinition[] childNodeDefinitions = 
ntFolder.getDeclaredChildNodeDefinitions();
+        assertEquals(1, childNodeDefinitions.length);
+        assertEquals("*", childNodeDefinitions[0].getName());
+
+        NodeType ntFile = nodeTypeManager.getNodeType(JcrConstants.NT_FILE);
+        childNodeDefinitions = ntFile.getDeclaredChildNodeDefinitions();
+        assertEquals(1, childNodeDefinitions.length);
+        assertEquals(JcrConstants.JCR_CONTENT, 
childNodeDefinitions[0].getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredPropertyDefinitions()}.
+     */
+    @Test
+    public void testGetDeclaredPropertyDefinitions() throws 
RepositoryException {
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        PropertyDefinition[] propertyDefinitions = 
ntBase.getDeclaredPropertyDefinitions();
+        assertEquals(2, propertyDefinitions.length);
+        assertEquals(JcrConstants.JCR_PRIMARYTYPE, 
propertyDefinitions[0].getName());
+        assertEquals(JcrConstants.JCR_MIXINTYPES, 
propertyDefinitions[1].getName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypes()}.
+     */
+    @Test
+    public void testGetDeclaredSupertypes() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        NodeType[] supertypes = ntFolder.getDeclaredSupertypes();
+        assertEquals(1, supertypes.length);
+        assertEquals(JcrConstants.NT_HIERARCHYNODE, supertypes[0].getName());
+
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        supertypes = ntBase.getDeclaredSupertypes();
+        assertEquals(0, supertypes.length);
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPrimaryItemName()}.
+     */
+    @Test
+    public void testGetPrimaryItemName() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertNull(ntFolder.getPrimaryItemName());
+
+        NodeType ntFile = nodeTypeManager.getNodeType(JcrConstants.NT_FILE);
+        assertEquals(JcrConstants.JCR_CONTENT, ntFile.getPrimaryItemName());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getPropertyDefinitions()}.
+     */
+    @Test
+    public void testGetPropertyDefinitions() throws RepositoryException {
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        PropertyDefinition[] propertyDefinitions = 
ntBase.getPropertyDefinitions();
+        assertEquals(4, propertyDefinitions.length);
+        assertEquals(JcrConstants.JCR_CREATED, 
propertyDefinitions[0].getName());
+        assertEquals("jcr:createdBy", propertyDefinitions[1].getName());
+        assertEquals(JcrConstants.JCR_PRIMARYTYPE, 
propertyDefinitions[2].getName());
+        assertEquals(JcrConstants.JCR_MIXINTYPES, 
propertyDefinitions[3].getName());
+
+        // test inheritence from supertype
+        NodeType autocreatedChildAndPropExt = 
this.session.getWorkspace().getNodeTypeManager().getNodeType("nt:autocreatedChildAndPropExt");
+        propertyDefinitions = 
autocreatedChildAndPropExt.getPropertyDefinitions();
+        assertEquals(5, propertyDefinitions.length);
+        assertTrue(Stream.of(propertyDefinitions).anyMatch(pd -> 
"prop1".equals(pd.getName())));
+        assertTrue(Stream.of(propertyDefinitions).anyMatch(pd -> 
"prop3".equals(pd.getName())));
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSupertypes()}.
+     */
+    @Test
+    public void testGetSupertypes() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        NodeType[] supertypes = ntFolder.getSupertypes();
+        assertEquals(3, supertypes.length);
+        assertEquals(JcrConstants.NT_HIERARCHYNODE, supertypes[0].getName());
+        assertEquals("mix:created", supertypes[1].getName());
+        assertEquals(JcrConstants.NT_BASE, supertypes[2].getName());
+
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        supertypes = ntBase.getSupertypes();
+        assertEquals(0, supertypes.length);
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isMixin()}.
+     */
+    @Test
+    public void testIsMixin() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertFalse(ntFolder.isMixin());
+
+        NodeType mixReferenceable = 
nodeTypeManager.getNodeType(JcrConstants.MIX_REFERENCEABLE);
+        assertTrue(mixReferenceable.isMixin());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSubtypes()}.
+     */
+    @Test
+    public void testGetDeclaredSubtypes() throws RepositoryException {
+        NodeType mixCreated = nodeTypeManager.getNodeType("mix:created");
+        NodeTypeIterator subtypes = mixCreated.getDeclaredSubtypes();
+        assertEquals(1, subtypes.getSize());
+        assertEquals(JcrConstants.NT_HIERARCHYNODE, 
subtypes.nextNodeType().getName());
+
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        subtypes = ntFolder.getDeclaredSubtypes();
+        assertFalse(subtypes.hasNext());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getSubtypes()}.
+     */
+    @Test
+    public void testGetSubtypes() throws RepositoryException {
+        NodeType mixCreated = nodeTypeManager.getNodeType("mix:created");
+        NodeTypeIterator subtypes = mixCreated.getSubtypes();
+        assertEquals(3, subtypes.getSize());
+        assertEquals(JcrConstants.NT_FILE, subtypes.nextNodeType().getName());
+        assertEquals(JcrConstants.NT_HIERARCHYNODE, 
subtypes.nextNodeType().getName());
+        assertEquals(JcrConstants.NT_FOLDER, 
subtypes.nextNodeType().getName());
+
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        subtypes = ntFolder.getSubtypes();
+        assertFalse(subtypes.hasNext());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#getDeclaredSupertypeNames()}.
+     */
+    @Test
+    public void testGetDeclaredSupertypeNames() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        String[] supertypeNames = ntFolder.getDeclaredSupertypeNames();
+        assertEquals(1, supertypeNames.length);
+        assertEquals(JcrConstants.NT_HIERARCHYNODE, supertypeNames[0]);
+
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        supertypeNames = ntBase.getDeclaredSupertypeNames();
+        assertEquals(0, supertypeNames.length);
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isAbstract()}.
+     */
+    @Test
+    public void testIsAbstract() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertFalse(ntFolder.isAbstract());
+
+        NodeType ntBase = nodeTypeManager.getNodeType(JcrConstants.NT_BASE);
+        assertTrue(ntBase.isAbstract());
+    }
+
+    /**
+     * Test method for {@link 
org.apache.sling.testing.mock.jcr.MockNodeType#isQueryable()}.
+     */
+    @Test
+    public void testIsQueryable() throws RepositoryException {
+        NodeType ntFolder = 
nodeTypeManager.getNodeType(JcrConstants.NT_FOLDER);
+        assertTrue(ntFolder.isQueryable());
+    }
+
+}
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockPropertyTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockPropertyTest.java
index 53e2a8b..2fad327 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockPropertyTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockPropertyTest.java
@@ -21,13 +21,16 @@ package org.apache.sling.testing.mock.jcr;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.List;
 
 import javax.jcr.Node;
 import javax.jcr.Property;
@@ -37,6 +40,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.ValueFormatException;
+import javax.jcr.util.TraversingItemVisitor;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.jackrabbit.value.BinaryValue;
@@ -385,12 +389,12 @@ public class MockPropertyTest extends AbstractItemTest {
         assertEquals(PropertyType.UNDEFINED, prop1.getType());
     }
 
-    @Test(expected=ValueFormatException.class)
+    @Test
     public void testSingleValueAsValueArray() throws RepositoryException {
         this.node1.setProperty("prop1", 
this.session.getValueFactory().createValue("value1"));
         Property prop1 = this.node1.getProperty("prop1");
         assertFalse(prop1.isMultiple());
-        assertEquals("value1", prop1.getValues()[0].getString());
+        assertThrows(ValueFormatException.class, () -> prop1.getValues());
     }
 
     @Test
@@ -437,4 +441,41 @@ public class MockPropertyTest extends AbstractItemTest {
         assertFalse(this.prop1.isSame(otherProp1));
     }
 
+    @Test
+    public void testAccept() throws RepositoryException {
+        Property prop = this.node1.setProperty("prop1", "value1");
+
+        final List<String> leaveNodes = new ArrayList<>();
+        final List<String> leaveProperties = new ArrayList<>();
+        final List<String> enterNodes = new ArrayList<>();
+        final List<String> enterProperties = new ArrayList<>();
+        prop.accept(new TraversingItemVisitor() {
+            @Override
+            protected void leaving(Node node, int level) throws 
RepositoryException {
+                leaveNodes.add(node.getPath());
+            }
+
+            @Override
+            protected void leaving(Property property, int level) throws 
RepositoryException {
+                leaveProperties.add(property.getPath());
+            }
+
+            @Override
+            protected void entering(Node node, int level) throws 
RepositoryException {
+                enterNodes.add(node.getPath());
+            }
+
+            @Override
+            protected void entering(Property property, int level) throws 
RepositoryException {
+                enterProperties.add(property.getPath());
+            }
+        });
+
+        assertEquals(0, enterNodes.size());
+        assertEquals(0, leaveNodes.size());
+
+        assertEquals(1, enterProperties.size());
+        assertEquals(1, leaveProperties.size());
+    }
+
 }
diff --git 
a/src/test/java/org/apache/sling/testing/mock/jcr/MockQueryManagerTest.java 
b/src/test/java/org/apache/sling/testing/mock/jcr/MockQueryManagerTest.java
index bebb827..70173c8 100644
--- a/src/test/java/org/apache/sling/testing/mock/jcr/MockQueryManagerTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/jcr/MockQueryManagerTest.java
@@ -165,7 +165,6 @@ public class MockQueryManagerTest {
         return result1;
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     public void testQueryResults_ResultHandler() throws RepositoryException {
         MockJcr.addQueryResultHandler(queryManager, new 
MockQueryResultHandler() {
@@ -182,7 +181,6 @@ public class MockQueryManagerTest {
         assertEquals(sampleNodes.size(), result.getNodes().getSize());
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     public void testQueryResults_ResultHandler_WithUnknownSize() throws 
RepositoryException {
         MockJcr.addQueryResultHandler(queryManager, new 
MockQueryResultHandler() {
diff --git 
a/src/test/resources/org/apache/sling/testing/mock/jcr/test_nodetypes.cnd 
b/src/test/resources/org/apache/sling/testing/mock/jcr/test_nodetypes.cnd
new file mode 100644
index 0000000..35985d0
--- /dev/null
+++ b/src/test/resources/org/apache/sling/testing/mock/jcr/test_nodetypes.cnd
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+
+//------------------------------------------------------------------------------
+// B A S E  T Y P E
+//------------------------------------------------------------------------------
+
+/**
+ * nt:base is an abstract primary node type that is the base type for all other
+ * primary node types. It is the only primary node type without supertypes.
+ *
+ * @since 1.0
+ */
+[nt:base]
+  abstract
+  - jcr:primaryType (NAME) mandatory autocreated protected COMPUTE
+  - jcr:mixinTypes (NAME) protected multiple COMPUTE
+
+//------------------------------------------------------------------------------
+// S T A N D A R D   A P P L I C A T I O N   N O D E   T Y P E S
+//------------------------------------------------------------------------------
+
+/**
+ * This abstract node type serves as the supertype of nt:file and nt:folder.
+ * @since 1.0
+ */
+[nt:hierarchyNode] > mix:created
+  abstract
+
+/**
+ * Nodes of this type may be used to represent folders or directories. This 
node
+ * type inherits the item definitions of nt:hierarchyNode and adds the ability
+ * to have any number of other nt:hierarchyNode child nodes with any names.
+ * This means, in particular, that it can have child nodes of types nt:folder,
+ * nt:file or nt:linkedFile.
+ *
+ * @since 1.0
+ */
+[nt:folder] > nt:hierarchyNode
+  + * (nt:hierarchyNode) VERSION
+
+/**
+ * Nodes of this node type may be used to represent files. This node type 
inherits
+ * the item definitions of nt:hierarchyNode and requires a single child node 
called
+ * jcr:content. The jcr:content node is used to hold the actual content of the
+ * file. This child node is mandatory, but not auto-created. Its node type 
will be
+ * application-dependent and therefore it must be added by the user. A common
+ * approach is to make the jcr:content a node of type nt:resource or 
oak:Resource. The
+ * jcr:content child node is also designated as the primary child item of its 
parent.
+ *
+ * @since 1.0
+ */
+[nt:file] > nt:hierarchyNode
+  primaryitem jcr:content
+  + jcr:content (nt:base) mandatory
+
+/**
+ * This mixin node type can be used to add standardized creation information
+ * properties to a node. Since the properties are protected, their values are
+ * controlled by the repository, which should set them appropriately upon the
+ * initial persist of a node with this mixin type. In cases where this mixin is
+ * added to an already existing node the semantics of these properties are
+ * implementation specific. Note that jackrabbit initializes the properties to
+ * the current date and user in this case.
+ *
+ *
+ * @since 2.0
+ */
+[mix:created]
+  mixin
+  - jcr:created (DATE) autocreated protected
+  - jcr:createdBy (STRING) autocreated protected
+
+/**
+ * This mixin node type can be used to provide standardized modification
+ * information properties to a node.
+ *
+ * The following is not yet implemented in Jackrabbit:
+ * "Since the properties are protected, their values
+ *  are controlled by the repository, which should set them appropriately upon 
a
+ *  significant modification of the subgraph of a node with this mixin. What
+ *  constitutes a significant modification will depend on the semantics of the 
various
+ *  parts of a node's subgraph and is implementation-dependent"
+ *
+ * Jackrabbit initializes the properties to the current date and user in the
+ * case they are newly created.
+ *
+ * Note that the protected attributes suggested by JSR283 are omitted in this 
variant.
+ * @since 2.0
+ */
+[mix:lastModified]
+  mixin
+  - jcr:lastModified (DATE) autocreated
+  - jcr:lastModifiedBy (STRING) autocreated
+
+//------------------------------------------------------------------------------
+// U N S T R U C T U R E D   C O N T E N T
+//------------------------------------------------------------------------------
+
+/**
+ * This node type is used to store unstructured content. It allows any number 
of
+ * child nodes or properties with any names. It also allows multiple nodes 
having
+ * the same name as well as both multi-value and single-value properties with 
any
+ * names. This node type also supports client-orderable child nodes.
+ *
+ * @since 1.0
+ */
+[nt:unstructured]
+  orderable
+  - * (UNDEFINED) multiple
+  - * (UNDEFINED)
+  + * (nt:base) = nt:unstructured sns VERSION
+
+//------------------------------------------------------------------------------
+// R E F E R E N C E A B L E
+//------------------------------------------------------------------------------
+
+/**
+ * This node type adds an auto-created, mandatory, protected STRING property to
+ * the node, called jcr:uuid, which exposes the identifier of the node.
+ * Note that the term "UUID" is used for backward compatibility with JCR 1.0
+ * and does not necessarily imply the use of the UUID syntax, or global 
uniqueness.
+ * The identifier of a referenceable node must be a referenceable identifier.
+ * Referenceable identifiers must fulfill a number of constraints beyond the
+ * minimum required of standard identifiers (see 3.8.3 Referenceable 
Identifiers).
+ * A reference property is a property that holds the referenceable identifier 
of a
+ * referenceable node and therefore serves as a pointer to that node. The two 
types
+ * of reference properties, REFERENCE and WEAKREFERENCE differ in that the 
former
+ * enforces referential integrity while the latter does not.
+ *
+ * @since 1.0
+ */
+[mix:referenceable]
+  mixin
+  - jcr:uuid (STRING) mandatory autocreated protected INITIALIZE 
+
+
+/**
+ * For code coverage of the cnd loading
+ */
+[nt:toParsePropDefaultValuesndValueConstraint]
+    - prop1 (STRING) = 'value1' autocreated < '^.{1,2000}$'
+
+/**
+ * To test auto-created child and prop when a node of this type is added
+ */
+[nt:autocreatedChildAndProp]
+  + child1 (nt:base) = nt:folder autocreated
+  - prop1 (STRING) = 'value1' autocreated
+  - prop2 (STRING) = 'value1', 'value2' multiple autocreated
+// for testing inheritance
+[nt:autocreatedChildAndPropExt] > nt:autocreatedChildAndProp
+  + child3 (nt:base) = nt:folder autocreated
+  - prop3 (STRING) = 'value1' autocreated
+[mix:autocreatedChildAndProp]
+  mixin
+  + child1 (nt:base) = nt:folder autocreated
+  - prop1 (STRING) = 'value1' autocreated
+  - prop2 (STRING) = 'value1', 'value2' multiple autocreated
+


Reply via email to