From 04ff552c42f3200dd71a58f94e9d57436b67c4f3 Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Fri, 09 Nov 2012 15:26:03 +0000
Subject: [PATCH] - rename SchemaBuilderTest.java in SchemaBuilderTestCase.java. - SchemaBuilderTestCase.java: added new tests. - SchemaBuilder.java :  - fix a small bug about 'removeDITContentRule(final DITContentRule rule)'.  						- 'rewrap' comments. - checkstyle : ok.

---
 /dev/null                                                                                         |  349 --------
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java         |   99 -
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java | 1965 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2,000 insertions(+), 413 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 33e9ae8..50c2c78 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -95,8 +95,8 @@
     // Constructs a search request for retrieving the subschemaSubentry
     // attribute from the named entry.
     private static SearchRequest getReadSchemaForEntrySearchRequest(final DN dn) {
-        return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter
-                .objectClassPresent(), SUBSCHEMA_SUBENTRY_ATTRS);
+        return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter.objectClassPresent(),
+                SUBSCHEMA_SUBENTRY_ATTRS);
     }
 
     // Constructs a search request for retrieving the named subschema
@@ -324,8 +324,7 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("sup")) {
                     // This specifies the name or OID of the superior attribute
@@ -350,27 +349,22 @@
                 } else if (tokenName.equalsIgnoreCase("syntax")) {
                     // This specifies the numeric OID of the syntax for this
                     // matching rule. It may optionally be immediately followed
-                    // by
-                    // an open curly brace, an integer definition, and a close
+                    // by an open curly brace, an integer definition, and a close
                     // curly brace to suggest the minimum number of characters
                     // that should be allowed in values of that type. This
                     // implementation will ignore any such length because it
-                    // does
-                    // not impose any practical limit on the length of attribute
+                    // does not impose any practical limit on the length of attribute
                     // values.
                     syntax = SchemaUtils.readOIDLen(reader, allowMalformedNamesAndOptions);
                 } else if (tokenName.equalsIgnoreCase("single-definition")) {
                     // This indicates that attributes of this type are allowed
-                    // to
-                    // have at most one definition. We do not need any more
+                    // to have at most one definition. We do not need any more
                     // parsing for this token.
                     isSingleValue = true;
                 } else if (tokenName.equalsIgnoreCase("single-value")) {
                     // This indicates that attributes of this type are allowed
-                    // to
-                    // have at most one value. We do not need any more parsing
-                    // for
-                    // this token.
+                    // to have at most one value. We do not need any more parsing
+                    // for this token.
                     isSingleValue = true;
                 } else if (tokenName.equalsIgnoreCase("collective")) {
                     // This indicates that attributes of this type are
@@ -385,8 +379,7 @@
                     isNoUserModification = true;
                 } else if (tokenName.equalsIgnoreCase("usage")) {
                     // This specifies the usage string for this attribute type.
-                    // It
-                    // should be followed by one of the strings
+                    // It should be followed by one of the strings
                     // "userApplications", "directoryOperation",
                     // "distributedOperation", or "dSAOperation".
                     int length = 0;
@@ -417,8 +410,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -627,8 +619,7 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("aux")) {
                     auxiliaryClasses = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
@@ -644,8 +635,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -856,8 +846,7 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("form")) {
                     nameForm = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
@@ -866,8 +855,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -1021,23 +1009,20 @@
                     names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
                 } else if (tokenName.equalsIgnoreCase("desc")) {
                     // This specifies the description for the matching rule. It
-                    // is
-                    // an arbitrary string of characters enclosed in single
+                    // is an arbitrary string of characters enclosed in single
                     // quotes.
                     description = SchemaUtils.readQuotedString(reader);
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the matching rule should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("syntax")) {
                     syntax = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -1199,16 +1184,14 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("applies")) {
                     attributes = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -1368,8 +1351,7 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("oc")) {
                     structuralClass = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
@@ -1382,8 +1364,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -1560,8 +1541,7 @@
                 } else if (tokenName.equalsIgnoreCase("obsolete")) {
                     // This indicates whether the attribute type should be
                     // considered obsolete. We do not need to do any more
-                    // parsing
-                    // for this token.
+                    // parsing for this token.
                     isObsolete = true;
                 } else if (tokenName.equalsIgnoreCase("sup")) {
                     superiorClasses = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
@@ -1573,13 +1553,11 @@
                     objectClassType = ObjectClassType.ABSTRACT;
                 } else if (tokenName.equalsIgnoreCase("structural")) {
                     // This indicates that this is a structural objectclass. We
-                    // do
-                    // not need any more parsing for this token.
+                    // do not need any more parsing for this token.
                     objectClassType = ObjectClassType.STRUCTURAL;
                 } else if (tokenName.equalsIgnoreCase("auxiliary")) {
                     // This indicates that this is an auxiliary objectclass. We
-                    // do
-                    // not need any more parsing for this token.
+                    // do not need any more parsing for this token.
                     objectClassType = ObjectClassType.AUXILIARY;
                 } else if (tokenName.equalsIgnoreCase("must")) {
                     requiredAttributes =
@@ -1590,8 +1568,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -2142,8 +2119,7 @@
                 } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
                     // This must be a non-standard property and it must be
                     // followed by either a single definition in single quotes
-                    // or
-                    // an open parenthesis followed by one or more values in
+                    // or an open parenthesis followed by one or more values in
                     // single quotes separated by spaces followed by a close
                     // parenthesis.
                     if (extraProperties.isEmpty()) {
@@ -2249,19 +2225,17 @@
     }
 
     /**
-     * Specifies whether or not the JPEG Photo syntax should allow values
-     * which do not conform to the JFIF or Exif specifications.
+     * Specifies whether or not the JPEG Photo syntax should allow values which
+     * do not conform to the JFIF or Exif specifications.
      * <p>
      * By default this compatibility option is set to {@code true}.
      *
      * @param allowMalformedJPEGPhotos
-     *            {@code true} if the JPEG Photo syntax should allow
-     *            values which do not conform to the JFIF or Exif
-     *            specifications.
+     *            {@code true} if the JPEG Photo syntax should allow values
+     *            which do not conform to the JFIF or Exif specifications.
      * @return A reference to this {@code SchemaBuilder}.
      */
