From 3edfdef912dc5193e9313c82ee851f145b0505fb Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 29 Mar 2016 09:48:25 +0000
Subject: [PATCH] OPENDJ-2803 Migrate Attribute

---
 opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java |  222 +++++++++++++++++++++------
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java         |  232 +++++++++++++++++++---------
 2 files changed, 327 insertions(+), 127 deletions(-)

diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
index 7f732b6..754c654 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -81,7 +81,6 @@
     private static final class MultiOptionImpl extends Impl {
 
         private final String[] normalizedOptions;
-
         private final String[] options;
 
         private MultiOptionImpl(final String[] options, final String[] normalizedOptions) {
@@ -203,7 +202,6 @@
     private static final class SingleOptionImpl extends Impl {
 
         private final String normalizedOption;
-
         private final String option;
 
         private SingleOptionImpl(final String option, final String normalizedOption) {
@@ -351,9 +349,8 @@
     private static final AttributeDescription OBJECT_CLASS;
     static {
         final AttributeType attributeType = Schema.getCoreSchema().getAttributeType("2.5.4.0");
-        OBJECT_CLASS =
-                new AttributeDescription(attributeType.getNameOrOID(), attributeType,
-                        ZERO_OPTION_IMPL);
+        final String attributeName = attributeType.getNameOrOID();
+        OBJECT_CLASS = new AttributeDescription(attributeName, attributeName, attributeType, ZERO_OPTION_IMPL);
     }
 
     /**
@@ -378,21 +375,15 @@
         Reject.ifNull(option);
 
         final String normalizedOption = toLowerCase(option);
-        if (pimpl.hasOption(normalizedOption)) {
+        if (optionsPimpl.hasOption(normalizedOption)) {
             return this;
         }
 
-        final String oldAttributeDescription = attributeDescription;
-        final StringBuilder builder =
-                new StringBuilder(oldAttributeDescription.length() + option.length() + 1);
-        builder.append(oldAttributeDescription);
-        builder.append(';');
-        builder.append(option);
-        final String newAttributeDescription = builder.toString();
+        final String newAttributeDescription = appendOption(attributeDescription, option);
 
-        final Impl impl = pimpl;
+        final Impl impl = optionsPimpl;
         if (impl instanceof ZeroOptionImpl) {
-            return new AttributeDescription(newAttributeDescription, attributeType,
+            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                     new SingleOptionImpl(option, normalizedOption));
         } else if (impl instanceof SingleOptionImpl) {
             final SingleOptionImpl simpl = (SingleOptionImpl) impl;
@@ -410,7 +401,7 @@
                 newNormalizedOptions[1] = normalizedOption;
             }
 
-            return new AttributeDescription(newAttributeDescription, attributeType,
+            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                     new MultiOptionImpl(newOptions, newNormalizedOptions));
         } else {
             final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
@@ -441,7 +432,7 @@
                 newNormalizedOptions[sz2] = normalizedOption;
             }
 
-            return new AttributeDescription(newAttributeDescription, attributeType,
+            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                     new MultiOptionImpl(newOptions, newNormalizedOptions));
         }
     }
@@ -464,7 +455,7 @@
         Reject.ifNull(option);
 
         final String normalizedOption = toLowerCase(option);
-        if (!pimpl.hasOption(normalizedOption)) {
+        if (!optionsPimpl.hasOption(normalizedOption)) {
             return this;
         }
 
@@ -479,11 +470,11 @@
                 .length());
         final String newAttributeDescription = builder.toString();
 
-        final Impl impl = pimpl;
+        final Impl impl = optionsPimpl;
         if (impl instanceof ZeroOptionImpl) {
             throw new IllegalStateException("ZeroOptionImpl unexpected");
         } else if (impl instanceof SingleOptionImpl) {
-            return new AttributeDescription(newAttributeDescription, attributeType,
+            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                     ZERO_OPTION_IMPL);
         } else {
             final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
@@ -503,7 +494,7 @@
                     remainingNormalizedOption = mimpl.normalizedOptions[0];
                 }
 
-                return new AttributeDescription(newAttributeDescription, attributeType,
+                return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                         new SingleOptionImpl(remainingOption, remainingNormalizedOption));
             } else {
                 final String[] newOptions = new String[mimpl.options.length - 1];
@@ -522,15 +513,14 @@
                     }
                 }
 
-                return new AttributeDescription(newAttributeDescription, attributeType,
+                return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                         new MultiOptionImpl(newOptions, newNormalizedOptions));
             }
         }
     }
 
     /**
-     * Creates an attribute description having the provided attribute type and
-     * no options.
+     * Creates an attribute description having the provided attribute type and no options.
      *
      * @param attributeType
      *            The attribute type.
@@ -539,21 +529,35 @@
      *             If {@code attributeType} was {@code null}.
      */
     public static AttributeDescription create(final AttributeType attributeType) {
-        Reject.ifNull(attributeType);
-
-        // Use object identity in case attribute type does not come from
-        // core schema.
-        if (attributeType == OBJECT_CLASS.getAttributeType()) {
-            return OBJECT_CLASS;
-        } else {
-            return new AttributeDescription(attributeType.getNameOrOID(), attributeType,
-                    ZERO_OPTION_IMPL);
-        }
+        return create(attributeType.getNameOrOID(), attributeType);
     }
 
     /**
-     * Creates an attribute description having the provided attribute type and
-     * single option.
+     * Creates an attribute description having the provided attribute name, type and no options.
+     *
+     * @param attributeName
+     *            The attribute name.
+     * @param attributeType
+     *            The attribute type.
+     * @return The attribute description.
+     * @throws NullPointerException
+     *             If {@code attributeType} was {@code null}.
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2803 Migrate Attribute
+     */
+    @Deprecated
+    public static AttributeDescription create(final String attributeName, final AttributeType attributeType) {
+        Reject.ifNull(attributeName, attributeType);
+
+        // Use object identity in case attribute type does not come from core schema.
+        if (attributeType == OBJECT_CLASS.getAttributeType()) {
+            return OBJECT_CLASS;
+        }
+        return new AttributeDescription(attributeName, attributeName, attributeType, ZERO_OPTION_IMPL);
+    }
+
+    /**
+     * Creates an attribute description having the provided attribute type and single option.
      *
      * @param attributeType
      *            The attribute type.
@@ -564,18 +568,64 @@
      *             If {@code attributeType} or {@code option} was {@code null}.
      */
     public static AttributeDescription create(final AttributeType attributeType, final String option) {
-        Reject.ifNull(attributeType, option);
+        return create(attributeType.getNameOrOID(), attributeType, option);
+    }
 
-        final String oid = attributeType.getNameOrOID();
+    /**
+     * Creates an attribute description having the provided attribute name, type and single option.
+     *
+     * @param attributeName
+     *            The attribute name.
+     * @param attributeType
+     *            The attribute type.
+     * @param option
+     *            The attribute option.
+     * @return The attribute description.
+     * @throws NullPointerException
+     *             If {@code attributeType} or {@code option} was {@code null}.
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2803 Migrate Attribute
+     */
+    @Deprecated
+    public static AttributeDescription create(
+            final String attributeName, final AttributeType attributeType, final String option) {
+        Reject.ifNull(attributeName, attributeType, option);
+
+        final String attributeDescription = appendOption(attributeName, option);
+        final String normalizedOption = toLowerCase(option);
+
+        return new AttributeDescription(attributeDescription, attributeName, attributeType,
+            new SingleOptionImpl(option, normalizedOption));
+    }
+
+    private static String appendOption(final String oid, final String option) {
         final StringBuilder builder = new StringBuilder(oid.length() + option.length() + 1);
         builder.append(oid);
         builder.append(';');
         builder.append(option);
-        final String attributeDescription = builder.toString();
-        final String normalizedOption = toLowerCase(option);
+        return builder.toString();
+    }
 
-        return new AttributeDescription(attributeDescription, attributeType, new SingleOptionImpl(
-                option, normalizedOption));
+    /**
+     * Creates an attribute description having the provided attribute name, type and options.
+     *
+     * @param attributeName
+     *            The attribute name.
+     * @param attributeType
+     *            The attribute type.
+     * @param options
+     *            The attribute options.
+     * @return The attribute description.
+     * @throws NullPointerException
+     *             If {@code attributeType} or {@code options} was {@code null}.
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2803 Migrate Attribute
+     */
+    @Deprecated
+    public static AttributeDescription create(
+            final String attributeName, final AttributeType attributeType, final String... options) {
+        Reject.ifNull(options);
+        return create(attributeName, attributeType, Arrays.asList(options));
     }
 
     /**
@@ -591,7 +641,7 @@
      */
     public static AttributeDescription create(final AttributeType attributeType, final String... options) {
         Reject.ifNull(options);
-        return create(attributeType, Arrays.asList(options));
+        return create(attributeType.getNameOrOID(), attributeType, Arrays.asList(options));
     }
 
     /**
@@ -606,23 +656,43 @@
      *             If {@code attributeType} or {@code options} was {@code null}.
      */
     public static AttributeDescription create(final AttributeType attributeType, final Collection<String> options) {
-        Reject.ifNull(attributeType);
+        return create(attributeType.getNameOrOID(), attributeType, options);
+    }
+
+    /**
+     * Creates an attribute description having the provided attribute name, type and options.
+     *
+     * @param attributeName
+     *            The attribute name.
+     * @param attributeType
+     *            The attribute type.
+     * @param options
+     *            The attribute options.
+     * @return The attribute description.
+     * @throws NullPointerException
+     *             If {@code attributeType} or {@code options} was {@code null}.
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2803 Migrate Attribute
+     */
+    @Deprecated
+    public static AttributeDescription create(
+            final String attributeName, final AttributeType attributeType, final Collection<String> options) {
+        Reject.ifNull(attributeName, attributeType);
 
         final Collection<String> opts = options != null ? options : Collections.<String> emptySet();
         switch (opts.size()) {
         case 0:
-            return create(attributeType);
+            return create(attributeName, attributeType);
         case 1:
-            return create(attributeType, opts.iterator().next());
+            return create(attributeName, attributeType, opts.iterator().next());
         default:
             final String[] optionsList = new String[opts.size()];
             final String[] normalizedOptions = new String[opts.size()];
 
             final Iterator<String> it = opts.iterator();
-            final String oid = attributeType.getNameOrOID();
             final StringBuilder builder =
-                    new StringBuilder(oid.length() + it.next().length() + it.next().length() + 2);
-            builder.append(oid);
+                    new StringBuilder(attributeName.length() + it.next().length() + it.next().length() + 2);
+            builder.append(attributeName);
 
             int i = 0;
             for (final String option : opts) {
@@ -634,10 +704,9 @@
             Arrays.sort(normalizedOptions);
 
             final String attributeDescription = builder.toString();
-            return new AttributeDescription(attributeDescription, attributeType,
+            return new AttributeDescription(attributeDescription, attributeName, attributeType,
                     new MultiOptionImpl(optionsList, normalizedOptions));
         }
-
     }
 
     /**
@@ -779,7 +848,6 @@
             i++;
             while (i < length) {
                 c = attributeDescription.charAt(i);
-
                 if (c == ';' || c == ' ') {
                     break;
                 }
@@ -827,8 +895,7 @@
             i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
         }
 
-        // Determine the portion of the string containing the attribute type
-        // name.
+        // Determine the portion of the string containing the attribute type name.
         String oid;
         if (attributeTypeStart == 0 && attributeTypeEnd == length) {
             oid = attributeDescription;
@@ -848,15 +915,12 @@
         // If we're already at the end of the attribute description then it
         // does not contain any options.
         if (i == length) {
-            // Use object identity in case attribute type does not come from
-            // core schema.
+            // Use object identity in case attribute type does not come from core schema.
             if (attributeType == OBJECT_CLASS.getAttributeType()
                     && attributeDescription.equals(OBJECT_CLASS.toString())) {
                 return OBJECT_CLASS;
-            } else {
-                return new AttributeDescription(attributeDescription, attributeType,
-                        ZERO_OPTION_IMPL);
             }
+            return new AttributeDescription(attributeDescription, oid, attributeType, ZERO_OPTION_IMPL);
         }
 
         // At this point 'i' must point at a semi-colon.
@@ -911,7 +975,7 @@
         // If we're already at the end of the attribute description then it
         // only contains a single option.
         if (i == length) {
-            return new AttributeDescription(attributeDescription, attributeType,
+            return new AttributeDescription(attributeDescription, oid, attributeType,
                     new SingleOptionImpl(option, normalizedOption));
         }
 
@@ -977,23 +1041,23 @@
             normalizedOptions.add(normalizedOption);
         }
 
-        return new AttributeDescription(attributeDescription, attributeType, new MultiOptionImpl(
-                options.toArray(new String[options.size()]), normalizedOptions
-                        .toArray(new String[normalizedOptions.size()])));
+        return new AttributeDescription(attributeDescription, oid, attributeType,
+                new MultiOptionImpl(options.toArray(new String[options.size()]),
+                                    normalizedOptions.toArray(new String[normalizedOptions.size()])));
     }
 
     private final String attributeDescription;
-
+    private final String nameOrOid;
     private final AttributeType attributeType;
-
-    private final Impl pimpl;
+    private final Impl optionsPimpl;
 
     /** Private constructor. */
-    private AttributeDescription(final String attributeDescription,
+    private AttributeDescription(final String attributeDescription, final String attributeName,
             final AttributeType attributeType, final Impl pimpl) {
         this.attributeDescription = attributeDescription;
+        this.nameOrOid = attributeName;
         this.attributeType = attributeType;
-        this.pimpl = pimpl;
+        this.optionsPimpl = pimpl;
     }
 
     /**
@@ -1016,7 +1080,7 @@
             return result;
         } else {
             // Attribute type is the same, so compare options.
-            return pimpl.compareTo(other.pimpl);
+            return optionsPimpl.compareTo(other.optionsPimpl);
         }
     }
 
@@ -1033,7 +1097,7 @@
      */
     public boolean hasOption(final String option) {
         final String normalizedOption = toLowerCase(option);
-        return pimpl.hasOption(normalizedOption);
+        return optionsPimpl.hasOption(normalizedOption);
     }
 
     /**
@@ -1054,7 +1118,7 @@
             return true;
         } else if (o instanceof AttributeDescription) {
             final AttributeDescription other = (AttributeDescription) o;
-            return attributeType.equals(other.attributeType) && pimpl.equals(other.pimpl);
+            return attributeType.equals(other.attributeType) && optionsPimpl.equals(other.optionsPimpl);
         } else {
             return false;
         }
@@ -1070,6 +1134,20 @@
     }
 
     /**
+     * Returns the attribute name or the oid provided by the user associated with this attribute
+     * description.
+     *
+     * @return The attribute name or the oid provided by the user associated with this attribute
+     *         description.
+     * @deprecated This method may be removed at any time
+     * @since OPENDJ-2803 Migrate Attribute
+     */
+    @Deprecated
+    public String getNameOrOID() {
+        return nameOrOid;
+    }
+
+    /**
      * Returns an {@code Iterable} containing the options contained in this
      * attribute description. Attempts to remove options using an iterator's
      * {@code remove()} method are not permitted and will result in an
@@ -1078,7 +1156,7 @@
      * @return An {@code Iterable} containing the options.
      */
     public Iterable<String> getOptions() {
-        return pimpl;
+        return optionsPimpl;
     }
 
     /**
@@ -1091,7 +1169,7 @@
     @Override
     public int hashCode() {
         // FIXME: should we cache this?
-        return attributeType.hashCode() * 31 + pimpl.hashCode();
+        return attributeType.hashCode() * 31 + optionsPimpl.hashCode();
     }
 
     /**
@@ -1101,7 +1179,7 @@
      *         {@code false} if not.
      */
     public boolean hasOptions() {
-        return pimpl.hasOptions();
+        return optionsPimpl.hasOptions();
     }
 
     /**
@@ -1160,7 +1238,7 @@
      */
     public boolean isSubTypeOf(final AttributeDescription other) {
         return attributeType.isSubTypeOf(other.attributeType)
-            && pimpl.isSubTypeOf(other.pimpl);
+            && optionsPimpl.isSubTypeOf(other.optionsPimpl);
     }
 
     /**
@@ -1187,7 +1265,7 @@
      */
     public boolean isSuperTypeOf(final AttributeDescription other) {
         return attributeType.isSuperTypeOf(other.attributeType)
-            && pimpl.isSuperTypeOf(other.pimpl);
+            && optionsPimpl.isSuperTypeOf(other.optionsPimpl);
     }
 
     /**
@@ -1205,7 +1283,7 @@
         if (this == other) {
             return true;
         } else {
-            return attributeType.matches(other.attributeType) && pimpl.equals(other.pimpl);
+            return attributeType.matches(other.attributeType) && optionsPimpl.equals(other.optionsPimpl);
         }
     }
 
diff --git a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
index 9b520fc..a2c061c 100644
--- a/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
+++ b/opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
@@ -21,9 +21,11 @@
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
-import java.util.Iterator;
+import java.util.Arrays;
 
+import org.assertj.core.api.Assertions;
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.schema.AttributeType;
 import org.forgerock.opendj.ldap.schema.Schema;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -161,7 +163,10 @@
             { "cn;BAR;FOO", "cn", new String[] { "BAR", "FOO" }, true },
             { " cn;BAR;FOO ", "cn", new String[] { "BAR", "FOO" }, true },
             { "  cn;BAR;FOO  ", "cn", new String[] { "BAR", "FOO" }, true },
+            { "  CN;BAR;FOO  ", "CN", new String[] { "BAR", "FOO" }, true },
             { "cn;xxx;yyy;zzz", "cn", new String[] { "xxx", "yyy", "zzz" }, false },
+            { "cn;zzz;YYY;xxx", "cn", new String[] { "zzz", "YYY", "xxx" }, false },
+            { "CN;zzz;YYY;xxx", "CN", new String[] { "zzz", "YYY", "xxx" }, false },
         };
         // @formatter:on
     }
@@ -224,15 +229,14 @@
                 AttributeDescription.valueOf(ad, Schema.getCoreSchema());
 
         assertEquals(attributeDescription.toString(), ad);
-
+        assertEquals(attributeDescription.getNameOrOID(), ad);
         assertEquals(attributeDescription.getAttributeType().getNameOrOID(), at);
         assertEquals(attributeDescription.isObjectClass(), isObjectClass);
 
         assertFalse(attributeDescription.hasOptions());
         assertFalse(attributeDescription.hasOption("dummy"));
 
-        final Iterator<String> iterator = attributeDescription.getOptions().iterator();
-        assertFalse(iterator.hasNext());
+        Assertions.assertThat(attributeDescription.getOptions()).isEmpty();
     }
 
     /** FIXME: none of these pass! The valueOf method is far too lenient. */
@@ -252,8 +256,7 @@
         assertEquals(attributeDescription.getAttributeType().getNameOrOID(), at);
         assertFalse(attributeDescription.isObjectClass());
 
-        assertEquals(attributeDescription.hasOptions(), options.length != 0);
-
+        assertOptions(attributeDescription, options);
         assertFalse(attributeDescription.hasOption("dummy"));
         if (containsFoo) {
             assertTrue(attributeDescription.hasOption("foo"));
@@ -264,28 +267,24 @@
             assertFalse(attributeDescription.hasOption("FOO"));
             assertFalse(attributeDescription.hasOption("FoO"));
         }
+    }
 
+    private void assertOptions(final AttributeDescription attributeDescription, final String... options) {
+        assertEquals(attributeDescription.hasOptions(), options.length != 0);
         for (final String option : options) {
             assertTrue(attributeDescription.hasOption(option));
         }
 
-        final Iterator<String> iterator = attributeDescription.getOptions().iterator();
-        for (final String option : options) {
-            assertTrue(iterator.hasNext());
-            assertEquals(iterator.next(), option);
-        }
-        assertFalse(iterator.hasNext());
+        Assertions.assertThat(attributeDescription.getOptions()).containsExactly(options);
     }
 
     @Test
     public void testWithOptionAddFirstOption() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn");
         AttributeDescription ad2 = ad1.withOption("test");
-        assertTrue(ad2.hasOptions());
-        assertTrue(ad2.hasOption("test"));
+        assertOptions(ad2, "test");
         assertFalse(ad2.hasOption("dummy"));
         assertEquals(ad2.toString(), "cn;test");
-        assertEquals(ad2.getOptions().iterator().next(), "test");
     }
 
     @Test
@@ -297,16 +296,20 @@
 
     @Test
     public void testWithOptionAddSecondOption() {
-        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1");
-        AttributeDescription ad2 = ad1.withOption("test2");
-        assertTrue(ad2.hasOptions());
-        assertTrue(ad2.hasOption("test1"));
-        assertTrue(ad2.hasOption("test2"));
+        testWithOptionAddSecondOption("test1", "test2");
+    }
+
+    @Test
+    public void testWithOptionAddSecondOption2() {
+        testWithOptionAddSecondOption("test2", "test1");
+    }
+
+    private void testWithOptionAddSecondOption(String option1, String option2) {
+        AttributeDescription ad1 = AttributeDescription.valueOf("cn;" + option1);
+        AttributeDescription ad2 = ad1.withOption(option2);
+        assertOptions(ad2, option1, option2);
         assertFalse(ad2.hasOption("dummy"));
-        assertEquals(ad2.toString(), "cn;test1;test2");
-        Iterator<String> i = ad2.getOptions().iterator();
-        assertEquals(i.next(), "test1");
-        assertEquals(i.next(), "test2");
+        assertEquals(ad2.toString(), toAttributeDescriptionString("cn", option1, option2));
     }
 
     @Test
@@ -319,6 +322,24 @@
     }
 
     @Test
+    public void testWithOptionAddMultipleOptions() {
+        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
+        AttributeDescription ad2 = ad1.withOption("test4").withOption("test3");
+        assertOptions(ad2, "test1", "test2", "test4", "test3");
+        assertFalse(ad2.hasOption("dummy"));
+        assertEquals(ad2.toString(), "cn;test1;test2;test4;test3");
+    }
+
+    @Test
+    public void testWithOptionAddMultipleOptions2() {
+        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
+        AttributeDescription ad2 = ad1.withOption("test0");
+        assertOptions(ad2, "test1", "test2", "test0");
+        assertFalse(ad2.hasOption("dummy"));
+        assertEquals(ad2.toString(), "cn;test1;test2;test0");
+    }
+
+    @Test
     public void testWithoutOptionEmpty() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn");
         AttributeDescription ad2 = ad1.withoutOption("test");
@@ -329,10 +350,9 @@
     public void testWithoutOptionFirstOption() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test");
         AttributeDescription ad2 = ad1.withoutOption("test");
-        assertFalse(ad2.hasOptions());
+        assertOptions(ad2);
         assertFalse(ad2.hasOption("test"));
         assertEquals(ad2.toString(), "cn");
-        assertFalse(ad2.getOptions().iterator().hasNext());
     }
 
     @Test
@@ -346,22 +366,18 @@
     public void testWithoutOptionSecondOption1() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
         AttributeDescription ad2 = ad1.withoutOption("test1");
-        assertTrue(ad2.hasOptions());
+        assertOptions(ad2, "test2");
         assertFalse(ad2.hasOption("test1"));
-        assertTrue(ad2.hasOption("test2"));
         assertEquals(ad2.toString(), "cn;test2");
-        assertEquals(ad2.getOptions().iterator().next(), "test2");
     }
 
     @Test
     public void testWithoutOptionSecondOption2() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
         AttributeDescription ad2 = ad1.withoutOption("test2");
-        assertTrue(ad2.hasOptions());
-        assertTrue(ad2.hasOption("test1"));
+        assertOptions(ad2, "test1");
         assertFalse(ad2.hasOption("test2"));
         assertEquals(ad2.toString(), "cn;test1");
-        assertEquals(ad2.getOptions().iterator().next(), "test1");
     }
 
     @Test
@@ -375,42 +391,27 @@
     public void testWithoutOptionThirdOption1() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
         AttributeDescription ad2 = ad1.withoutOption("test1");
-        assertTrue(ad2.hasOptions());
+        assertOptions(ad2, "test2", "test3");
         assertFalse(ad2.hasOption("test1"));
-        assertTrue(ad2.hasOption("test2"));
-        assertTrue(ad2.hasOption("test3"));
         assertEquals(ad2.toString(), "cn;test2;test3");
-        Iterator<String> i = ad2.getOptions().iterator();
-        assertEquals(i.next(), "test2");
-        assertEquals(i.next(), "test3");
     }
 
     @Test
     public void testWithoutOptionThirdOption2() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
         AttributeDescription ad2 = ad1.withoutOption("test2");
