/*
 * 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 2006-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2013-2015 ForgeRock AS
 */
package org.opends.server.types;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.forgerock.opendj.ldap.schema.ObjectClassType;
import org.forgerock.util.Utils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.schema.SchemaConstants;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

/**
 * This class defines a set of tests for the
 * {@link org.opends.server.types.ObjectClass} class.
 */
public final class TestObjectClass extends TestCommonSchemaElements {
  /**
   * Internal class to simplify construction of object classes.
   */
  private static final class ObjectClassBuilder extends
      SchemaDefinitionBuilder<ObjectClass> {
    /** The superior object class from which this object class inherits. */
    private Set<ObjectClass> superior;

    /** The type of object class. */
    private ObjectClassType objectClassType;

    /** The set of required attribute types. */
    private Set<AttributeType> requiredAttributeTypes;
    /** The set of optional attribute types. */
    private Set<AttributeType> optionalAttributeTypes;



    /** {@inheritDoc} */
    @Override
    protected void resetBuilder() {
      this.superior = null;
      this.objectClassType = ObjectClassType.STRUCTURAL;
      this.requiredAttributeTypes = null;
      this.optionalAttributeTypes = null;
    }



    /**
     * Create a new object class builder.
     */
    public ObjectClassBuilder() {
      super();
    }



    /**
     * Create a new object class builder.
     *
     * @param primaryName
     *          The object class primary name.
     * @param oid
     *          The object class OID.
     */
    public ObjectClassBuilder(String primaryName, String oid) {
      super(primaryName, oid);
    }



    /** {@inheritDoc} */
    @Override
    protected ObjectClass buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties) {

      StringBuilder definition = new StringBuilder();
      definition.append("( ");
      definition.append(oid);

      LinkedHashSet<String> nameSet = new LinkedHashSet<>();
      if (primaryName != null)
      {
        nameSet.add(primaryName);
      }

      if (names != null)
      {
        nameSet.addAll(names);
      }

      if (! nameSet.isEmpty())
      {
        definition.append(" NAME ");
        if (nameSet.size() == 1)
        {
          definition.append("'");
          definition.append(nameSet.iterator().next());
          definition.append("'");
        }
        else
        {
          definition.append("( '");
          Utils.joinAsString(definition, "' '", nameSet);
          definition.append("' )");
        }
      }

      if (description != null)
      {
        definition.append(" DESC '");
        definition.append(description);
        definition.append("'");
      }

      if (isObsolete)
      {
        definition.append(" OBSOLETE");
      }

      if (superior != null)
      {
        definition.append(" SUP ");
        Iterator<ObjectClass> iterator = superior.iterator();
        ObjectClass oc =  iterator.next();

        if(iterator.hasNext())
        {
          definition.append("( ");
          definition.append(oc.getNameOrOID());

          while(iterator.hasNext())
          {
            definition.append(" $ ");
            definition.append(iterator.next().getNameOrOID());
          }

          definition.append(" )");
        }
        else
        {
          definition.append(oc.getNameOrOID());
        }
      }

      if (objectClassType != null)
      {
        definition.append(" ");
        definition.append(objectClassType);
      }

      append(definition, "MUST", requiredAttributeTypes);
      append(definition, "MAY", optionalAttributeTypes);

      if (extraProperties != null)
      {
        for (String property : extraProperties.keySet())
        {
          List<String> values = extraProperties.get(property);
          if (values == null || values.isEmpty())
          {
            continue;
          }
          else if (values.size() == 1)
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" '");
            definition.append(values.get(0));
            definition.append("'");
          }
          else
          {
            definition.append(" ");
            definition.append(property);
            definition.append(" (");
            for (String value : values)
            {
              definition.append(" '");
              definition.append(value);
              definition.append("'");
            }

            definition.append(" )");
          }
        }
      }

      definition.append(" )");


      return new ObjectClass(definition.toString(), primaryName, names, oid,
                             description, superior,
                             requiredAttributeTypes,
                             optionalAttributeTypes, objectClassType,
                             isObsolete, extraProperties);
    }



    private void append(StringBuilder definition, String word, Set<AttributeType> attrTypes)
    {
      if (attrTypes != null && !attrTypes.isEmpty())
      {
        definition.append(" ");
        definition.append(word);
        definition.append(" ");
        if (attrTypes.size() == 1)
        {
          definition.append(attrTypes.iterator().next().getNameOrOID());
        }
        else
        {
          definition.append("( ");
          Iterator<AttributeType> iterator = attrTypes.iterator();
          definition.append(iterator.next().getNameOrOID());
          while (iterator.hasNext())
          {
            definition.append(" $ ");
            definition.append(iterator.next().getNameOrOID());
          }
          definition.append(" )");
        }
      }
    }



    /**
     * Set the objectClassType.
     *
     * @param objectClassType
     *          The objectClassType.
     */
    public void setObjectClassType(ObjectClassType objectClassType) {
      this.objectClassType = objectClassType;
    }



    /**
     * Set the superior.
     *
     * @param superior
     *          The superior.
     */
    public void setSuperior(Set<ObjectClass> superior) {
      this.superior = superior;
    }



    /**
     * Add required attribute types.
     *
     * @param types
     *          The required attribute type(s) to add.
     */
    public void addRequiredAttributeTypes(AttributeType... types) {
      if (types == null) {
        throw new NullPointerException("Null types");
      }

      if (this.requiredAttributeTypes == null) {
        this.requiredAttributeTypes = new LinkedHashSet<>();
      }

      this.requiredAttributeTypes.addAll(Arrays.asList(types));
    }



    /**
     * Add optional attribute types.
     *
     * @param types
     *          The optional attribute type(s) to add.
     */
    public void addOptionalAttributeTypes(AttributeType... types) {
      if (types == null) {
        throw new NullPointerException("Null types");
      }

      if (this.optionalAttributeTypes == null) {
        this.optionalAttributeTypes = new LinkedHashSet<>();
      }

      this.optionalAttributeTypes.addAll(Arrays.asList(types));
    }
  }



  /** Array of attribute types to use in tests. */
  private AttributeType[] types;



  /**
   * Once-only initialization.
   *
   * @throws Exception
   *           If an unexpected error occurred.
   */
  @BeforeClass(dependsOnMethods = "setUp")
  public final void setUpTypes() throws Exception {
    types = new AttributeType[10];

    for (int i = 0; i < types.length; i++) {
      String name = "testType" + i;
      types[i] = DirectoryServer.getAttributeTypeOrDefault(name);
    }
  }



  /**
   * Check that the constructor throws an NPE when mandatory
   * parameters are not specified.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(expectedExceptions = NullPointerException.class)
  public void testConstructorNPE() throws Exception {
    Set<AttributeType> emptySet = Collections.emptySet();
    Map<String, List<String>> emptyMap = Collections.emptyMap();

    new ObjectClass(null, "test", Collections.singleton("test"), null,
        "description", Collections.singleton(DirectoryServer.getTopObjectClass()),
        emptySet,
        emptySet, ObjectClassType.STRUCTURAL, false, emptyMap);
  }



  /**
   * Check that the constructor does not throw an exception when all
   * optional parameters are not specified.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testConstructorDefault() throws Exception {
    String definition = "( 1.2.3 )";
    ObjectClass type = new ObjectClass(definition, null, null, "1.2.3", null,
        null, null, null, null, false, null);

    Assert.assertNull(type.getPrimaryName());
  }



  /**
   * Create test data for testing the
   * {@link AttributeType#isOperational()} method.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "getObjectClassTypeTestData")
  public Object[][] createGetObjectClassTypeTestData() {
    return new Object[][] { { null, ObjectClassType.STRUCTURAL },
        { ObjectClassType.STRUCTURAL, ObjectClassType.STRUCTURAL },
        { ObjectClassType.ABSTRACT, ObjectClassType.ABSTRACT },
        { ObjectClassType.AUXILIARY, ObjectClassType.AUXILIARY } };
  }



  /**
   * Check that the {@link ObjectClass#getObjectClassType()} method.
   *
   * @param type
   *          The object class type.
   * @param result
   *          Expected result.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "getObjectClassTypeTestData")
  public void testGetObjectClassType(ObjectClassType type,
      ObjectClassType result) throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.setObjectClassType(type);
    ObjectClass c = builder.getInstance();
    Assert.assertEquals(c.getObjectClassType(), result);
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getOptionalAttributeChain().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainNoSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();

    Set<AttributeType> chain = c.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with multiple superiors but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainEmptyMS() throws Exception {
    ObjectClassBuilder builder1 = new ObjectClassBuilder("parent1",
        "1.2.3");
    builder1.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent1 = builder1.getInstance();

    ObjectClassBuilder builder2 = new ObjectClassBuilder("parent2","3.4.5");
    builder2.addOptionalAttributeTypes(types[3], types[4], types[5]);
    ObjectClass parent2 = builder2.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    ObjectClassBuilder builder3 = new ObjectClassBuilder("child", "6.7.8");
    builder3.setSuperior(superiors);
    ObjectClass child = builder3.getInstance();

    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChain() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with multiple superiors and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainMS() throws Exception {
    ObjectClassBuilder builder1 = new ObjectClassBuilder("parent1",
        "1.2.3");
    builder1.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent1 = builder1.getInstance();

    ObjectClassBuilder builder2 = new ObjectClassBuilder("parent2","3.4.5");
    builder2.addOptionalAttributeTypes(types[3], types[4], types[5]);
    ObjectClass parent2 = builder2.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    ObjectClassBuilder builder3 = new ObjectClassBuilder("child", "6.7.8");
    builder3.addOptionalAttributeTypes(types[6], types[7], types[8]);
    builder3.setSuperior(superiors);
    ObjectClass child = builder3.getInstance();

    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 9);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
    Assert.assertTrue(chain.contains(types[6]));
    Assert.assertTrue(chain.contains(types[7]));
    Assert.assertTrue(chain.contains(types[8]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getOptionalAttributes().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();

    Set<AttributeType> chain = c.getOptionalAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.getOptionalAttributes().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributes() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getOptionalAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getRequiredAttributeChain().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainNoSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();

    Set<AttributeType> chain = c.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with multiple superiors but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainEmptyMS() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent1",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent1 = builder.getInstance();

    builder = new ObjectClassBuilder("parent2","3.4.5");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    ObjectClass parent2 = builder.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    builder = new ObjectClassBuilder("child", "6.7.8");
    builder.setSuperior(superiors);
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChain() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with multiple superiors and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainMS() throws Exception {
     ObjectClassBuilder builder = new ObjectClassBuilder("parent1",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent1 = builder.getInstance();

    builder = new ObjectClassBuilder("parent2","3.4.5");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    ObjectClass parent2 = builder.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    builder = new ObjectClassBuilder("child", "6.7.8");
    builder.addRequiredAttributeTypes(types[6], types[7], types[8]);
    builder.setSuperior(superiors);
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 9);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
    Assert.assertTrue(chain.contains(types[6]));
    Assert.assertTrue(chain.contains(types[7]));
    Assert.assertTrue(chain.contains(types[8]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getRequiredAttributes().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();

    Set<AttributeType> chain = c.getRequiredAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.getRequiredAttributes().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributes() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Set<AttributeType> chain = child.getRequiredAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }



  /**
   * Check the {@link ObjectClass#getSuperiorClasses()} method with no
   * superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetSuperiorClassNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getSuperiorClasses().isEmpty());
  }



  /**
   * Check the {@link ObjectClass#getSuperiorClasses()} method with a
   * superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetSuperiorClassWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.getSuperiorClasses().contains(parent));
  }



  /**
   * Check the {@link ObjectClass#getSuperiorClasses()} method with multiple
   * superiors.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetSuperiorClassWithSuperiors() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent1",
        "1.2.3");
    ObjectClass parent1 = builder.getInstance();
    builder = new ObjectClassBuilder("parent2",
            "2.3.4");
    ObjectClass parent2 = builder.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    builder = new ObjectClassBuilder("child", "1.2.3.4");
    builder.setSuperior(superiors);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.getSuperiorClasses().contains(parent1));
    Assert.assertTrue(child.getSuperiorClasses().contains(parent2));
  }



  /**
   * Check the {@link ObjectClass#isDescendantOf(ObjectClass)} method
   * with no superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsDescendantOfNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType1",
        "1.2.1");
    ObjectClass c1 = builder.getInstance();

    builder = new ObjectClassBuilder("testType2", "1.2.2");
    ObjectClass c2 = builder.getInstance();

    Assert.assertFalse(c1.isDescendantOf(c2));
  }



  /**
   * Check the {@link ObjectClass#isDescendantOf(ObjectClass)} method
   * with a superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsDescendantOfWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "grandParent", "1.2.1");
    ObjectClass grandParent = builder.getInstance();

    builder = new ObjectClassBuilder("parent", "1.2.2");
    builder.setSuperior(Collections.singleton(grandParent));
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(parent.isDescendantOf(grandParent));
    Assert.assertTrue(child.isDescendantOf(parent));
    Assert.assertTrue(child.isDescendantOf(grandParent));

    Assert.assertFalse(child.isDescendantOf(child));
    Assert.assertFalse(parent.isDescendantOf(child));
    Assert.assertFalse(grandParent.isDescendantOf(child));
  }



  /**
   * Check the {@link ObjectClass#isDescendantOf(ObjectClass)} method
   * with multiple superiors.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsDescendantOfWithMultipleSuperiors() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "grandParent", "1.2.1");
    ObjectClass grandParent = builder.getInstance();

    builder = new ObjectClassBuilder("parent1", "1.2.2");
    builder.setSuperior(Collections.singleton(grandParent));
    ObjectClass parent1 = builder.getInstance();

    builder = new ObjectClassBuilder("parent2","2.2.2");
    ObjectClass parent2 = builder.getInstance();
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(superiors);
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(parent1.isDescendantOf(grandParent));
    Assert.assertTrue(child.isDescendantOf(parent1));
    Assert.assertTrue(child.isDescendantOf(parent2));
    Assert.assertTrue(child.isDescendantOf(grandParent));

    Assert.assertFalse(child.isDescendantOf(child));
    Assert.assertFalse(parent1.isDescendantOf(child));
    Assert.assertFalse(parent1.isDescendantOf(parent2));
    Assert.assertFalse(grandParent.isDescendantOf(child));
  }



  /**
   * Create test data for testing the
   * {@link ObjectClass#isExtensibleObject()} method.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "isExtensibleObjectTestData")
  public Object[][] createIsExtensibleObjectTestData() {
    return new Object[][] { { "test", "1.2.3", false },
        { "extensibleObject", "1.2.3", true },
        { "test", "1.3.6.1.4.1.1466.101.120.111", true },
        { "extensibleObject", "1.3.6.1.4.1.1466.101.120.111", true } };
  }



  /**
   * Check that the {@link ObjectClass#getObjectClassType()} method.
   *
   * @param name
   *          The object class name.
   * @param oid
   *          The object class oid.
   * @param result
   *          Expected result.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "isExtensibleObjectTestData")
  public void testIsExtensibleObject(String name, String oid,
      boolean result) throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(name, oid);
    ObjectClass c = builder.getInstance();
    Assert.assertEquals(c.isExtensibleObject(), result);
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isOptional(types[0]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isOptional(types[0]));
    Assert.assertFalse(c.isOptional(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalEmptyWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isOptional(types[0]));
    Assert.assertFalse(child.isOptional(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[1]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isOptional(types[0]));
    Assert.assertTrue(child.isOptional(types[1]));
    Assert.assertFalse(child.isOptional(types[2]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensible() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isOptional(types[0]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensibleRequired() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isOptional(types[0]));
    Assert.assertTrue(c.isOptional(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensibleRequiredSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("extensibleObject", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass c = builder.getInstance();

    Assert.assertFalse(c.isOptional(types[0]));
    Assert.assertTrue(c.isOptional(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isRequired(types[0]));
  }



  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequired(types[0]));
    Assert.assertFalse(c.isRequired(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredEmptyWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isRequired(types[0]));
    Assert.assertFalse(child.isRequired(types[1]));
  }



  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[1]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isRequired(types[0]));
    Assert.assertTrue(child.isRequired(types[1]));
    Assert.assertFalse(child.isRequired(types[2]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isRequiredOrOptional(types[0]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
    Assert.assertFalse(c.isRequiredOrOptional(types[2]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalEmptyWithSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isRequiredOrOptional(types[0]));
    Assert.assertTrue(child.isRequiredOrOptional(types[1]));
    Assert.assertFalse(child.isRequiredOrOptional(types[2]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[2]);
    builder.addRequiredAttributeTypes(types[3]);
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass child = builder.getInstance();

    Assert.assertTrue(child.isRequiredOrOptional(types[0]));
    Assert.assertTrue(child.isRequiredOrOptional(types[1]));
    Assert.assertTrue(child.isRequiredOrOptional(types[2]));
    Assert.assertTrue(child.isRequiredOrOptional(types[3]));
    Assert.assertFalse(child.isRequiredOrOptional(types[4]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensible() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensibleRequired()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
  }



  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensibleRequiredSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();

    builder = new ObjectClassBuilder("extensibleObject", "1.2.3");
    builder.setSuperior(Collections.singleton(parent));
    ObjectClass c = builder.getInstance();

    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
  }

  /**
   * Create test data for testing different combinations of superiors.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "superiorData")
  public Object[][] createSuperiorData() {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "parent1", SchemaConstants.NO_ATTRIBUTES);
    builder.setObjectClassType(ObjectClassType.ABSTRACT);
    ObjectClass parent1 = builder.getInstance();

    builder = new ObjectClassBuilder(
        "parent2", "1.2");
    builder.setObjectClassType(ObjectClassType.ABSTRACT);
    ObjectClass parent2 = builder.getInstance();

    builder = new ObjectClassBuilder(
        "parent3", "1.3");
    builder.setObjectClassType(ObjectClassType.STRUCTURAL);
    ObjectClass parent3 = builder.getInstance();

    builder = new ObjectClassBuilder(
        "parent4", "1.4");
    ObjectClass parent4 = builder.getInstance();

    builder = new ObjectClassBuilder(
        "parent5", "1.5");
    builder.setObjectClassType(ObjectClassType.AUXILIARY);
    ObjectClass parent5 = builder.getInstance();

    builder = new ObjectClassBuilder(
        "parent6", "1.6");
    builder.setObjectClassType(ObjectClassType.AUXILIARY);
    ObjectClass parent6 = builder.getInstance();

    return new Object[][] { { parent1, parent2, ObjectClassType.ABSTRACT,true },
        { parent3, parent4, ObjectClassType.STRUCTURAL,true },
        { parent5, parent6, ObjectClassType.AUXILIARY,true }
    };
  }



  /**
   * Check incompatible superiors.
   *
   * @param parent1
   *          First superior
   * @param parent2
   *          Second superior
   * @param type
   *          The object class type.
   * @param isValid
   *          Whether the superior combination is valid.
   */
  @Test(dataProvider = "superiorData")
  public void testMultipleSuperiors(ObjectClass parent1,
          ObjectClass parent2,
          ObjectClassType type,
          boolean isValid) throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType", "1.2.3");
    builder.setObjectClassType(type);
    Set<ObjectClass> superiors = new LinkedHashSet<>();
    superiors.add(parent1);
    superiors.add(parent2);
    builder.setSuperior(superiors);
    ObjectClass child = builder.getInstance();
    Assert.assertEquals(child.getSuperiorClasses().size(), 2);
  }



  /** {@inheritDoc} */
  @Override
  protected SchemaDefinitionBuilder getBuilder(String name, String oid) {
    return new ObjectClassBuilder(name, oid);
  }

}
