@Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowOverridingChildNodeIfRequiredTypesDoNotNarrow() throws Exception {
    /*
     * testNode declares No-SNS childNode testChildNode requiring type nt:hierarchy
     * testNodeB extends testNode with No-SNS childNode testChildNode requiring type nt:base -> ILLEGAL
     */
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(
        new String[] {
          "nt:base",
        });

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:hierarchyNode"});
    child.setSameNameSiblings(false);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
    nodeBTemplate.setName(TEST_TYPE_NAME + "B");
    nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});

    child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    child.setSameNameSiblings(false);
    nodeBTemplate.getNodeDefinitionTemplates().add(child);

    List<NodeTypeDefinition> templates =
        Arrays.asList(new NodeTypeDefinition[] {ntTemplate, nodeBTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @Test
  public void shouldAllowTypeWithMultipleChildNodes() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    child.setSameNameSiblings(true);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:unstructured"});
    child.setSameNameSiblings(false);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME + "2");
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    child.setSameNameSiblings(true);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @SuppressWarnings("unchecked")
  @Test
  public void shouldAllowUnregisteringUnusedTypesWithMutualDependencies() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);

    JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
    childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
    ntTemplate.getNodeDefinitionTemplates().add(childNode);

    NodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(this.context);
    ntTemplate2.setName(TEST_TYPE_NAME2);

    JcrNodeDefinitionTemplate childNode2 = new JcrNodeDefinitionTemplate(this.context);
    childNode2.setDefaultPrimaryTypeName(TEST_TYPE_NAME);
    ntTemplate2.getNodeDefinitionTemplates().add(childNode2);

    try {
      repoTypeManager.registerNodeTypes(
          Arrays.asList(new NodeTypeDefinition[] {ntTemplate, ntTemplate2}));
    } catch (Exception ex) {
      fail(ex.getMessage());
    }

    Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
    Name type2NameAsName = nameFactory.create(TEST_TYPE_NAME2);
    int nodeTypeCount = nodeTypes().getAllNodeTypes().size();
    repoTypeManager.unregisterNodeType(
        Arrays.asList(new Name[] {typeNameAsName, type2NameAsName}), true);
    assertThat(nodeTypes().getAllNodeTypes().size(), is(nodeTypeCount - 2));
    assertThat(nodeTypes().getNodeType(typeNameAsName), is(nullValue()));
    assertThat(nodeTypes().getNodeType(type2NameAsName), is(nullValue()));
  }
  @Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowOverridingChildNodeFromDifferentAncestors() throws Exception {
    /*
     * testNode
     * testNodeB extends testNode and declares node testChildNode
     * testNodeC extends testNode and declares node testChildNode
     * testNodeD extends testNodeB and testNodeC and overrides testChildNode --> ILLEGAL
     */
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(
        new String[] {
          "nt:base",
        });

    JcrNodeTypeTemplate nodeBTemplate = new JcrNodeTypeTemplate(this.context);
    nodeBTemplate.setName(TEST_TYPE_NAME + "B");
    nodeBTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(JcrLexicon.SYSTEM.getString(registry));
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    nodeBTemplate.getNodeDefinitionTemplates().add(child);

    JcrNodeTypeTemplate nodeCTemplate = new JcrNodeTypeTemplate(this.context);
    nodeCTemplate.setName(TEST_TYPE_NAME + "C");
    nodeCTemplate.setDeclaredSuperTypeNames(new String[] {TEST_TYPE_NAME});

    child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(JcrLexicon.SYSTEM.getString(registry));
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    nodeCTemplate.getNodeDefinitionTemplates().add(child);

    JcrNodeTypeTemplate nodeDTemplate = new JcrNodeTypeTemplate(this.context);
    nodeDTemplate.setName(TEST_TYPE_NAME + "D");
    nodeDTemplate.setDeclaredSuperTypeNames(
        new String[] {nodeBTemplate.getName(), nodeCTemplate.getName()});

    List<NodeTypeDefinition> templates =
        Arrays.asList(
            new NodeTypeDefinition[] {ntTemplate, nodeBTemplate, nodeCTemplate, nodeDTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowOverridingProtectedChildNode() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(new String[] {"mode:root", "mix:referenceable"});

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(JcrLexicon.SYSTEM.getString(registry));
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    ntTemplate.getNodeDefinitionTemplates().add(child);

    List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @FixFor("MODE-826")
  @Test
  public void shouldAllowRegisteringNodeTypeWithOnlyResidualChildNodeDefinition() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);

    // Create the residual child node definition ...
    JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
    childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
    childNode.setName("*");
    ntTemplate.getNodeDefinitionTemplates().add(childNode);

    // And register it ...
    repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
  }
  @Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowMandatoryResidualChildNode() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(JcrNodeType.RESIDUAL_ITEM_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    child.setMandatory(true);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowAutocreatedChildNodeWithNoDefaultPrimaryType() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);
    ntTemplate.setDeclaredSuperTypeNames(new String[] {"nt:base", "mix:referenceable"});

    JcrNodeDefinitionTemplate child = new JcrNodeDefinitionTemplate(this.context);
    child.setName(TEST_CHILD_NODE_NAME);
    child.setRequiredPrimaryTypeNames(new String[] {"nt:base"});
    child.setAutoCreated(true);
    ntTemplate.getNodeDefinitionTemplates().add(child);

    List<NodeTypeDefinition> templates = Arrays.asList(new NodeTypeDefinition[] {ntTemplate});
    compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates));
  }
  @FixFor("MODE-826")
  @Test
  public void
      shouldAllowRegisteringNodeTypeWithPrimaryItemNameAndOnlyNonResidualChildNodeDefinition()
          throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);
    // Set the primary item name to be a name that DOES match the child node definition ...
    ntTemplate.setPrimaryItemName(TEST_CHILD_NODE_NAME);

    // Create the residual child node definition ...
    JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
    childNode.setDefaultPrimaryTypeName(TEST_TYPE_NAME2);
    childNode.setName(TEST_CHILD_NODE_NAME);
    ntTemplate.getNodeDefinitionTemplates().add(childNode);

    // And register it ...
    repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] {ntTemplate}));
  }
  @Test
  public void shouldAllowUnregisteringUnusedType() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);

    JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
    childNode.setDefaultPrimaryTypeName(JcrNtLexicon.FILE.getString(this.registry));
    ntTemplate.getNodeDefinitionTemplates().add(childNode);

    try {
      repoTypeManager.registerNodeType(ntTemplate);
    } catch (Exception ex) {
      fail(ex.getMessage());
    }

    Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
    int nodeTypeCount = nodeTypes().getAllNodeTypes().size();
    repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] {typeNameAsName}), true);
    assertThat(nodeTypes().getAllNodeTypes().size(), is(nodeTypeCount - 1));
    assertThat(nodeTypes().getNodeType(typeNameAsName), is(nullValue()));
  }
  @Test(expected = InvalidNodeTypeDefinitionException.class)
  public void shouldNotAllowUnregisteringDefaultPrimaryType() throws Exception {
    ntTemplate.setName(TEST_TYPE_NAME);

    JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
    childNode.setDefaultPrimaryTypeName(JcrNtLexicon.FILE.getString(this.registry));
    ntTemplate.getNodeDefinitionTemplates().add(childNode);

    try {
      repoTypeManager.registerNodeType(ntTemplate);
    } catch (Exception ex) {
      fail(ex.getMessage());
    }

    repoTypeManager.unregisterNodeType(
        Arrays.asList(
            new Name[] {
              JcrNtLexicon.FILE,
            }),
        true);
  }