-        assertTrue(ad2.hasOptions());
-        assertTrue(ad2.hasOption("test1"));
+        assertOptions(ad2, "test1", "test3");
         assertFalse(ad2.hasOption("test2"));
-        assertTrue(ad2.hasOption("test3"));
         assertEquals(ad2.toString(), "cn;test1;test3");
-        Iterator<String> i = ad2.getOptions().iterator();
-        assertEquals(i.next(), "test1");
-        assertEquals(i.next(), "test3");
     }
 
     @Test
     public void testWithoutOptionThirdOption3() {
         AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
         AttributeDescription ad2 = ad1.withoutOption("test3");
-        assertTrue(ad2.hasOptions());
-        assertTrue(ad2.hasOption("test1"));
-        assertTrue(ad2.hasOption("test2"));
+        assertOptions(ad2, "test1", "test2");
         assertFalse(ad2.hasOption("test3"));
         assertEquals(ad2.toString(), "cn;test1;test2");
-        Iterator<String> i = ad2.getOptions().iterator();
-        assertEquals(i.next(), "test1");
-        assertEquals(i.next(), "test2");
     }
 
     @Test
@@ -419,4 +420,125 @@
         AttributeDescription ad2 = ad1.withoutOption("dummy");
         assertSame(ad1, ad2);
     }
