mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
25.01.2011 2acc9b3468534251048f561600f42d24d0e07bbf
Fix for OPENDJ-205: Add support for rejecting and skipping records to the LDIF readers

Fix and re-enabled unit tests.

3 files modified
1973 ■■■■ changed files
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java 63 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java 5 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/EntrySchemaCheckingTestCase.java 1905 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -3141,7 +3141,8 @@
        // content rule.
        if (checkDITContentRule)
        {
          if (objectClass.getObjectClassType() == ObjectClassType.AUXILIARY)
          if (objectClass.getObjectClassType() == ObjectClassType.AUXILIARY
              && !ditContentRule.getAuxiliaryClasses().contains(objectClass))
          {
            if (errorMessages != null)
            {
@@ -3161,11 +3162,11 @@
        // present.
        if (checkObjectClasses)
        {
          for (final AttributeType t : objectClass.getRequiredAttributes())
          for (final AttributeType t : objectClass.getDeclaredRequiredAttributes())
          {
            final Attribute a = Attributes.emptyAttribute(AttributeDescription
                .create(t));
            if (entry.containsAttribute(a, null))
            if (!entry.containsAttribute(a, null))
            {
              if (errorMessages != null)
              {
@@ -3191,7 +3192,7 @@
        {
          final Attribute a = Attributes.emptyAttribute(AttributeDescription
              .create(t));
          if (entry.containsAttribute(a, null))
          if (!entry.containsAttribute(a, null))
          {
            if (errorMessages != null)
            {
@@ -3284,37 +3285,37 @@
              }
            }
          }
        }
          // Check attributes contain an appropriate number of values.
          if (checkAttributeValues)
        // Check all attributes contain an appropriate number of values.
        if (checkAttributeValues)
        {
          final int sz = attribute.size();
          if (sz == 0)
          {
            final int sz = attribute.size();
            if (sz == 0)
            if (errorMessages != null)
            {
              if (errorMessages != null)
              {
                final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_EMPTY_ATTRIBUTE
                    .get(entry.getName().toString(), t.getNameOrOID());
                errorMessages.add(message);
              }
              if (policy.checkAttributeValues().isReject())
              {
                return false;
              }
              final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_EMPTY_ATTRIBUTE
              .get(entry.getName().toString(), t.getNameOrOID());
              errorMessages.add(message);
            }
            else if (sz > 1 && t.isSingleValue())
            if (policy.checkAttributeValues().isReject())
            {
              if (errorMessages != null)
              {
                final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_SINGLE_VALUED_ATTRIBUTE
                    .get(entry.getName().toString(), t.getNameOrOID());
                errorMessages.add(message);
              }
              if (policy.checkAttributeValues().isReject())
              {
                return false;
              }
              return false;
            }
          }
          else if (sz > 1 && t.isSingleValue())
          {
            if (errorMessages != null)
            {
              final LocalizableMessage message = ERR_ENTRY_SCHEMA_AT_SINGLE_VALUED_ATTRIBUTE
              .get(entry.getName().toString(), t.getNameOrOID());
              errorMessages.add(message);
            }
            if (policy.checkAttributeValues().isReject())
            {
              return false;
            }
          }
        }
@@ -3388,7 +3389,7 @@
      for (final AVA ava : rdn)
      {
        final AttributeType t = ava.getAttributeType();
        if (nameForm.isRequiredOrOptional(t))
        if (!nameForm.isRequiredOrOptional(t))
        {
          if (nameFormWarnings != null)
          {
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -2233,6 +2233,11 @@
      throws ConflictingSchemaElementException, NullPointerException
  {
    Validator.ensureNotNull(schema);
    // All of the schema elements must be duplicated because validation will
    // cause them to update all their internal references which, although
    // unlikely, may be different in the new schema.
    for (final Syntax syntax : schema.getSyntaxes())
    {
      addSyntax(syntax.duplicate(), overwrite);
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/EntrySchemaCheckingTestCase.java
@@ -32,7 +32,8 @@
import static org.forgerock.opendj.ldap.schema.SchemaValidationPolicy.defaultPolicy;
import static org.forgerock.opendj.ldap.schema.SchemaValidationPolicy.ignoreAll;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.DN;
@@ -52,401 +53,73 @@
@Test
public class EntrySchemaCheckingTestCase extends SchemaTestCase
{
  /**
   * Ensures that the provided entry fails schema checking validation with
   * strict compliance enabled, but will pass in a more relaxed configuration.
   * <p>
   * Uses the default schema.
   *
   * @param e
   *          The entry to be tested.
   */
  private void failOnlyForStrictEvaluation(Entry e)
  {
    failOnlyForStrictEvaluation(e, Schema.getDefaultSchema());
  }
  /**
   * Ensures that the provided entry fails schema checking validation with
   * strict compliance enabled, but will pass in a more relaxed configuration.
   *
   * @param e
   *          The entry to be tested.
   * @param schema
   *          The schema to use.
   */
  private void failOnlyForStrictEvaluation(Entry e, Schema schema)
  {
    assertThat(
        conformsToSchema(e, schema, defaultPolicy()
            .requireSingleStructuralObjectClass(Policy.IGNORE), null)).isTrue();
    assertThat(
        conformsToSchema(e, schema, defaultPolicy()
            .requireSingleStructuralObjectClass(Policy.WARN), null)).isTrue();
    assertThat(
        conformsToSchema(e, schema, defaultPolicy()
            .requireSingleStructuralObjectClass(Policy.REJECT), null))
        .isFalse();
  }
  /**
   * Tests schema checking for an entry with a valid single structural
   * objectclass.
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes allowed by the DIT content rule are allowed even if not
   * directly allowed by any of the entry's objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testValidSingleStructuralClass() throws Exception
  @Test
  public void testAllowAttributeAllowedByDCR() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: domain",
        "dc: example");
    // @formatter:on
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests schema checking for an entry (not covered by a DIT content rule) with
   * a valid single structural objectclass as well as an auxiliary objectclass.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testValidSingleStructuralClassAndAuxiliaryClass()
      throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: organization",
        "objectClass: dcObject",
        "dc: example",
        "o: Example Org");
    // @formatter:on
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests schema checking for an entry that does not contain a structural
   * objectclass.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testNoStructuralClass() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: dcObject",
        "dc: example");
    // @formatter:on
    failOnlyForStrictEvaluation(e);
  }
  /**
   * Tests schema checking for an entry that contains multiple structural
   * objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testMultipleStructuralClasses() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: uid=test.user,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "objectClass: account",
        "uid: test.user",
        "givenName: Test",
        "sn: User",
        "cn: Test User");
    // @formatter:on
    failOnlyForStrictEvaluation(e);
  }
  /**
   * Tests schema checking for an entry that contains an undefined objectclass
   * with no other structural class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testUndefinedStructuralObjectClass() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: xxxundefinedstructuralxxx",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isFalse();
  }
  /**
   * Tests schema checking for an entry that contains an undefined objectclass
   * as well as a valid structural class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testUndefinedAuxiliaryObjectClass() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: device",
        "objectClass: xxxundefinedauxiliaryxxx",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isFalse();
  }
  /**
   * Tests schema checking for an entry that is missing an attribute required by
   * its structural object class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testMissingAttributeRequiredByStructuralClass() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmissingatrequiredbystructuraloc-oid "
                + "NAME 'testMissingATRequiredByStructuralOC' SUP top STRUCTURAL "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testMissingATRequiredByStructuralOC",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isFalse();
  }
  private Entry newEntry(String... ldif)
  {
    return newEntry(Schema.getDefaultSchema(), ldif);
  }
  private Entry newEntry(Schema schema, String... ldif)
  {
    try
    {
      return new LDIFEntryReader(ldif).setSchema(schema).readEntry();
    }
    catch (Exception e)
    {
      throw new IllegalArgumentException(e);
    }
  }
  /**
   * Tests schema checking for an entry that is missing an attribute required by
   * an auxiliary object class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testMissingAttributeRequiredByAuxiliaryClass() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmissingatrequiredbyauxiliaryoc-oid "
                + "NAME 'testMissingATRequiredByAuxiliaryOC' SUP top AUXILIARY "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: device",
        "objectClass: testMissingATRequiredByAuxiliaryOC",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isFalse();
  }
  /**
   * Tests schema checking for an entry that includes an attribute type that is
   * not allowed by any of its object classes.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testDisallowedAttributeType() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testdisallowedattributetypeoc-oid "
                + "NAME 'testDisallowedAttributeTypeOC' SUP top STRUCTURAL "
            "( testallowatallowedbydcroc-oid "
                + "NAME 'testAllowATAllowedByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .toSchema();
        .addDITContentRule(
            "( testallowatallowedbydcroc-oid "
                + "NAME 'testAllowATAllowedByDCR' MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDisallowedAttributeTypeOC",
        "objectClass: testAllowATAllowedByDCROC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isFalse();
  }
  private boolean conformsToSchema(final Entry entry,
      final SchemaValidationPolicy policy,
      final Collection<LocalizableMessage> errorMessages)
  {
    return conformsToSchema(entry, Schema.getDefaultSchema(), policy,
        errorMessages);
  }
  private boolean conformsToSchema(final Entry entry, final Schema schema,
      final SchemaValidationPolicy policy,
      final Collection<LocalizableMessage> errorMessages)
  {
    return schema.validateEntry(entry, policy, errorMessages);
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * multivalued attribute.
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes required by the DIT content rule are allowed even if not
   * directly allowed by any of the entry's objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testMultipleValuesForMultiValuedAttribute() throws Exception
  @Test
  public void testAllowAttributeRequiredByDCR() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testallowatrequiredbydcroc-oid "
                + "NAME 'testAllowATRequiredByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testallowatrequiredbydcroc-oid "
                + "NAME 'testAllowATRequiredByDCR' MUST description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(
        "dn: o=test",
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: organization",
        "o: test",
        "o: foo");
        "objectClass: testAllowATRequiredByDCROC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * single-valued attribute.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testMultipleValuesForSingleValuedAttribute() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: domain",
        "dc: example",
        "dc: foo");
    // @formatter:on
    assertThat(
        conformsToSchema(e, ignoreAll().checkAttributeValues(Policy.REJECT),
            null)).isFalse();
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * single-valued operational attribute.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testMultipleValuesForSingleValuedOperationalAttribute()
      throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: domain",
        "dc: example",
        "creatorsName: cn=Directory Manager",
        "creatorsName: cn=Another Manager");
    // @formatter:on
    assertThat(
        conformsToSchema(e, ignoreAll().checkAttributeValues(Policy.REJECT),
            null)).isFalse();
    assertConformsToSchema(e, schema, defaultPolicy());
  }
@@ -458,10 +131,10 @@
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  @Test
  public void testAuxiliaryClassAllowedByDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testauxiliaryclassallowedbydcroc-oid "
                + "NAME 'testAuxiliaryClassAllowedByDCROC' SUP top STRUCTURAL "
@@ -478,7 +151,7 @@
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testAuxiliaryClassAllowedByDCROC",
@@ -486,7 +159,7 @@
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
    assertConformsToSchema(e, schema, defaultPolicy());
  }
@@ -499,10 +172,10 @@
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  @Test
  public void testAuxiliaryClassNotAllowedByDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testauxiliaryclassnotallowedbydcroc-oid "
                + "NAME 'testAuxiliaryClassNotAllowedByDCROC' SUP top STRUCTURAL "
@@ -518,7 +191,7 @@
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testAuxiliaryClassNotAllowedByDCROC",
@@ -526,552 +199,44 @@
        "cn: test");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.removeAttribute("objectClass", "testAuxiliaryClassNotAllowedByDCROCAux");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes required by the DIT content rule are allowed even if not
   * directly allowed by any of the entry's objectclasses.
   * Tests schema checking for an entry that includes an attribute type that is
   * not allowed by any of its object classes.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testAllowAttributeRequiredByDCR() throws Exception
  @Test
  public void testDisallowedAttributeType() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testallowatrequiredbydcroc-oid "
                + "NAME 'testAllowATRequiredByDCROC' SUP top STRUCTURAL "
            "( testdisallowedattributetypeoc-oid "
                + "NAME 'testDisallowedAttributeTypeOC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testallowatrequiredbydcroc-oid "
                + "NAME 'testAllowATRequiredByDCR' MUST description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
        .toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testAllowATRequiredByDCROC",
        "objectClass: testDisallowedAttributeTypeOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes required by the DIT content rule are required even if not
   * directly allowed by any of the entry's objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testRequireAttributeRequiredByDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testrequireatrequiredbydcroc-oid "
                + "NAME 'testRequireATRequiredByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testrequireatrequiredbydcroc-oid "
                + "NAME 'testRequireATRequiredByDCR' MUST description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testRequireATRequiredByDCROC",
        "cn: test");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
  }
  /**
   * Tests schema checking for an entry for which there is a DIT content rule
   * covering the structural objectclass but that DIT content rule is marked
   * OBSOLETE. In this case, any attribute types required by the DIT content
   * rule should not be required for the entry.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testDontRequireAttributeRequiredByObsoleteDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testdontrequireatrequiredbyobsoletedcroc-oid "
                + "NAME 'testDontRequireATRequiredByObsoleteDCROC' SUP top "
                + "STRUCTURAL MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')",
            false)
        .addDITContentRule(
            "( testdontrequireatrequiredbyobsoletedcroc-oid "
                + "NAME 'testDontRequireATRequiredByObsoleteDCR' OBSOLETE "
                + "MUST description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontRequireATRequiredByObsoleteDCROC",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes allowed by the DIT content rule are allowed even if not
   * directly allowed by any of the entry's objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testAllowAttributeAllowedByDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testallowatallowedbydcroc-oid "
                + "NAME 'testAllowATAllowedByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testallowatallowedbydcroc-oid "
                + "NAME 'testAllowATAllowedByDCR' MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testAllowATAllowedByDCROC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes allowed by the DIT content rule are allowed but not
   * required if they are not required by any of the associated object classes.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testDontRequireAttributeAllowedByDCR() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testdontrequireatallowedbydcroc-oid "
                + "NAME 'testDontRequireATAllowedByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testdontrequireatallowedbydcroc-oid "
                + "NAME 'testDontRequireATAllowedByDCR' MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontRequireATAllowedByDCROC",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests 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.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testDontAllowAttributeProhibitedByDCR() throws Exception
  {
    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 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontAllowAttributeProhibitedByDCROC",
        "cn: test",
        "description: foo");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component is compliant with that name form.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testSatisfiesSingleValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsatisfiessinglevaluednameformoc-oid "
                + "NAME 'testSatisfiesSingleValuedNameFormOC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsatisfiessinglevaluednameform-oid "
                + "NAME 'testSatisfiesSingleValuedNameForm' "
                + "OC testSatisfiesSingleValuedNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testSatisfiesSingleValuedNameFormOC",
        "cn: test");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests that an entry covered by a name form will be rejected if its
   * single-valued RDN component violates that name form.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testViolatesSingleValuedNameForm() throws Exception
  {
    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 cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testViolatesSingleValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
  }
  /**
   * Tests that an entry covered by a name form will be rejected if its
   * multivalued RDN component violates that name form which only allows a
   * single value.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testMVViolatesSingleValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmvviolatessinglevaluednameformoc-oid "
                + "NAME 'testMVViolatesSingleValuedNameFormOC' SUP top STRUCTURAL "
                + "MUST cn MAY description X-ORIGIN 'EntrySchemaCheckingTestCase')",
            false)
        .addNameForm(
            "( testmvviolatessinglevaluednameform-oid "
                + "NAME 'testMVViolatesSingleValuedNameForm' "
                + "OC testMVViolatesSingleValuedNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testMVViolatesSingleValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
  }
  /**
   * Tests that an entry covered by a name form will not be rejected if its
   * single-valued RDN component violates that name form but the name form is
   * declared OBSOLETE.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testViolatesSingleValuedObsoleteNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testviolatessinglevaluedobsoletenameformoc-oid "
                + "NAME 'testViolatesSingleValuedObsoleteNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testviolatessinglevaluedobsoletenameform-oid "
                + "NAME 'testViolatesSingleValuedObsoleteNameForm' OBSOLETE "
                + "OC testViolatesSingleValuedObsoleteNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testViolatesSingleValuedObsoleteNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * multivalued RDN component is compliant with that name form which requires
   * multiple values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testSatisfiesRequiredMultiValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsatisfiesrequiredmultivaluednameformoc-oid "
                + "NAME 'testSatisfiesRequiredMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsatisfiesrequiredmultivaluednameform-oid "
                + "NAME 'testSatisfiesRequiredMultiValuedNameForm' "
                + "OC testSatisfiesRequiredMultiValuedNameFormOC "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testSatisfiesRequiredMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component only contains one of the multiple required
   * attribute types.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testViolatesRequiredMultiValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testviolatesrequiredmultivaluednameformoc-oid "
                + "NAME 'testViolatesRequiredMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testviolatesrequiredmultivaluednameform-oid "
                + "NAME 'testViolatesRequiredMultiValuedNameForm' "
                + "OC testViolatesRequiredMultiValuedNameFormOC "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testViolatesRequiredMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component is compliant with that name form which requires
   * one value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testSVSatisfiesOptionalMultiValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsvsatisfiesoptionalmultivaluednameformoc-oid "
                + "NAME 'testSVSatisfiesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsvsatisfiesoptionalmultivaluednameform-oid "
                + "NAME 'testSVSatisfiesOptionalMultiValuedNameForm' "
                + "OC testSVSatisfiesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testSVSatisfiesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * multivalued RDN component is compliant with that name form which requires
   * one value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testMVSatisfiesOptionalMultiValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmvsatisfiesoptionalmultivaluednameformoc-oid "
                + "NAME 'testMVSatisfiesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testmvsatisfiesoptionalmultivaluednameform-oid "
                + "NAME 'testMVSatisfiesOptionalMultiValuedNameForm' "
                + "OC testMVSatisfiesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testMVSatisfiesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertThat(conformsToSchema(e, schema, defaultPolicy(), null)).isTrue();
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component violates that name form which requires one
   * value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  public void testSVViolatesOptionalMultiValuedNameForm() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsvviolatesoptionalmultivaluednameformoc-oid "
                + "NAME 'testSVViolatesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsvviolatesoptionalmultivaluednameform-oid "
                + "NAME 'testSVViolatesOptionalMultiValuedNameForm' "
                + "OC testSVViolatesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testSVViolatesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
    e.removeAttribute("description", "foo");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
@@ -1083,10 +248,10 @@
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(enabled = false)
  @Test
  public void testDITStructureRuleConstraints() throws Exception
  {
    Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testditstructureruleconstraintssupoc-oid "
                + "NAME 'testDITStructureRuleConstraintsSupOC' SUP top "
@@ -1122,10 +287,11 @@
        "cn: child");
    // @formatter:on
    failOnlyForStrictEvaluation(e, schema);
    assertDoesNotConformToSchema(e, schema, defaultPolicy()
        .checkDITStructureRules(Policy.REJECT, newResolver(null)));
    // @formatter:off
    Entry p = newEntry(schema,
    final Entry p = newEntry(schema,
        "dn: ou=parent,o=test",
        "changetype: add",
        "objectClass: top",
@@ -1133,12 +299,8 @@
        "ou: parent");
    // @formatter:on
    assertThat(
        conformsToSchema(
            e,
            schema,
            defaultPolicy().checkDITStructureRules(Policy.REJECT,
                newResolver(p)), null)).isFalse();
    assertConformsToSchema(e, schema,
        defaultPolicy().checkDITStructureRules(Policy.REJECT, newResolver(p)));
    // @formatter:off
    e = newEntry(schema,
@@ -1148,47 +310,129 @@
        "cn: not below valid parent");
    // @formatter:on
    assertThat(
        conformsToSchema(
            e,
            schema,
            defaultPolicy().checkDITStructureRules(Policy.REJECT,
                newResolver(null)), null)).isFalse();
    assertDoesNotConformToSchema(e, schema, defaultPolicy()
        .checkDITStructureRules(Policy.REJECT, newResolver(null)));
    // @formatter:off
    e = newEntry(schema,
        "dn: cn=invalid entry below parent covered by DSR,ou=parent,o=test",
        "objectClass: top", "objectClass: device",
        "cn: invalid entry below parent covered by DSR");
        "dn: o=invalid entry below parent covered by DSR,ou=parent,o=test",
        "objectClass: top",
        "objectClass: organization",
        "o: invalid entry below parent covered by DSR");
    // @formatter:on
    assertThat(
        conformsToSchema(
            e,
            schema,
            defaultPolicy().checkDITStructureRules(Policy.REJECT,
                newResolver(p)), null)).isFalse();
    assertDoesNotConformToSchema(e, schema, defaultPolicy()
        .checkDITStructureRules(Policy.REJECT, newResolver(p)));
  }
  private EntryResolver newResolver(final Entry e)
  /**
   * Tests 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.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testDontAllowAttributeProhibitedByDCR() throws Exception
  {
    return new EntryResolver()
    {
    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 'EntrySchemaCheckingTestCase' )", false).toSchema();
      public Entry getEntry(DN dn) throws ErrorResultException
      {
        if (e == null)
        {
          throw ErrorResultException.newErrorResult(ResultCode.NO_SUCH_OBJECT,
              "no such entry " + dn.toString());
        }
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontAllowAttributeProhibitedByDCROC",
        "cn: test",
        "description: foo");
    // @formatter:on
        assertThat((Object) dn).isEqualTo(e.getName());
        return e;
      }
    };
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.removeAttribute("description", "foo");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes allowed by the DIT content rule are allowed but not
   * required if they are not required by any of the associated object classes.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testDontRequireAttributeAllowedByDCR() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testdontrequireatallowedbydcroc-oid "
                + "NAME 'testDontRequireATAllowedByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testdontrequireatallowedbydcroc-oid "
                + "NAME 'testDontRequireATAllowedByDCR' MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontRequireATAllowedByDCROC",
        "cn: test");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry for which there is a DIT content rule
   * covering the structural objectclass but that DIT content rule is marked
   * OBSOLETE. In this case, any attribute types required by the DIT content
   * rule should not be required for the entry.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testDontRequireAttributeRequiredByObsoleteDCR() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testdontrequireatrequiredbyobsoletedcroc-oid "
                + "NAME 'testDontRequireATRequiredByObsoleteDCROC' SUP top "
                + "STRUCTURAL MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')",
            false)
        .addDITContentRule(
            "( testdontrequireatrequiredbyobsoletedcroc-oid "
                + "NAME 'testDontRequireATRequiredByObsoleteDCR' OBSOLETE "
                + "MUST description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testDontRequireATRequiredByObsoleteDCROC",
        "cn: test");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
@@ -1200,24 +444,799 @@
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  @Test
  public void testInvalidSuperiorAttribute() throws Exception
  {
    // @formatter:off
    Entry e = newEntry(
    final Entry e = newEntry(
        "dn: uid=test.user,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "objectClass: account",
        "uid: test.user",
        "givenName: Test",
        "sn: User",
        "cn: Test User",
        "name: foo");
    // @formatter:off
    assertThat(conformsToSchema(e, defaultPolicy(), null)).isFalse();
    assertDoesNotConformToSchema(e, defaultPolicy());
    e.removeAttribute("name", "foo");
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that is missing an attribute required by
   * an auxiliary object class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMissingAttributeRequiredByAuxiliaryClass() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmissingatrequiredbyauxiliaryoc-oid "
                + "NAME 'testMissingATRequiredByAuxiliaryOC' SUP top AUXILIARY "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: device",
        "objectClass: testMissingATRequiredByAuxiliaryOC",
        "cn: test");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.addAttribute("description", "xxx");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that is missing an attribute required by
   * its structural object class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMissingAttributeRequiredByStructuralClass() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmissingatrequiredbystructuraloc-oid "
                + "NAME 'testMissingATRequiredByStructuralOC' SUP top STRUCTURAL "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testMissingATRequiredByStructuralOC",
        "cn: test");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.addAttribute("description", "xxx");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that contains multiple structural
   * objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMultipleStructuralClasses() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: uid=test.user,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organization",
        "o: test",
        "sn: User",
        "cn: Test User");
    // @formatter:on
    assertDoesNotConformToSchema(e, defaultPolicy());
    e.removeAttribute("objectClass", "organization");
    e.removeAttribute("o", "test");
    assertConformsToSchema(e, ignoreAll().checkAttributeValues(Policy.REJECT));
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * multivalued attribute.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMultipleValuesForMultiValuedAttribute() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: o=test",
        "objectClass: top",
        "objectClass: organization",
        "o: test",
        "o: foo");
    // @formatter:on
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * single-valued attribute.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMultipleValuesForSingleValuedAttribute() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "dc: example",
        "dc: foo");
    // @formatter:on
    assertDoesNotConformToSchema(e,
        ignoreAll().checkAttributeValues(Policy.REJECT));
    e.removeAttribute("dc", "foo");
    assertConformsToSchema(e, ignoreAll().checkAttributeValues(Policy.REJECT));
  }
  /**
   * Tests schema checking for an entry that includes multiple values for a
   * single-valued operational attribute.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMultipleValuesForSingleValuedOperationalAttribute()
      throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: domain",
        "dc: example",
        "creatorsName: cn=Directory Manager",
        "creatorsName: cn=Another Manager");
    // @formatter:on
    assertDoesNotConformToSchema(e,
        ignoreAll().checkAttributeValues(Policy.REJECT));
    e.removeAttribute("creatorsName", "cn=Another Manager");
    assertConformsToSchema(e, ignoreAll().checkAttributeValues(Policy.REJECT));
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * multivalued RDN component is compliant with that name form which requires
   * one value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMVSatisfiesOptionalMultiValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmvsatisfiesoptionalmultivaluednameformoc-oid "
                + "NAME 'testMVSatisfiesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testmvsatisfiesoptionalmultivaluednameform-oid "
                + "NAME 'testMVSatisfiesOptionalMultiValuedNameForm' "
                + "OC testMVSatisfiesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testMVSatisfiesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be rejected if its
   * multivalued RDN component violates that name form which only allows a
   * single value.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testMVViolatesSingleValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testmvviolatessinglevaluednameformoc-oid "
                + "NAME 'testMVViolatesSingleValuedNameFormOC' SUP top STRUCTURAL "
                + "MUST cn MAY description X-ORIGIN 'EntrySchemaCheckingTestCase')",
            false)
        .addNameForm(
            "( testmvviolatessinglevaluednameform-oid "
                + "NAME 'testMVViolatesSingleValuedNameForm' "
                + "OC testMVViolatesSingleValuedNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testMVViolatesSingleValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.setName("cn=test,o=test");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that does not contain a structural
   * objectclass.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testNoStructuralClass() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( domain-oid " + "NAME 'domain' SUP top STRUCTURAL "
                + "MUST dc X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: dcObject",
        "dc: example");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.addAttribute("objectClass", "domain");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry covered by a DIT content rule to ensure
   * that attributes required by the DIT content rule are required even if not
   * directly allowed by any of the entry's objectclasses.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testRequireAttributeRequiredByDCR() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testrequireatrequiredbydcroc-oid "
                + "NAME 'testRequireATRequiredByDCROC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addDITContentRule(
            "( testrequireatrequiredbydcroc-oid "
                + "NAME 'testRequireATRequiredByDCR' MUST description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testRequireATRequiredByDCROC",
        "cn: test");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.addAttribute("description", "foo");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * multivalued RDN component is compliant with that name form which requires
   * multiple values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testSatisfiesRequiredMultiValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsatisfiesrequiredmultivaluednameformoc-oid "
                + "NAME 'testSatisfiesRequiredMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsatisfiesrequiredmultivaluednameform-oid "
                + "NAME 'testSatisfiesRequiredMultiValuedNameForm' "
                + "OC testSatisfiesRequiredMultiValuedNameFormOC "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test+description=foo,o=test",
        "objectClass: top",
        "objectClass: testSatisfiesRequiredMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component is compliant with that name form.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testSatisfiesSingleValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsatisfiessinglevaluednameformoc-oid "
                + "NAME 'testSatisfiesSingleValuedNameFormOC' SUP top STRUCTURAL "
                + "MUST cn X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsatisfiessinglevaluednameform-oid "
                + "NAME 'testSatisfiesSingleValuedNameForm' "
                + "OC testSatisfiesSingleValuedNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testSatisfiesSingleValuedNameFormOC",
        "cn: test");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component is compliant with that name form which requires
   * one value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testSVSatisfiesOptionalMultiValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsvsatisfiesoptionalmultivaluednameformoc-oid "
                + "NAME 'testSVSatisfiesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsvsatisfiesoptionalmultivaluednameform-oid "
                + "NAME 'testSVSatisfiesOptionalMultiValuedNameForm' "
                + "OC testSVSatisfiesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testSVSatisfiesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component violates that name form which requires one
   * value but allows other values.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testSVViolatesOptionalMultiValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testsvviolatesoptionalmultivaluednameformoc-oid "
                + "NAME 'testSVViolatesOptionalMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testsvviolatesoptionalmultivaluednameform-oid "
                + "NAME 'testSVViolatesOptionalMultiValuedNameForm' "
                + "OC testSVViolatesOptionalMultiValuedNameFormOC MUST cn "
                + "MAY description X-ORIGIN 'EntrySchemaCheckingTestCase' )",
            false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testSVViolatesOptionalMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.setName("cn=test+description=foo,o=test");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that contains an undefined objectclass
   * as well as a valid structural class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testUndefinedAuxiliaryObjectClass() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: xxxundefinedauxiliaryxxx",
        "cn: test",
        "sn: test");
    // @formatter:on
    assertDoesNotConformToSchema(e, defaultPolicy());
    e.removeAttribute("objectClass", "xxxundefinedauxiliaryxxx");
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry that contains an undefined objectclass
   * with no other structural class.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testUndefinedStructuralObjectClass() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: xxxundefinedstructuralxxx",
        "o: test");
    // @formatter:on
    assertDoesNotConformToSchema(e, defaultPolicy());
    e.removeAttribute("objectClass", "xxxundefinedstructuralxxx");
    e.addAttribute("objectClass", "organization");
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry with a valid single structural
   * objectclass.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testValidSingleStructuralClass() throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: organization",
        "o: example");
    // @formatter:on
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests schema checking for an entry (not covered by a DIT content rule) with
   * a valid single structural objectclass as well as an auxiliary objectclass.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testValidSingleStructuralClassAndAuxiliaryClass()
      throws Exception
  {
    // @formatter:off
    final Entry e = newEntry(
        "dn: dc=example,dc=com",
        "objectClass: top",
        "objectClass: organization",
        "objectClass: dcObject",
        "dc: example",
        "o: Example Org");
    // @formatter:on
    assertConformsToSchema(e, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be accepted if its
   * single-valued RDN component only contains one of the multiple required
   * attribute types.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testViolatesRequiredMultiValuedNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testviolatesrequiredmultivaluednameformoc-oid "
                + "NAME 'testViolatesRequiredMultiValuedNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testviolatesrequiredmultivaluednameform-oid "
                + "NAME 'testViolatesRequiredMultiValuedNameForm' "
                + "OC testViolatesRequiredMultiValuedNameFormOC "
                + "MUST ( cn $ description ) "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: cn=test,o=test",
        "objectClass: top",
        "objectClass: testViolatesRequiredMultiValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.setName("cn=test+description=foo,o=test");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will be rejected if its
   * single-valued RDN component violates that name form.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testViolatesSingleValuedNameForm() throws Exception
  {
    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 cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testViolatesSingleValuedNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertDoesNotConformToSchema(e, schema, defaultPolicy());
    e.setName("cn=test,o=test");
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  /**
   * Tests that an entry covered by a name form will not be rejected if its
   * single-valued RDN component violates that name form but the name form is
   * declared OBSOLETE.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test
  public void testViolatesSingleValuedObsoleteNameForm() throws Exception
  {
    final Schema schema = new SchemaBuilder(Schema.getDefaultSchema())
        .addObjectClass(
            "( testviolatessinglevaluedobsoletenameformoc-oid "
                + "NAME 'testViolatesSingleValuedObsoleteNameFormOC' SUP top "
                + "STRUCTURAL MUST cn MAY description "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase')", false)
        .addNameForm(
            "( testviolatessinglevaluedobsoletenameform-oid "
                + "NAME 'testViolatesSingleValuedObsoleteNameForm' OBSOLETE "
                + "OC testViolatesSingleValuedObsoleteNameFormOC MUST cn "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' )", false).toSchema();
    // @formatter:off
    final Entry e = newEntry(schema,
        "dn: description=foo,o=test",
        "objectClass: top",
        "objectClass: testViolatesSingleValuedObsoleteNameFormOC",
        "cn: test",
        "description: foo");
    // @formatter:on
    assertConformsToSchema(e, schema, defaultPolicy());
  }
  private void assertConformsToSchema(final Entry entry, final Schema schema,
      final SchemaValidationPolicy policy)
  {
    final List<LocalizableMessage> errorMessages = new LinkedList<LocalizableMessage>();
    assertThat(schema.validateEntry(entry, policy, errorMessages)).as(
        errorMessages.toString()).isTrue();
  }
  private void assertConformsToSchema(final Entry entry,
      final SchemaValidationPolicy policy)
  {
    assertConformsToSchema(entry, Schema.getDefaultSchema(), policy);
  }
  private void assertDoesNotConformToSchema(final Entry entry,
      final Schema schema, final SchemaValidationPolicy policy)
  {
    final List<LocalizableMessage> errorMessages = new LinkedList<LocalizableMessage>();
    assertThat(schema.validateEntry(entry, policy, errorMessages)).as(
        errorMessages.toString()).isFalse();
  }
  private void assertDoesNotConformToSchema(final Entry entry,
      final SchemaValidationPolicy policy)
  {
    assertDoesNotConformToSchema(entry, Schema.getDefaultSchema(), policy);
  }
  private Entry newEntry(final Schema schema, final String... ldif)
  {
    try
    {
      return new LDIFEntryReader(ldif).setSchema(schema).readEntry();
    }
    catch (final Exception e)
    {
      throw new IllegalArgumentException(e);
    }
  }
  private Entry newEntry(final String... ldif)
  {
    return newEntry(Schema.getDefaultSchema(), ldif);
  }
  private EntryResolver newResolver(final Entry e)
  {
    return new EntryResolver()
    {
      public Entry getEntry(final DN dn) throws ErrorResultException
      {
        if (e == null)
        {
          throw ErrorResultException.newErrorResult(ResultCode.NO_SUCH_OBJECT,
              "no such entry " + dn.toString());
        }
        assertThat((Object) dn).isEqualTo(e.getName());
        return e;
      }
    };
  }
}