-    public SchemaBuilder allowMalformedJPEGPhotos(
-            final boolean allowMalformedJPEGPhotos) {
+    public SchemaBuilder allowMalformedJPEGPhotos(final boolean allowMalformedJPEGPhotos) {
         lazyInitBuilder();
 
         this.allowMalformedJPEGPhotos = allowMalformedJPEGPhotos;
@@ -2510,15 +2484,13 @@
     public Schema toSchema() {
         // If this schema builder was initialized from another schema and no
         // modifications have been made since then we can simply return the
-        // original
-        // schema.
+        // original schema.
         if (copyOnWriteSchema != null) {
             return copyOnWriteSchema;
         }
 
         // We still need to ensure that this builder has been initialized
-        // (otherwise
-        // some fields may still be null).
+        // (otherwise some fields may still be null).
         lazyInitBuilder();
 
         final String localSchemaName;
@@ -2899,7 +2871,7 @@
             final List<DITContentRule> rules = name2ContentRules.get(lowerName);
             if (rules != null && rules.contains(rule)) {
                 if (rules.size() <= 1) {
-                    name2AttributeTypes.remove(lowerName);
+                    name2ContentRules.remove(lowerName);
                 } else {
                     rules.remove(rule);
                 }
@@ -3012,8 +2984,7 @@
         }
 
         // Attribute types need special processing because they have
-        // hierarchical
-        // dependencies.
+        // hierarchical dependencies.
         final List<AttributeType> invalidAttributeTypes = new LinkedList<AttributeType>();
         for (final AttributeType attributeType : numericOID2AttributeTypes.values()) {
             attributeType.validate(schema, invalidAttributeTypes, warnings);
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
deleted file mode 100644
index 1174f0d..0000000
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Copyright 2011 ForgeRock AS.
- */
-package org.forgerock.opendj.ldap.schema;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-
-import org.forgerock.i18n.LocalizedIllegalArgumentException;
-import org.testng.annotations.Test;
-
-/**
- * Test SchemaBuilder.
- */
-public class SchemaBuilderTest extends SchemaTestCase {
-
-    /**
-     * Tests that schema validation resolves dependencies between parent/child
-     * attribute types regardless of the order in which they were added.
-     */
-    @Test
-    public void testAttributeTypeDependenciesChildThenParent() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema())
-                        .addAttributeType("( childtype-oid NAME 'childtype' SUP parenttype )",
-                                false)
-                        .addAttributeType(
-                                "( parenttype-oid NAME 'parenttype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
-                                false).toSchema();
-        assertThat(schema.getAttributeType("childtype").getSyntax()).isNotNull();
-        assertThat(schema.getAttributeType("childtype").getSyntax().getOID()).isEqualTo(
-                "1.3.6.1.4.1.1466.115.121.1.15");
-    }
-
-    /**
-     * Tests that schema validation resolves dependencies between parent/child
-     * attribute types regardless of the order in which they were added.
-     */
-    @Test
-    public void testAttributeTypeDependenciesParentThenChild() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema())
-                        .addAttributeType(
-                                "( parenttype-oid NAME 'parenttype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
-                                false).addAttributeType(
-                                "( childtype-oid NAME 'childtype' SUP parenttype )", false)
-                        .toSchema();
-        assertThat(schema.getAttributeType("childtype").getSyntax()).isNotNull();
-        assertThat(schema.getAttributeType("childtype").getSyntax().getOID()).isEqualTo(
-                "1.3.6.1.4.1.1466.115.121.1.15");
-    }
-
-    /**
-     * Tests that attribute types must have a syntax or a superior.
-     */
-    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
-    public void testAttributeTypeNoSuperiorNoSyntax() {
-        new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
-                "( parenttype-oid NAME 'parenttype' )", false);
-    }
-
-    /**
-     * Tests that schema validation handles validation failures for superior
-     * attribute types regardless of the order.
-     */
-    @Test
-    public void testAttributeTypeSuperiorFailureChildThenParent() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
-                        "( childtype-oid NAME 'childtype' SUP parenttype )", false)
-                        .addAttributeType("( parenttype-oid NAME 'parenttype' SUP xxx )", false)
-                        .toSchema();
-
-        try {
-            schema.getAttributeType("childtype");
-            fail("childtype should not be in the schema because its parent is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-
-        try {
-            schema.getAttributeType("parenttype");
-            fail("parenttype should not be in the schema because it is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-    }
-
-    /**
-     * Tests that schema validation handles validation failures for superior
-     * attribute types regardless of the order.
-     */
-    @Test
-    public void testAttributeTypeSuperiorFailureParentThenChild() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
-                        "( parenttype-oid NAME 'parenttype' SUP xxx )", false).addAttributeType(
-                        "( childtype-oid NAME 'childtype' SUP parenttype )", false).toSchema();
-
-        try {
-            schema.getAttributeType("childtype");
-            fail("childtype should not be in the schema because its parent is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-
-        try {
-            schema.getAttributeType("parenttype");
-            fail("parenttype should not be in the schema because it is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-    }
-
-    /**
-     * Test for OPENDJ-156: Errors when parsing collective attribute
-     * definitions.
-     */
-    @Test
-    public void testCollectiveAttribute() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
-                        "( 2.5.4.11.1 NAME 'c-ou' "
-                                + "SUP ou SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
-                                + "COLLECTIVE X-ORIGIN 'RFC 3671' )", false).toSchema();
-        assertThat(schema.getWarnings()).isEmpty();
-    }
-
-    /**
-     * Tests that it is possible to create a schema which is an exact copy of
-     * another and take advantage of copy on write.
-     */
-    @Test
-    public void testCopyOnWriteNoChanges() {
-        final Schema baseSchema = Schema.getCoreSchema();
-        final Schema schema = new SchemaBuilder(baseSchema).toSchema();
-
-        assertThat(schema).isSameAs(baseSchema);
-    }
-
-    /**
-     * Tests that it is possible to create a schema which is based on another.
-     */
-    @Test
-    public void testCopyOnWriteWithChanges() {
-        final Schema baseSchema = Schema.getCoreSchema();
-        final Schema schema =
-                new SchemaBuilder(baseSchema).addAttributeType(
-                        "( testtype-oid NAME 'testtype' SUP name )", false).toSchema();
-        assertThat(schema).isNotSameAs(baseSchema);
-        assertThat(schema.getObjectClasses().containsAll(baseSchema.getObjectClasses()));
-        assertThat(schema.getObjectClasses().size())
-                .isEqualTo(baseSchema.getObjectClasses().size());
-        assertThat(schema.getAttributeTypes().containsAll(baseSchema.getAttributeTypes()));
-        assertThat(schema.getAttributeType("testtype")).isNotNull();
-        assertThat(schema.getSchemaName()).isEqualTo(baseSchema.getSchemaName());
-        assertThat(schema.allowMalformedNamesAndOptions()).isEqualTo(
-                baseSchema.allowMalformedNamesAndOptions());
-    }
-
-    /**
-     * Tests that it is possible to create an empty schema.
-     */
-    @Test
-    public void testCreateEmptySchema() {
-        final Schema schema = new SchemaBuilder().toSchema();
-        assertThat(schema.getAttributeTypes()).isEmpty();
-        assertThat(schema.getObjectClasses()).isEmpty();
-        assertThat(schema.getSyntaxes()).isEmpty();
-        assertThat(schema.getWarnings()).isEmpty();
-        // Could go on...
-    }
-
-    /**
-     * Tests that multiple consecutive invocations of toSchema return the exact
-     * same schema.
-     */
-    @Test
-    public void testMultipleToSchema1() {
-        final Schema baseSchema = Schema.getCoreSchema();
-        final SchemaBuilder builder = new SchemaBuilder(baseSchema);
-        final Schema schema1 = builder.toSchema();
-        final Schema schema2 = builder.toSchema();
-        assertThat(schema1).isSameAs(baseSchema);
-        assertThat(schema1).isSameAs(schema2);
-    }
-
-    /**
-     * Tests that multiple consecutive invocations of toSchema return the exact
-     * same schema.
-     */
-    @Test
-    public void testMultipleToSchema2() {
-        final SchemaBuilder builder =
-                new SchemaBuilder().addAttributeType(
-                        "( testtype-oid NAME 'testtype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
-                        false);
-        final Schema schema1 = builder.toSchema();
-        final Schema schema2 = builder.toSchema();
-        assertThat(schema1).isSameAs(schema2);
-        assertThat(schema1.getAttributeType("testtype")).isNotNull();
-        assertThat(schema2.getAttributeType("testtype")).isNotNull();
-    }
-
-    /**
-     * Tests that schema validation resolves dependencies between parent/child
-     * object classes regardless of the order in which they were added.
-     */
-    @Test
-    public void testObjectClassDependenciesChildThenParent() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema()).addObjectClass(
-                        "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
-                        false).addObjectClass(
-                        "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST cn )", false)
-                        .toSchema();
-
-        final AttributeType cn = schema.getAttributeType("cn");
-        final AttributeType sn = schema.getAttributeType("sn");
-
-        assertThat(schema.getObjectClass("childtype").isRequired(cn)).isTrue();
-        assertThat(schema.getObjectClass("childtype").isRequired(sn)).isTrue();
-    }
-
-    /**
-     * Tests that schema validation resolves dependencies between parent/child
-     * object classes regardless of the order in which they were added.
-     */
-    @Test
-    public void testObjectClassDependenciesParentThenChild() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema())
-                        .addObjectClass(
-                                "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST cn )",
-                                false)
-                        .addObjectClass(
-                                "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
-                                false).toSchema();
-
-        final AttributeType cn = schema.getAttributeType("cn");
-        final AttributeType sn = schema.getAttributeType("sn");
-
-        assertThat(schema.getObjectClass("childtype").isRequired(cn)).isTrue();
-        assertThat(schema.getObjectClass("childtype").isRequired(sn)).isTrue();
-    }
-
-    /**
-     * Tests that schema validation handles validation failures for superior
-     * object classes regardless of the order.
-     */
-    @Test
-    public void testObjectClassSuperiorFailureChildThenParent() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema()).addObjectClass(
-                        "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
-                        false).addObjectClass(
-                        "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST xxx )", false)
-                        .toSchema();
-
-        try {
-            schema.getObjectClass("childtype");
-            fail("childtype should not be in the schema because its parent is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-
-        try {
-            schema.getObjectClass("parenttype");
-            fail("parenttype should not be in the schema because it is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-    }
-
-    /**
-     * Tests that schema validation handles validation failures for superior
-     * object classes regardless of the order.
-     */
-    @Test
-    public void testObjectClassSuperiorFailureParentThenChild() {
-        final Schema schema =
-                new SchemaBuilder(Schema.getCoreSchema())
-                        .addObjectClass(
-                                "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST xxx )",
-                                false)
-                        .addObjectClass(
-                                "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
-                                false).toSchema();
-
-        try {
-            schema.getObjectClass("childtype");
-            fail("childtype should not be in the schema because its parent is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-
-        try {
-            schema.getObjectClass("parenttype");
-            fail("parenttype should not be in the schema because it is invalid");
-        } catch (final UnknownSchemaElementException e) {
-            // Expected.
-        }
-    }
-
-    /**
-     * Tests that a schema builder can be re-used after toSchema has been
-     * called.
-     */
-    @Test
-    public void testReuseSchemaBuilder() {
-        final SchemaBuilder builder = new SchemaBuilder();
-        final Schema schema1 =
-                builder.addAttributeType(
-                        "( testtype1-oid NAME 'testtype1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
-                        false).toSchema();
-
-        final Schema schema2 =
-                builder.addAttributeType(
-                        "( testtype2-oid NAME 'testtype2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
-                        false).toSchema();
-        assertThat(schema1).isNotSameAs(schema2);
-        assertThat(schema1.getAttributeType("testtype1")).isNotNull();
-        assertThat(schema1.hasAttributeType("testtype2")).isFalse();
-        assertThat(schema2.getAttributeType("testtype1")).isNotNull();
-        assertThat(schema2.getAttributeType("testtype2")).isNotNull();
-    }
-}
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
new file mode 100644
index 0000000..0800f7d
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
@@ -0,0 +1,1965 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions copyright 2012 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap.schema;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.SCHEMA_PROPERTY_ORIGIN;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.EntryNotFoundException;
+import org.forgerock.opendj.ldap.LinkedHashMapEntry;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.testng.annotations.Test;
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.Responses;
+
+/**
+ * Test SchemaBuilder.
+ */
+@SuppressWarnings("javadoc")
+public class SchemaBuilderTestCase extends SchemaTestCase {
+
+    /**
+     * Tests that schema validation resolves dependencies between parent/child
+     * attribute types regardless of the order in which they were added.
+     */
+    @Test
+    public void testAttributeTypeDependenciesChildThenParent() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema())
+                        .addAttributeType("( childtype-oid NAME 'childtype' SUP parenttype )",
+                                false)
+                        .addAttributeType(
+                                "( parenttype-oid NAME 'parenttype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+                                false).toSchema();
+        assertThat(schema.getAttributeType("childtype").getSyntax()).isNotNull();
+        assertThat(schema.getAttributeType("childtype").getSyntax().getOID()).isEqualTo(
+                "1.3.6.1.4.1.1466.115.121.1.15");
+    }
+
+    /**
+     * Tests that schema validation resolves dependencies between parent/child
+     * attribute types regardless of the order in which they were added.
+     */
+    @Test
+    public void testAttributeTypeDependenciesParentThenChild() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema())
+                        .addAttributeType(
+                                "( parenttype-oid NAME 'parenttype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
+                                false).addAttributeType(
+                                "( childtype-oid NAME 'childtype' SUP parenttype )", false)
+                        .toSchema();
+        assertThat(schema.getAttributeType("childtype").getSyntax()).isNotNull();
+        assertThat(schema.getAttributeType("childtype").getSyntax().getOID()).isEqualTo(
+                "1.3.6.1.4.1.1466.115.121.1.15");
+    }
+
+    /**
+     * Tests that attribute types must have a syntax or a superior.
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public void testAttributeTypeNoSuperiorNoSyntax() {
+        new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
+                "( parenttype-oid NAME 'parenttype' )", false);
+    }
+
+    /**
+     * Tests that schema validation handles validation failures for superior
+     * attribute types regardless of the order.
+     */
+    @Test
+    public void testAttributeTypeSuperiorFailureChildThenParent() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
+                        "( childtype-oid NAME 'childtype' SUP parenttype )", false)
+                        .addAttributeType("( parenttype-oid NAME 'parenttype' SUP xxx )", false)
+                        .toSchema();
+
+        try {
+            schema.getAttributeType("childtype");
+            fail("childtype should not be in the schema because its parent is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+
+        try {
+            schema.getAttributeType("parenttype");
+            fail("parenttype should not be in the schema because it is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+    }
+
+    /**
+     * Tests that schema validation handles validation failures for superior
+     * attribute types regardless of the order.
+     */
+    @Test
+    public void testAttributeTypeSuperiorFailureParentThenChild() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
+                        "( parenttype-oid NAME 'parenttype' SUP xxx )", false).addAttributeType(
+                        "( childtype-oid NAME 'childtype' SUP parenttype )", false).toSchema();
+
+        try {
+            schema.getAttributeType("childtype");
+            fail("childtype should not be in the schema because its parent is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+
+        try {
+            schema.getAttributeType("parenttype");
+            fail("parenttype should not be in the schema because it is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+    }
+
+    /**
+     * Test for OPENDJ-156: Errors when parsing collective attribute
+     * definitions.
+     */
+    @Test
+    public void testCollectiveAttribute() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema()).addAttributeType(
+                        "( 2.5.4.11.1 NAME 'c-ou' "
+                                + "SUP ou SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
+                                + "COLLECTIVE X-ORIGIN 'RFC 3671' )", false).toSchema();
+        assertThat(schema.getWarnings()).isEmpty();
+    }
+
+    /**
+     * Tests that it is possible to create a schema which is an exact copy of
+     * another and take advantage of copy on write.
+     */
+    @Test
+    public void testCopyOnWriteNoChanges() {
+        final Schema baseSchema = Schema.getCoreSchema();
+        final Schema schema = new SchemaBuilder(baseSchema).toSchema();
+
+        assertThat(schema).isSameAs(baseSchema);
+    }
+
+    /**
+     * Tests that it is possible to create a schema which is based on another.
+     */
+    @Test
+    public void testCopyOnWriteWithChanges() {
+        final Schema baseSchema = Schema.getCoreSchema();
+        final Schema schema =
+                new SchemaBuilder(baseSchema).addAttributeType(
+                        "( testtype-oid NAME 'testtype' SUP name )", false).toSchema();
+        assertThat(schema).isNotSameAs(baseSchema);
+        assertThat(schema.getObjectClasses().containsAll(baseSchema.getObjectClasses()));
+        assertThat(schema.getObjectClasses().size())
+                .isEqualTo(baseSchema.getObjectClasses().size());
+        assertThat(schema.getAttributeTypes().containsAll(baseSchema.getAttributeTypes()));
+        assertThat(schema.getAttributeType("testtype")).isNotNull();
+        assertThat(schema.getSchemaName()).isEqualTo(baseSchema.getSchemaName());
+        assertThat(schema.allowMalformedNamesAndOptions()).isEqualTo(
+                baseSchema.allowMalformedNamesAndOptions());
+    }
+
+    /**
+     * Tests that it is possible to create an empty schema.
+     */
+    @Test
+    public void testCreateEmptySchema() {
+        final Schema schema = new SchemaBuilder().toSchema();
+        assertThat(schema.getAttributeTypes()).isEmpty();
+        assertThat(schema.getObjectClasses()).isEmpty();
+        assertThat(schema.getSyntaxes()).isEmpty();
+        assertThat(schema.getWarnings()).isEmpty();
+        // Could go on...
+    }
+
+    /**
+     * Tests that multiple consecutive invocations of toSchema return the exact
+     * same schema.
+     */
+    @Test
+    public void testMultipleToSchema1() {
+        final Schema baseSchema = Schema.getCoreSchema();
+        final SchemaBuilder builder = new SchemaBuilder(baseSchema);
+        final Schema schema1 = builder.toSchema();
+        final Schema schema2 = builder.toSchema();
+        assertThat(schema1).isSameAs(baseSchema);
+        assertThat(schema1).isSameAs(schema2);
+    }
+
+    /**
+     * Tests that multiple consecutive invocations of toSchema return the exact
+     * same schema.
+     */
+    @Test
+    public void testMultipleToSchema2() {
+        final SchemaBuilder builder =
+                new SchemaBuilder().addAttributeType(
+                        "( testtype-oid NAME 'testtype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+                        false);
+        final Schema schema1 = builder.toSchema();
+        final Schema schema2 = builder.toSchema();
+        assertThat(schema1).isSameAs(schema2);
+        assertThat(schema1.getAttributeType("testtype")).isNotNull();
+        assertThat(schema2.getAttributeType("testtype")).isNotNull();
+    }
+
+    /**
+     * Tests that schema validation resolves dependencies between parent/child
+     * object classes regardless of the order in which they were added.
+     */
+    @Test
+    public void testObjectClassDependenciesChildThenParent() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema()).addObjectClass(
+                        "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
+                        false).addObjectClass(
+                        "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST cn )", false)
+                        .toSchema();
+
+        final AttributeType cn = schema.getAttributeType("cn");
+        final AttributeType sn = schema.getAttributeType("sn");
+
+        assertThat(schema.getObjectClass("childtype").isRequired(cn)).isTrue();
+        assertThat(schema.getObjectClass("childtype").isRequired(sn)).isTrue();
+    }
+
+    /**
+     * Tests that schema validation resolves dependencies between parent/child
+     * object classes regardless of the order in which they were added.
+     */
+    @Test
+    public void testObjectClassDependenciesParentThenChild() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema())
+                        .addObjectClass(
+                                "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST cn )",
+                                false)
+                        .addObjectClass(
+                                "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
+                                false).toSchema();
+
+        final AttributeType cn = schema.getAttributeType("cn");
+        final AttributeType sn = schema.getAttributeType("sn");
+
+        assertThat(schema.getObjectClass("childtype").isRequired(cn)).isTrue();
+        assertThat(schema.getObjectClass("childtype").isRequired(sn)).isTrue();
+    }
+
+    /**
+     * Tests that schema validation handles validation failures for superior
+     * object classes regardless of the order.
+     */
+    @Test
+    public void testObjectClassSuperiorFailureChildThenParent() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema()).addObjectClass(
+                        "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
+                        false).addObjectClass(
+                        "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST xxx )", false)
+                        .toSchema();
+
+        try {
+            schema.getObjectClass("childtype");
+            fail("childtype should not be in the schema because its parent is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+
+        try {
+            schema.getObjectClass("parenttype");
+            fail("parenttype should not be in the schema because it is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+    }
+
+    /**
+     * Tests that schema validation handles validation failures for superior
+     * object classes regardless of the order.
+     */
+    @Test
+    public void testObjectClassSuperiorFailureParentThenChild() {
+        final Schema schema =
+                new SchemaBuilder(Schema.getCoreSchema())
+                        .addObjectClass(
+                                "( parenttype-oid NAME 'parenttype' SUP top STRUCTURAL MUST xxx )",
+                                false)
+                        .addObjectClass(
+                                "( childtype-oid NAME 'childtype' SUP parenttype STRUCTURAL MUST sn )",
+                                false).toSchema();
+
+        try {
+            schema.getObjectClass("childtype");
+            fail("childtype should not be in the schema because its parent is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+
+        try {
+            schema.getObjectClass("parenttype");
+            fail("parenttype should not be in the schema because it is invalid");
+        } catch (final UnknownSchemaElementException e) {
+            // Expected.
+        }
+    }
+
+    /**
+     * Tests that a schema builder can be re-used after toSchema has been
+     * called.
+     */
+    @Test
+    public void testReuseSchemaBuilder() {
+        final SchemaBuilder builder = new SchemaBuilder();
+        final Schema schema1 =
+                builder.addAttributeType(
+                        "( testtype1-oid NAME 'testtype1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+                        false).toSchema();
+
+        final Schema schema2 =
+                builder.addAttributeType(
+                        "( testtype2-oid NAME 'testtype2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+                        false).toSchema();
+        assertThat(schema1).isNotSameAs(schema2);
+        assertThat(schema1.getAttributeType("testtype1")).isNotNull();
+        assertThat(schema1.hasAttributeType("testtype2")).isFalse();
+        assertThat(schema2.getAttributeType("testtype1")).isNotNull();
+        assertThat(schema2.getAttributeType("testtype2")).isNotNull();
+    }
+
+    /**
+     * The SchemaBuilder (Entry) doesn't allow a null parameter. Throws a
+     * NullPointerException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = NullPointerException.class)
+    public final void testSchemaBuilderDoesntAllowNullEntry() throws Exception {
+        final Entry e = null;
+        @SuppressWarnings("unused")
+        final SchemaBuilder builder = new SchemaBuilder(e);
+    }
+
+    /**
+     * Test to build a schema with an entry.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryWithCoreSchema() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "attributeTypes: ( temporary-fake-attr-id NAME 'myCustomAttribute' EQUALITY"
+                + " caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+            "objectClasses: ( temporary-fake-oc-id NAME 'myCustomObjClass'"
+                + " SUP top AUXILIARY MAY myCustomAttribute )",
+            "modifiersName: cn=Directory Manager,cn=Root DNs,cn=config",
+            "modifyTimestamp: 20110620095948Z"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder(e);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+        // Need to add the core schema for the standards attributes.
+        schema = Schema.getCoreSchema();
+
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNotNull();
+        assertThat(schema.getAttributeType("myCustomAttribute").getNameOrOID()).isEqualTo(
+                "myCustomAttribute");
+        assertThat(schema.getAttributeType("myCustomAttribute").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ORIGIN 'RFC 4512' )");
+        assertThat(schema.getAttributeType("myCustomAttribute").getUsage().toString()).isEqualTo(
+                "userApplications");
+
+        assertThat(schema.getObjectClassesWithName("myCustomObjClass")).isNotNull();
+    }
+
+    /**
+     * Building a schema with an ldif entry but without a core schema throws an
+     * UnknownSchemaElementException. We can read in the schema warning :
+     * [...]The object class "myCustomObjClass" specifies the superior object
+     * class "top" which is not defined in the schema (...).
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderWithEntryWithoutCoreSchema() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "attributeTypes: ( temporary-fake-attr-id NAME 'myCustomAttribute' EQUALITY"
+                + " caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+            "objectClasses: ( temporary-fake-oc-id NAME 'myCustomObjClass'"
+                + " SUP top AUXILIARY MAY myCustomAttribute )",
+            "modifiersName: cn=Directory Manager,cn=Root DNs,cn=config",
+            "modifyTimestamp: 20110620095948Z"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder(e);
+
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNotNull();
+
+        Schema schema = builder.toSchema();
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNotNull();
+    }
+
+    /**
+     * Adds a ldapsyntax to the schema. Ldapsyntaxes define allowable values can
+     * be used for an attribute.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddLdapSyntax() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "ldapSyntaxes:"
+                + " ( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Add a new ldapsyntax' )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+        // No warnings
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getSyntaxes()).isNotNull();
+        assertThat(schema.getSyntax("1.3.6.1.4.1.1466.115.121.1.15").getDescription()).isEqualTo(
+                "Add a new ldapsyntax");
+    }
+
+    /**
+     * Attempt to add a malformed ldap syntax. The schema is created but
+     * contains several warnings about the encountered errors.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMalformedLdapSyntax() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "ldapSyntaxes:" // malformed syntax
+                + " ( 1.3.6.1.4.1.1466.115.121.1.15 MALFORMEDTOKEN 'binary' )"
+
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema sc = builder.toSchema();
+        // The schema must contain a warning!
+        assertThat(sc.getWarnings()).isNotEmpty();
+        assertThat(sc.getWarnings().toString()).contains("illegal token \"MALFORMEDTOKEN\"");
+    }
+
+    /**
+     * Add a matching rule use provided by the entry to the schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMatchingRuleUse() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "matchingRuleUse: ( 2.5.13.16 NAME 'bitStringMatch' APPLIES ( givenName $ surname ) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getMatchingRuleUses()).isNotNull();
+        assertThat(schema.getMatchingRuleUse("bitStringMatch").toString()).isEqualTo(
+                "( 2.5.13.16 NAME 'bitStringMatch' APPLIES ( givenName $ surname ) )");
+        // The schema do not contain warnings.
+        assertThat(schema.getWarnings()).isEmpty();
+    }
+
+    /**
+     * Try to add a malformed Matching Rule Use provided by the entry. The
+     * Matching Rule Use is not applied to the schema but it contains the
+     * warnings about it.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMalformedMatchingRuleUse() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "matchingRuleUse: ( 2.5.13.16 NAM 'bitStringMatch' APPLIES ( givenName $ surname ) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getMatchingRuleUses()).isEmpty();
+        // The schema must contain warnings ( : illegal token "NAM")
+        assertThat(schema.getWarnings()).isNotEmpty();
+        assertThat(schema.getWarnings().toString()).contains("illegal token");
+    }
+
+    /**
+     * Adds a matching rule via the entry to the new schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMatchingRule() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "matchingRules: ( 2.5.13.16 NAME 'bitStringMatch'"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getMatchingRuleUses()).isNotNull();
+        assertThat(schema.getMatchingRule("bitStringMatch").toString()).isEqualTo(
+                "( 2.5.13.16 NAME 'bitStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )");
+        // The schema do not contain warnings.
+        assertThat(schema.getWarnings()).isEmpty();
+    }
+
+    /**
+     * Try to add a Matching Rule via the entry to the new schema but the
+     * matchingRule is 'malformed'. Warnings can be found in the .getWarnings()
+     * function.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMalformedMatchingRule() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "matchingRules: ( 2.5.13.16 NAME 'bitStringMatch'"
+                + " SYNTAXE 1.3.6.1.4.1.1466.115.121.1.6 )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getMatchingRuleUses()).isEmpty();
+        // The schema does contain warning (e.g : it contains an illegal token "SYNTAXE")
+        assertThat(schema.getWarnings()).isNotEmpty();
+        assertThat(schema.getWarnings().toString()).contains("illegal token");
+    }
+
+    /**
+     * Add a DITContentRule to the schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddDITContentRule() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "DITContentRules: ( 2.5.6.4 DESC 'content rule for organization' NOT "
+                        + "( x121Address $ telexNumber ) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getCoreSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getDITContentRules()).isNotNull();
+        assertThat(schema.getDITContentRule("2.5.6.4").toString())
+                .isEqualTo(
+                        "( 2.5.6.4 DESC 'content rule for organization' NOT ( x121Address $ telexNumber ) )");
+        // The schema do not contain warnings.
+        assertThat(schema.getWarnings()).isEmpty();
+    }
+
+    /**
+     * Try to add a malformed DITContentRule to the schema. Warnings are added
+     * to the schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMalformedDITContentRule() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "DITContentRules: ( 2.5.6.4 DESCS 'content rule for organization' NOT "
+                    + "( x121Address $ telexNumber ) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getDefaultSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getDITContentRules()).isEmpty();
+        // The schema does contain warnings(eg. it contains an illegal token "DESCS")
+        assertThat(schema.getWarnings()).isNotEmpty();
+        assertThat(schema.getWarnings().toString()).contains("illegal token");
+    }
+
+    /**
+     * Adding a new objectclass to the schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddObjectClass() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "objectClasses:  ( 1.3.6.1.4.1.36733.2.1.1.15.1 NAME 'myNewClass'"
+                + " SUP top MUST ( cn ) MAY (sn $ uid) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getDefaultSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getDITContentRules()).isEmpty();
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getObjectClass("myNewClass").getOID().toString()).isEqualTo(
+                "1.3.6.1.4.1.36733.2.1.1.15.1");
+    }
+
+    /**
+     * Attempt to add a new object class to the schema but forget to declare the
+     * linked attribute.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderWithEntryAddMalformedObjectClass() throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "objectClasses: ( 1.3.6.1.4.1.36733.2.1.1.15.1 NAME 'myNewClass'"
+                + " SUP top MUST ( unknownAttribute ) MAY (sn $ uid) )"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder();
+        builder.addSchema(Schema.getDefaultSchema(), false);
+        builder.addSchema(e, true);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getDITContentRules()).isEmpty();
+        // The schema does contain warnings :
+        assertThat(schema.getWarnings()).isNotEmpty();
+        assertThat(schema.getWarnings().toString()).contains(
+                "\"unknownAttribute\" which is not defined in the schema");
+    }
+
+    /**
+     * Adding a description in the attribute types.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAddAttributeWithEntryContainingDescriptionWithCoreSchema()
+            throws Exception {
+        // @formatter:off
+        final String[] strEntry = {
+            "dn: cn=schema",
+            "objectClass: top",
+            "objectClass: ldapSubentry",
+            "objectClass: subschema",
+            "cn: schema",
+            "attributeTypes: ( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY"
+                + " caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+            "objectClasses: ( temporary-fake-oc-id NAME 'myCustomObjClass'"
+                + " SUP top AUXILIARY MAY myCustomAttribute )",
+            "modifiersName: cn=Directory Manager,cn=Root DNs,cn=config",
+            "modifyTimestamp: 20110620095948Z"
+        };
+        // @formatter:on
+        final Entry e = new LinkedHashMapEntry(strEntry);
+        final SchemaBuilder builder = new SchemaBuilder(e);
+
+        assertThat(e.getAttribute(Schema.ATTR_LDAP_SYNTAXES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_ATTRIBUTE_TYPES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_OBJECT_CLASSES)).isNotNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULE_USE)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_MATCHING_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_CONTENT_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_DIT_STRUCTURE_RULES)).isNull();
+        assertThat(e.getAttribute(Schema.ATTR_NAME_FORMS)).isNull();
+
+        // Need to add the core schema for the standards attributes.
+        builder.addSchema(Schema.getCoreSchema(), false);
+        Schema schema = builder.toSchema();
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNotNull();
+        assertThat(schema.getAttributeType("myCustomAttribute").getNameOrOID()).isEqualTo(
+                "myCustomAttribute");
+        assertThat(schema.getAttributeType("myCustomAttribute").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ORIGIN 'RFC 4512' )");
+        assertThat(schema.getAttributeType("myCustomAttribute").getUsage().toString()).isEqualTo(
+                "userApplications");
+        assertThat(schema.getAttributeType("myCustomAttribute").getDescription().toString())
+                .isEqualTo("A short description");
+
+        assertThat(schema.getObjectClassesWithName("myCustomObjClass")).isNotNull();
+    }
+
+    /**
+     * Similar to the previous code, adding a description in the attribute
+     * types. The description is properly inserted in the schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAddAttributeContainingDescriptionWithCoreSchema()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Adding the new schema containing the customclass
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+        // Adding default core schema
+        scBuild.addSchema(Schema.getCoreSchema(), false);
+        Schema schema = scBuild.toSchema();
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNotNull();
+        assertThat(schema.getAttributeType("myCustomAttribute").getNameOrOID()).isEqualTo(
+                "myCustomAttribute");
+        assertThat(schema.getAttributeType("myCustomAttribute").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ORIGIN 'RFC 4512' )");
+        assertThat(schema.getAttributeType("myCustomAttribute").getUsage().toString()).isEqualTo(
+                "userApplications");
+        assertThat(schema.getAttributeType("myCustomAttribute").getDescription().toString())
+                .isEqualTo("A short description");
+
+        assertThat(schema.getObjectClassesWithName("myCustomObjClass")).isNotNull();
+    }
+
+    /**
+     * Adding an attribute to the schema using a wrong 'USAGE' is impossible.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddAttributeDoesntAllowWrongUsage() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Adding the new schema containing the customclass
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE wrongUsage )", false);
+    }
+
+    /**
+     * The schema builder doesn't allow a null attribute type.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = NullPointerException.class)
+    public final void testSchemaBuilderAddAttributeTypeDoesntAllowNull() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Adding the new schema containing the customclass
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(null, false);
+    }
+
+    /**
+     * The schema builder doesn't allow an empty attribute type.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddAttributeTypeDoesntAllowEmptyString() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Adding the new schema containing the customclass
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(" ", false);
+
+    }
+
+    /**
+     * Schema Builder doesn't allow to add attribute when left parenthesis is
+     * missing.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddAttributeDoesntAllowLeftParenthesisMising()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                " temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+    }
+
+    /**
+     * Schema Builder doesn't allow to add attribute when right parenthesis is
+     * missing.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddAttributeDoesntAllowRightParenthesisMising()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                " ( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications ",
+                false);
+    }
+
+    /**
+     * Add an attribute using the string definition and the constructor.
+     * Verifying the equality between the two.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderCompareAddAttributeTypesSucceed() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+
+        Schema sc = scBuild.toSchema();
+        assertThat(sc.getAttributeType("myCustomAttribute").getDescription()).isEqualTo(
+                "A short description");
+        assertThat(sc.getAttributeType("myCustomAttribute").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ORIGIN 'RFC 4512' )");
+
+        // Description changes in this builder :
+        final SchemaBuilder scBuild2 = new SchemaBuilder(Schema.getDefaultSchema());
+        scBuild2.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild2.addAttributeType("temporary-fake-attr-id", Collections
+                .singletonList("myCustomAttribute"), "The new attribute type", false, null,
+                "caseIgnoreOrderingMatch", "caseIgnoreOrderingMatch", "caseIgnoreSubstringsMatch",
+                null, "1.3.6.1.4.1.1466.115.121.1.15", false, false, true,
+                AttributeUsage.USER_APPLICATIONS, null, false);
+        Schema sc2 = scBuild2.toSchema();
+
+        assertThat(sc2.getAttributeType("myCustomAttribute").getDescription()).isEqualTo(
+                "The new attribute type");
+        assertThat(sc2.getAttributeType("myCustomAttribute").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' X-ORIGIN 'RFC 4512' )");
+
+        assertThat(sc2.getAttributeType("myCustomAttribute")).isEqualTo(
+                sc.getAttributeType("myCustomAttribute"));
+    }
+
+    /**
+     * The objectClass defined in the schema builder need a left parenthesis.
+     * RFC4512. Must throw an exception.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddObjectClassDoesntAllowMalformedObjectClass()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Left parenthesis is missing underneath
+        scBuild.addObjectClass(" temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+    }
+
+    /**
+     * The schema builder rejects malformed object class definition. Must throw
+     * an exception.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
+    public final void testSchemaBuilderAddObjectClassDoesntAllowMalformedObjectClassIllegalToken()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        // Wrong object class definition (AUXI)
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXI MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+    }
+
+    /**
+     * Rewrite an existing object class.
+     */
+    @Test()
+    public final void testSchemaBuilderAddObjectClass() throws Exception {
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+        Set<String> attrs = new HashSet<String>();
+        attrs.add("seeAlso");
+        attrs.add("ou");
+        attrs.add("l");
+        attrs.add("description");
+
+        scBuild.addObjectClass("2.5.6.14", Collections.singletonList("device"),
+                "New description for the new existing Object Class", false, Collections
+                        .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs,
+                ObjectClassType.STRUCTURAL, Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN,
+                        Collections.singletonList("RFC 4519")), true);
+        Schema sc = scBuild.toSchema();
+
+        assertThat(sc.getWarnings()).isEmpty();
+        assertThat(sc.getObjectClass("device").getOID()).isEqualTo("2.5.6.14");
+        assertThat(sc.getObjectClass("device").getDescription()).isEqualTo(
+                "New description for the new existing Object Class");
+    }
+
+    /**
+     * The builder doesn't allow conflicting attributes marked as overwrite
+     * false. Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingAttributesOverwriteFalse()
+            throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+    }
+
+    /**
+     * The builder allows to have twin or more attributes if it can overwrite
+     * them. Only the last is kept. Attributes may have same OID and name.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingAttributesOverwriteTrue() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+
+        //@formatter:off
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                true);
+
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'Another description' "
+                + "EQUALITY objectIdentifierFirstComponentMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.37"
+                + " USAGE directoryOperation )",
+                true);
+        //@formatter:on
+
+        scBuild.addSchema(Schema.getCoreSchema(), false);
+        Schema schema = scBuild.toSchema();
+        assertThat(schema.getWarnings()).isEmpty();
+
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNotNull();
+        assertThat(schema.getAttributeType("myCustomAttribute").getOID()).isEqualTo(
+                "temporary-fake-attr-id");
+        assertThat(schema.getAttributeType("myCustomAttribute").getSyntax().toString())
+                .isEqualTo(
+                        "( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' X-ORIGIN 'RFC 4512' )");
+        assertThat(schema.getAttributeType("myCustomAttribute").getUsage().toString()).isEqualTo(
+                "directoryOperation");
+    }
+
+    /**
+     * The builder doesn't allow conflicting DIT Structure Rules marked as
+     * overwrite false. Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingDITOverwriteFalse() throws Exception {
+        //@formatter:off
+        new SchemaBuilder(Schema.getDefaultSchema())
+                .addObjectClass(
+                "( testditstructureruleconstraintssupoc-oid "
+                    + "NAME 'testDITStructureRuleConstraintsSupOC' SUP top "
+                    + "STRUCTURAL MUST ou X-ORIGIN 'SchemaBackendTestCase')", false)
+                .addObjectClass(
+                "( testditstructureruleconstraintssuboc-oid "
+                + "NAME 'testDITStructureRuleConstraintsSubOC' SUP top "
+                + "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')", false)
+                .addNameForm(
+                "( testditstructureruleconstraintsupsnf-oid "
+                + "NAME 'testDITStructureRuleConstraintsSupNF' "
+                + "OC testDITStructureRuleConstraintsSupOC MUST ou "
+                + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+                .addNameForm(
+                "( testditstructureruleconstraintsubsnf-oid "
+                + "NAME 'testDITStructureRuleConstraintsSubNF' "
+                + "OC testDITStructureRuleConstraintsSubOC MUST cn "
+                + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+                .addDITStructureRule(
+                "( 999014 " + "NAME 'testDITStructureRuleConstraintsSup' "
+                + "FORM testDITStructureRuleConstraintsSupNF "
+                + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+                .addDITStructureRule(
+                "( 999014 " + "NAME 'testDITStructureRuleConstraintsSup' "
+                + "DESC 'A short description' FORM testDITStructureRuleConstraintsSupNF "
+                + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+            .toSchema();
+        //@formatter:on
+    }
+
+    /**
+     * The builder allows conflicting DIT Structure Rules marked as overwrite
+     * true.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingDITStructureRuleOverwriteTrue()
+            throws Exception {
+        // @formatter:off
+        final Schema schema =
+            new SchemaBuilder(Schema.getDefaultSchema())
+                    .addObjectClass(
+                        "( testditstructureruleconstraintssupoc-oid "
+                        + "NAME 'testDITStructureRuleConstraintsSupOC' SUP top "
+                        + "STRUCTURAL MUST ou X-ORIGIN 'SchemaBackendTestCase')", false)
+                    .addObjectClass(
+                    "( testditstructureruleconstraintssuboc-oid "
+                    + "NAME 'testDITStructureRuleConstraintsSubOC' SUP top "
+                    + "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')", false)
+                    .addNameForm(
+                    "( testditstructureruleconstraintsupsnf-oid "
+                        + "NAME 'testDITStructureRuleConstraintsSupNF' "
+                        + "OC testDITStructureRuleConstraintsSupOC MUST ou "
+                        + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+                    .addNameForm(
+                    "( testditstructureruleconstraintsubsnf-oid "
+                        + "NAME 'testDITStructureRuleConstraintsSubNF' "
+                        + "OC testDITStructureRuleConstraintsSubOC MUST cn "
+                        + "X-ORIGIN 'SchemaBackendTestCase' )", false)
+                    .addDITStructureRule(
+                    "( 999014 " + "NAME 'testDITStructureRuleConstraintsSup' "
+                        + "FORM testDITStructureRuleConstraintsSupNF "
+                        + "X-ORIGIN 'SchemaBackendTestCase' )", true)
+                    .addDITStructureRule(
+                    "( 999014 " + "NAME 'testDITStructureRuleConstraintsSup' "
+                        + "DESC 'A short description' FORM testDITStructureRuleConstraintsSupNF "
+                        + "X-ORIGIN 'SchemaBackendTestCase' )", true)
+                    .toSchema();
+        // @formatter:on
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getDITStructureRulesWithName("testAllowATRequiredByDCR")).isNotNull();
+        assertThat(schema.getDITStructureRule(999014).getDescription()).isEqualTo(
+                "A short description");
+        assertThat(schema.getDITStructureRule(999014).getNameOrRuleID().toString()).isEqualTo(
+                "testDITStructureRuleConstraintsSup");
+    }
+
+    /**
+     * Add a content Rule with the builder.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAddDITContentRuleBuilder() throws Exception {
+        // @formatter:off
+        final Schema schema =
+            new SchemaBuilder(Schema.getCoreSchema())
+                .addObjectClass("( 2.16.840.1.113730.3.2.2 NAME 'myCustomObjClass"
+                    + "' SUP top)", false)
+                .addDITContentRule(
+                    "( 2.16.840.1.113730.3.2.2"
+                        + " NAME 'inetOPerson'"
+                        + " DESC 'inetOrgPerson is defined in RFC2798'"
+                        + ")", true)
+                .toSchema();
+        // @formatter:on
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getDITContentRule("inetOPerson")).isNotNull();
+        assertThat(schema.getDITContentRule("inetOPerson").getNameOrOID().toString()).isEqualTo(
+                "inetOPerson");
+        assertThat(schema.getDITContentRule("inetOPerson").getDescription()).isEqualTo(
+                "inetOrgPerson is defined in RFC2798");
+    }
+
+    /**
+     * The builder doesn't allow conflicting DIT Structure Rules marked as
+     * overwrite false. Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingDITContentRuleOverwriteFalse()
+            throws Exception {
+        // @formatter:off
+        new SchemaBuilder(Schema.getDefaultSchema())
+            .addObjectClass(
+                "( testdontallowattributeprohibitedbydcroc-oid"
+                    + " NAME 'testDontAllowAttributeProhibitedByDCROC' SUP top"
+                    + " STRUCTURAL MUST cn MAY description"
+                    + " X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
+            .addDITContentRule(
+                "( testdontallowattributeprohibitedbydcroc-oid"
+                    + " NAME 'testDontAllowAttributeProhibitedByDCR' NOT description"
+                    + " X-ORIGIN 'EntrySchemaCheckingTestCase2' )", false)
+            .addDITContentRule(
+                    "( testdontallowattributeprohibitedbydcroc-oid"
+                        + " NAME 'testDontAllowAttributeProhibitedByDCR'"
+                        + " DESC 'Ensure attributes prohibited' NOT description"
+                        + " X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
+        // @formatter:on
+    }
+
+    /**
+     * The builder allows conflicting DIT Content Rules marked as overwrite
+     * true. Schema checking for an entry covered by a DIT content rule to
+     * ensure that attributes prohibited by the DIT content rule are not allowed
+     * even if they are allowed by the associated object classes. (cf.
+     * EntrySchemaCheckingTestCase)
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingDITContentRuleOverwriteTrue()
+            throws Exception {
+        // @formatter:off
+        final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
+            .addObjectClass(
+                "( testdontallowattributeprohibitedbydcroc-oid"
+                    + " NAME 'testDontAllowAttributeProhibitedByDCROC' SUP top"
+                    + " STRUCTURAL MUST cn MAY description"
+                    + " X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
+            .addDITContentRule(
+                "( testdontallowattributeprohibitedbydcroc-oid"
+                    + " NAME 'testDontAllowAttributeProhibitedByDCR' NOT description"
+                    + " X-ORIGIN 'EntrySchemaCheckingTestCase2' )", true)
+            .addDITContentRule(
+                    "( testdontallowattributeprohibitedbydcroc-oid"
+                        + " NAME 'testDontAllowAttributeProhibitedByDCR'"
+                        + " DESC 'Ensure attributes prohibited' NOT description"
+                        + " X-ORIGIN 'EntrySchemaCheckingTestCase' )", true).toSchema();
+        // @formatter:on
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getDITContentRule("testDontAllowAttributeProhibitedByDCR")).isNotNull();
+        assertThat(
+                schema.getDITContentRule("testDontAllowAttributeProhibitedByDCR").getDescription())
+                .isEqualTo("Ensure attributes prohibited");
+        assertThat(
+                schema.getDITContentRule("testDontAllowAttributeProhibitedByDCR").getNameOrOID()
+                        .toString()).isEqualTo("testDontAllowAttributeProhibitedByDCR");
+    }
+
+    /**
+     * The builder doesn't allow conflicting Matching Rules marked as overwrite
+     * false. Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingMatchingRuleOverwriteFalse()
+            throws Exception {
+        // @formatter:off
+        new SchemaBuilder(Schema.getDefaultSchema())
+                .addMatchingRule(
+                "( 2.5.13.16 NAME 'bitStringMatche'"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )", false)
+                .addMatchingRule(// Matching rules from RFC 2252
+                        "( 2.5.13.16 NAME 'bitStringMatch'"
+                        + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", false)
+                .toSchema();
+        // @formatter:on
+    }
+
+    /**
+     * The builder allows conflicting Matching Rules marked as overwrite true.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingMatchingRuleOverwriteTrue()
+            throws Exception {
+        // @formatter:off
+        final Schema schema =
+            new SchemaBuilder(Schema.getDefaultSchema())
+                    .addMatchingRule(
+                    "( 2.5.13.16 NAME 'bitStringMatche'"
+                    + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )", true)
+                    .addMatchingRule(// Matching rules from RFC 2252
+                            "( 2.5.13.16 NAME 'bitStringMatch'"
+                            + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", true)
+                    .toSchema();
+        // @formatter:on
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getMatchingRule("bitStringMatch")).isNotNull();
+        assertThat(schema.getMatchingRule("bitStringMatch").getOID()).isEqualTo("2.5.13.16");
+        assertThat(schema.getMatchingRule("bitStringMatch").getSyntax().toString()).isEqualTo(
+                "( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' X-ORIGIN 'RFC 4512' )");
+    }
+
+    /**
+     * The builder doesn't allow conflicting Matching Rules marked as overwrite
+     * false. Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingMatchingRuleUseOverwriteFalse()
+            throws Exception {
+        // @formatter:off
+        new SchemaBuilder(Schema.getDefaultSchema())
+            .addMatchingRuleUse(
+                    "( 2.5.13.16 APPLIES ( givenName $ name ) )", false)
+            .addMatchingRuleUse(
+                        "( 2.5.13.16 APPLIES ( givenName $ surname ) )", false)
+            .toSchema();
+        // @formatter:on
+    }
+
+    /**
+     * The builder allows conflicting Matching Rules marked as overwrite true.
+     * Cf. RFC 4517 3.3.20.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingMatchingRuleUseOverwriteTrue()
+            throws Exception {
+        // @formatter:off
+        final Schema schema =
+            new SchemaBuilder(Schema.getDefaultSchema())
+                .addMatchingRuleUse(
+                    "( 2.5.13.16 NAME 'bitStringMatch' APPLIES ( givenName $ name ) )", true)
+                .addMatchingRuleUse(// from RFC 4517
+                    "( 2.5.13.16 NAME 'bitStringMatch' APPLIES ( givenName $ surname ) )", true)
+                .toSchema();
+        // @formatter:on
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getMatchingRuleUsesWithName("bitStringMatch")).isNotEmpty();
+        assertThat(schema.getMatchingRuleUses().size()).isEqualTo(1);
+
+        for (MatchingRuleUse o : schema.getMatchingRuleUses()) {
+            assertThat(o.getNameOrOID()).isEqualTo("bitStringMatch");
+            assertThat(o.getMatchingRuleOID()).isEqualTo("2.5.13.16");
+            assertThat(o.getMatchingRule().toString()).isEqualTo(
+                    "( 2.5.13.16 NAME 'bitStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.6"
+                            + " X-ORIGIN 'RFC 4512' )");
+        }
+        assertThat(schema.getWarnings()).isEmpty();
+
+    }
+
+    /**
+     * The builder doesn't allow conflicting NameForm marked as overwrite false.
+     * Must throw a ConflictingSchemaElementException.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = ConflictingSchemaElementException.class)
+    public final void testSchemaBuilderDoesntAllowConflictingNameFormOverwriteFalse()
+            throws Exception {
+        // @formatter:off
+        new SchemaBuilder(Schema.getDefaultSchema())
+            .addNameForm(
+                "( testviolatessinglevaluednameform-oid "
+                    + "NAME 'testViolatesSingleValuedNameForm' "
+                    + "OC testViolatesSingleValuedNameFormOC MUST cn "
+                    + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false)
+            .addNameForm(
+                "( testviolatessinglevaluednameform-oid "
+                    + "NAME 'testViolatesSingleValuedNameForm' "
+                    + "OC testViolatesSingleValuedNameFormOC MUST cn "
+                    + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false)
+            .toSchema();
+        // @formatter:on
+    }
+
+    /**
+     * The builder allows conflicting Name Form marked as overwrite true.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAllowsConflictingNameFormOverwriteTrue() throws Exception {
+        // @formatter:off
+        final Schema schema =
+            new SchemaBuilder(Schema.getDefaultSchema())
+                .addObjectClass(
+                    "( testviolatessinglevaluednameformoc-oid "
+                            + "NAME 'testViolatesSingleValuedNameFormOC' SUP top STRUCTURAL "
+                            + "MUST cn MAY description X-ORIGIN 'EntrySchemaCheckingTestCase')",
+                    false)
+                .addNameForm(
+                    "( testviolatessinglevaluednameform-oid "
+                        + "NAME 'testViolatesSingleValuedNameForm' "
+                        + "OC testViolatesSingleValuedNameFormOC MUST sn "
+                        + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", true)
+                .addNameForm(
+                    "( testviolatessinglevaluednameform-oid "
+                        + "NAME 'testViolatesSingleValuedNameForm' "
+                        + "OC testViolatesSingleValuedNameFormOC MUST cn "
+                        + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", true)
+                .toSchema();
+        // @formatter:on
+
+        assertThat(schema.getWarnings()).isEmpty();
+        assertThat(schema.getNameFormsWithName("testViolatesSingleValuedNameForm")).isNotNull();
+        for (NameForm o : schema.getNameForms()) {
+            assertThat(o.getNameOrOID()).isEqualTo("testViolatesSingleValuedNameForm");
+            assertThat(o.getOID()).isEqualTo("testviolatessinglevaluednameform-oid");
+            assertThat(o.getStructuralClass().getOID().toString()).isEqualTo(
+                    "testviolatessinglevaluednameformoc-oid");
+        }
+    }
+
+    /**
+     * Use the schema builder to remove an attribute.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveAttributeType() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+        scBuild.addObjectClass("( temporary-fake-oc-id NAME 'myCustomObjClass"
+                + "' SUP top AUXILIARY MAY myCustomAttribute )", false);
+        scBuild.addAttributeType(
+                "( temporary-fake-attr-id NAME 'myCustomAttribute' DESC 'A short description' EQUALITY case"
+                        + "IgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstrings"
+                        + "Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications )",
+                false);
+        boolean isRemoved = scBuild.removeAttributeType("myCustomAttribute");
+        assertThat(isRemoved).isTrue();
+        Schema schema = scBuild.toSchema();
+        // The following line throws an exception.:
+        assertThat(schema.getAttributeType("myCustomAttribute")).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent attribute type. Do
+     * Nothing.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantAttributeType() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeAttributeType("wrongName");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent syntax.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantSyntax() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeSyntax("1.3.6.1.4.1.14aa");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to remove a syntax.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveSyntax() throws Exception {
+
+        assertThat(Schema.getCoreSchema().getSyntax("1.3.6.1.4.1.1466.115.121.1.15")).isNotNull();
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema());
+
+        boolean isRemoved = scBuild.removeSyntax("1.3.6.1.4.1.1466.115.121.1.15");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+        assertThat(sc.getSyntax("1.3.6.1.4.1.1466.115.121.1.15")).isNull();
+    }
+
+    /**
+     * Use the schema builder to remove a DIT Content Rule.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveDitContentRule() throws Exception {
+
+        // @formatter:off
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        scBuild.addObjectClass("( 2.16.840.1.113730.3.2.2 NAME 'myCustomObjClass"
+                + "' SUP top)", false);
+        scBuild.addDITContentRule(
+                    "( 2.16.840.1.113730.3.2.2"
+                            + " NAME 'inetOPerson'"
+                            + " DESC 'inetOrgPerson is defined in RFC2798'"
+                            + ")", true);
+        // @formatter:on
+
+        boolean isRemoved = scBuild.removeDITContentRule("inetOPerson");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+        for (DITContentRule dit : sc.getDITContentRules()) {
+            assertThat(dit.getNameOrOID()).isNotEqualTo("inetOPerson");
+        }
+    }
+
+    /**
+     * Use the schema builder to removing a non existent DIT Content Rule.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantDitContentRule() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeDITContentRule("badDITContentRule");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a DIT Structure Rule.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveDitStructureRule() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        scBuild.addObjectClass(
+                "( testditstructureruleconstraintssupoc-oid "
+                        + "NAME 'testDITStructureRuleConstraintsSupOC' SUP top "
+                        + "STRUCTURAL MUST ou X-ORIGIN 'SchemaBackendTestCase')", false)
+                .addObjectClass(
+                        "( testditstructureruleconstraintssuboc-oid "
+                                + "NAME 'testDITStructureRuleConstraintsSubOC' SUP top "
+                                + "STRUCTURAL MUST cn X-ORIGIN 'SchemaBackendTestCase')", false)
+                .addNameForm(
+                        "( testditstructureruleconstraintsupsnf-oid "
+                                + "NAME 'testDITStructureRuleConstraintsSupNF' "
+                                + "OC testDITStructureRuleConstraintsSupOC MUST ou "
+                                + "X-ORIGIN 'SchemaBackendTestCase' )", false).addNameForm(
+                        "( testditstructureruleconstraintsubsnf-oid "
+                                + "NAME 'testDITStructureRuleConstraintsSubNF' "
+                                + "OC testDITStructureRuleConstraintsSubOC MUST cn "
+                                + "X-ORIGIN 'SchemaBackendTestCase' )", false).addDITStructureRule(
+                        "( 999014 " + "NAME 'testDITStructureRuleConstraintsSup' "
+                                + "FORM testDITStructureRuleConstraintsSupNF "
+                                + "X-ORIGIN 'SchemaBackendTestCase' )", true);
+
+        boolean isRemoved = scBuild.removeDITStructureRule(999014);
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+
+        assertThat(sc.getDITStructureRule(999014)).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent DIT Structure Rule.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantDitStructureRule() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeDITStructureRule(999014);
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a Matching Rule.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveMatchingRule() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        scBuild.addMatchingRule(
+                // Matching rules from RFC 2252
+                "( 2.5.13.16 NAME 'bitStringMatch'" + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
+                false);
+
+        boolean isRemoved = scBuild.removeMatchingRule("bitStringMatch");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+
+        assertThat(sc.getMatchingRule("bitStringMatch")).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent Matching Rule.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantMatchingRule() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeMatchingRule("bitStringMatchZ");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a Matching Rule Use.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveMatchingRuleUSe() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        scBuild.addMatchingRuleUse(
+                "( 2.5.13.16 NAME 'bitStringMatch' APPLIES ( givenName $ surname ) )", false);
+
+        boolean isRemoved = scBuild.removeMatchingRuleUse("bitStringMatch");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+
+        assertThat(sc.getMatchingRuleUse("bitStringMatch")).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent Matching Rule Use.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantMatchingRuleUse() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeMatchingRuleUse("bitStringMatchZ");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a Name Form.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveNameForm() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        scBuild.addNameForm("( testviolatessinglevaluednameform-oid "
+                + "NAME 'testViolatesSingleValuedNameForm' "
+                + "OC testViolatesSingleValuedNameFormOC MUST cn "
+                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false);
+
+        boolean isRemoved = scBuild.removeNameForm("testViolatesSingleValuedNameForm");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+        assertThat(sc.getNameForm("testViolatesSingleValuedNameForm")).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent Name Form.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantNameForm() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeNameForm("bitStringMatchZ");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * Use the schema builder to removing a Object class.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = UnknownSchemaElementException.class)
+    public final void testSchemaBuilderRemoveObjectClass() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder();
+        scBuild.addObjectClass("( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn )"
+                + " MAY ( userPassword $ telephoneNumber $ seeAlso $ description )"
+                + " X-ORIGIN 'RFC 4519' )", false);
+
+        boolean isRemoved = scBuild.removeObjectClass("person");
+        assertThat(isRemoved).isTrue();
+        Schema sc = scBuild.toSchema();
+        assertThat(sc.getObjectClass("person")).isNull();
+    }
+
+    /**
+     * Use the schema builder to removing a non existent Object class.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderRemoveInexistantObjectClass() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        boolean isRemoved = scBuild.removeObjectClass("bitStringMatchZ");
+        assertThat(isRemoved).isFalse();
+    }
+
+    /**
+     * AddSchemaForEntry doesn't allow null.
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = NullPointerException.class)
+    public final void testSchemaBuilderAddSchemaForEntryDoesntAllowNull() throws Exception {
+
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+        scBuild.addSchemaForEntry(null, null, false);
+    }
+
+    /**
+     * Try to addSchemaForEntry but the entry doesn't include the
+     * subschemaSubentry attribute. Exception expected : The entry
+     * uid=scarter,ou=People,dc=example,dc=com does not include a
+     * subschemaSubentry attribute !
+     *
+     * @throws Exception
+     */
+    @Test(expectedExceptions = EntryNotFoundException.class)
+    public final void testSchemaBuilderAddSchemaForEntryDoesntContainSubschemaMockConnection()
+            throws Exception {
+        Connection connection = mock(Connection.class);
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+
+        // @formatter:off
+        final String[] entry = {
+            "dn: uid=scarter,ou=People,dc=example,dc=com",
+            "objectClass: person",
+            "objectClass: inetorgperson",
+            "objectClass: organizationalperson",
+            "objectClass: top",
+            "postalAddress: Aaccf Amar$01251 Chestnut Street$Panama City, DE  50369",
+            "postalCode: 50369", "uid: user.0"
+        };
+
+        when(
+            connection.searchSingleEntry((SearchRequest) any()))
+                .thenReturn(Responses.newSearchResultEntry(entry));
+        // @formatter:on
+
+        scBuild.addSchemaForEntry(connection,
+                DN.valueOf("uid=scarter,ou=People,dc=example,dc=com"), false);
+
+    }
+
+    /**
+     * Retrieving an LDAP Server's schema.
+     *
+     * @throws Exception
+     */
+    @Test()
+    public final void testSchemaBuilderAddSchemaForEntryMockConnection() throws Exception {
+        Connection connection = mock(Connection.class);
+        final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+
+        // @formatter:off
+        final String[] entry = {
+            "# Search result entry: uid=bjensen,ou=People,dc=example,dc=com",
+            "dn: uid=bjensen,ou=People,dc=example,dc=com",
+            "subschemaSubentry: cn=schema",
+            "entryDN: uid=bjensen,ou=people,dc=example,dc=com",
+            "entryUUID: fc252fd9-b982-3ed6-b42a-c76d2546312c"
+            // N.B : also works with previous example but needs the subschemaSubentry line.
+        };
+
+        // Send a search entry result :
+        when(
+            connection.searchSingleEntry((SearchRequest) any()))
+                .thenReturn(Responses.newSearchResultEntry(entry));
+        // @formatter:on
+
+        scBuild.addSchemaForEntry(connection,
+                DN.valueOf("uid=bjensen,ou=People,dc=example,dc=com"), false);
+
+        Schema sc = scBuild.toSchema();
+        // We retrieve the schema :
+        assertThat(sc.getSyntaxes()).isNotNull();
+        assertThat(sc.getAttributeTypes()).isNotNull();
+        assertThat(sc.getAttributeTypes()).isNotEmpty();
+        assertThat(sc.getObjectClasses()).isNotNull();
+        assertThat(sc.getObjectClasses()).isNotEmpty();
+        assertThat(sc.getMatchingRuleUses()).isNotNull();
+        assertThat(sc.getMatchingRuleUses()).isEmpty();
+        assertThat(sc.getMatchingRules()).isNotNull();
+        assertThat(sc.getMatchingRules()).isNotEmpty();
+        assertThat(sc.getDITContentRules()).isNotNull();
+        assertThat(sc.getDITContentRules()).isEmpty();
+        assertThat(sc.getDITStuctureRules()).isNotNull();
+        assertThat(sc.getDITStuctureRules()).isEmpty();
+        assertThat(sc.getNameForms()).isNotNull();
+        assertThat(sc.getNameForms()).isEmpty();
+
+        connection.close();
+    }
+}

--
Gitblit v1.10.0