+
+    @Test
+    public void testCreateAttributeType() {
+        Schema schema = Schema.getCoreSchema();
+        AttributeType attributeType = schema.getAttributeType("cn");
+        String name = attributeType.getNameOrOID();
+
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(attributeType),
+            name, attributeType);
+    }
+
+    @Test
+    public void testCreateAttributeNameAndType() {
+        Schema schema = Schema.getCoreSchema();
+        String name = "CN";
+        AttributeType attributeType = schema.getAttributeType(name);
+
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(name, attributeType),
+            name, attributeType);
+    }
+
+    @Test
+    public void testCreateAttributeTypeAndOption() {
+        Schema schema = Schema.getCoreSchema();
+        AttributeType attributeType = schema.getAttributeType("cn");
+        String name = attributeType.getNameOrOID();
+
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(attributeType, "option"),
+            name, attributeType, "option");
+    }
+
+    @Test
+    public void testCreateAttributeNameTypeAndOption() {
+        Schema schema = Schema.getCoreSchema();
+        String name = "CN";
+        AttributeType attributeType = schema.getAttributeType(name);
+
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(name, attributeType, "option"),
+            name, attributeType, "option");
+    }
+
+    @Test
+    public void testCreateAttributeTypeAndOptionsArray() {
+        Schema schema = Schema.getCoreSchema();
+        AttributeType attributeType = schema.getAttributeType("cn");
+        String name = attributeType.getNameOrOID();
+
+        String[] options = { "option1", "option2" };
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(attributeType, options),
+            name, attributeType, options);
+    }
+
+    @Test
+    public void testCreateAttributeNameTypeAndOptionsArray() {
+        Schema schema = Schema.getCoreSchema();
+        String name = "CN";
+        AttributeType attributeType = schema.getAttributeType(name);
+
+        String[] options = { "option1", "option2" };
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(name, attributeType, options),
+            name, attributeType, options);
+    }
+
+    @Test
+    public void testCreateAttributeTypeAndOptionsCollection() {
+        Schema schema = Schema.getCoreSchema();
+        AttributeType attributeType = schema.getAttributeType("cn");
+        String name = attributeType.getNameOrOID();
+
+        String[] options = { "option1", "option2" };
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(attributeType, Arrays.asList(options)),
+            name, attributeType, options);
+    }
+
+    @Test
+    public void testCreateAttributeNameTypeAndNoOptionsCollection() {
+        testCreateAttributeNameTypeAndOptionsCollection();
+    }
+
+    @Test
+    public void testCreateAttributeNameTypeAndOneOptionCollection() {
+        testCreateAttributeNameTypeAndOptionsCollection("option");
+    }
+
+    @Test
+    public void testCreateAttributeNameTypeAndTwoOptionsCollection() {
+        testCreateAttributeNameTypeAndOptionsCollection("option1", "option2");
+    }
+
+    private void testCreateAttributeNameTypeAndOptionsCollection(String... options) {
+        Schema schema = Schema.getCoreSchema();
+        String name = "CN";
+        AttributeType attributeType = schema.getAttributeType(name);
+
+        assertAttributeDescriptionCreate(
+            AttributeDescription.create(name, attributeType, Arrays.asList(options)),
+            name, attributeType, options);
+    }
+
+    private void assertAttributeDescriptionCreate(AttributeDescription attrDesc,
+            String name, AttributeType attributeType, String... options) {
+        assertEquals(attrDesc.getAttributeType(), attributeType);
+        assertEquals(attrDesc.getNameOrOID(), name);
+        assertOptions(attrDesc, options);
+        assertEquals(attrDesc.toString(), toAttributeDescriptionString(name, options));
+    }
+
+    private String toAttributeDescriptionString(String name, String... options) {
+        StringBuilder sb = new StringBuilder(name);
+        for (String option : options) {
+            sb.append(";").append(option);
+        }
+        return sb.toString();
+    }
 }

--
Gitblit v1.10.0