From 1c845e121b14b549308383e431c9040917984d6c Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Tue, 15 Jun 2010 14:39:37 +0000
Subject: [PATCH] DN normalization enhancements:

---
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/RDNTestCase.java                                      |    8 
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java |  212 +++++++++++++++
 opendj-sdk/sdk/src/org/opends/sdk/DN.java                                                                       |  224 +++++++--------
 opendj-sdk/sdk/src/org/opends/sdk/RDN.java                                                                      |   27 -
 opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java                         |  276 ++++++++++---------
 opendj-sdk/sdk/src/org/opends/sdk/AVA.java                                                                      |   36 --
 opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/DNTestCase.java                                       |   26 -
 7 files changed, 470 insertions(+), 339 deletions(-)

diff --git a/opendj-sdk/sdk/src/org/opends/sdk/AVA.java b/opendj-sdk/sdk/src/org/opends/sdk/AVA.java
index b6868ce..3949155 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/AVA.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/AVA.java
@@ -844,20 +844,6 @@
 
 
 
-  StringBuilder toNormalizedString(final StringBuilder builder)
-  {
-    return toString(builder, true);
-  }
-
-
-
-  StringBuilder toString(final StringBuilder builder)
-  {
-    return toString(builder, false);
-  }
-
-
-
   private ByteString getNormalizeValue()
   {
     final MatchingRule matchingRule = attributeType.getEqualityMatchingRule();
@@ -877,41 +863,29 @@
 
 
 
-  private StringBuilder toString(final StringBuilder builder,
-      final boolean normalize)
+  StringBuilder toString(final StringBuilder builder)
   {
-    final ByteString value = normalize ? getNormalizeValue() : attributeValue;
-
     if (!attributeType.getNames().iterator().hasNext())
     {
       builder.append(attributeType.getOID());
       builder.append("=#");
-      StaticUtils.toHex(value, builder);
+      StaticUtils.toHex(attributeValue, builder);
     }
     else
     {
       final String name = attributeType.getNameOrOID();
-      if (normalize)
-      {
-        // Normalizing.
-        StaticUtils.toLowerCase(name, builder);
-      }
-      else
-      {
-        builder.append(name);
-      }
-
+      builder.append(name);
       builder.append("=");
 
       final Syntax syntax = attributeType.getSyntax();
       if (!syntax.isHumanReadable())
       {
         builder.append("#");
-        StaticUtils.toHex(value, builder);
+        StaticUtils.toHex(attributeValue, builder);
       }
       else
       {
-        final String str = value.toString();
+        final String str = attributeValue.toString();
         if (str.length() == 0)
         {
           return builder;
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/DN.java b/opendj-sdk/sdk/src/org/opends/sdk/DN.java
index 7d4dd30..9631c20 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/DN.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/DN.java
@@ -154,6 +154,88 @@
 
 
 
+  /**
+   * Compares the provided DN values to determine their relative order in a
+   * sorted list.
+   *
+   * @param dn1
+   *          The first DN to be compared. It must not be {@code null}.
+   * @param dn2
+   *          The second DN to be compared. It must not be {@code null}.
+   * @return A negative integer if the first DN should come before the second DN
+   *         in a sorted list, a positive integer if the first DN should come
+   *         after the second DN in a sorted list, or zero if the two DN values
+   *         can be considered equal.
+   */
+  private static int compareTo(final DN dn1, final DN dn2)
+  {
+    // Quickly check if we are comparing against root dse.
+    if (dn1.isRootDN())
+    {
+      if (dn2.isRootDN())
+      {
+        // both are equal.
+        return 0;
+      }
+      else
+      {
+        // dn1 comes before dn2.
+        return -1;
+      }
+    }
+
+    if (dn2.isRootDN())
+    {
+      // dn1 comes after dn2.
+      return 1;
+    }
+
+    int dn1Size = dn1.size - 1;
+    int dn2Size = dn2.size - 1;
+    while (dn1Size >= 0 && dn2Size >= 0)
+    {
+      final DN dn1Parent = dn1.parent(dn1Size--);
+      final DN dn2Parent = dn2.parent(dn2Size--);
+      if (dn1Parent.isRootDN())
+      {
+        if (dn2Parent.isRootDN())
+        {
+          break;
+        }
+        return -1;
+      }
+
+      if (dn2Parent.isRootDN())
+      {
+        return 1;
+      }
+
+      final int result = dn1Parent.rdn.compareTo(dn2Parent.rdn);
+      if (result > 0)
+      {
+        return 1;
+      }
+      else if (result < 0)
+      {
+        return -1;
+      }
+    }
+
+    // What do we have here?
+    if (dn1Size > dn2Size)
+    {
+      return 1;
+    }
+    else if (dn1Size < dn2Size)
+    {
+      return -1;
+    }
+
+    return 0;
+  }
+
+
+
   // Decodes a DN using the provided reader and schema.
   private static DN decode(final String dnString, final SubstringReader reader,
       final Schema schema, final Map<String, DN> cache)
@@ -237,8 +319,6 @@
   // preserve the original whitespace.
   private String stringValue;
 
-  private String normalizedStringValue = null;
-
 
 
   // Private constructor.
@@ -343,87 +423,6 @@
 
 
   /**
-   * Compares the provided DN values to determine their relative order in a
-   * sorted list.
-   *
-   * @param dn1
-   *          The first DN to be compared. It must not be {@code null}.
-   * @param dn2
-   *          The second DN to be compared. It must not be {@code null}.
-   * @return A negative integer if the first DN should come before the second DN
-   *         in a sorted list, a positive integer if the first DN should come
-   *         after the second DN in a sorted list, or zero if the two DN values
-   *         can be considered equal.
-   */
-  public int compareTo(final DN dn1, final DN dn2)
-  {
-    // Quicly check if we are comparing against root dse.
-    if (dn1.isRootDN())
-    {
-      if (dn2.isRootDN())
-      {
-        // both are equal.
-        return 0;
-      }
-      else
-      {
-        // dn1 comes before dn2.
-        return -1;
-      }
-    }
-
-    if (dn2.isRootDN())
-    {
-      // dn1 comes after dn2.
-      return 1;
-    }
-
-    int dn1Size = dn1.size - 1;
-    int dn2Size = dn2.size - 1;
-    while (dn1Size >= 0 && dn2Size >= 0)
-    {
-      final DN dn1Parent = dn1.parent(dn1Size--);
-      final DN dn2Parent = dn2.parent(dn2Size--);
-      if (dn1Parent.isRootDN())
-      {
-        if (dn2Parent.isRootDN())
-        {
-          break;
-        }
-        return -1;
-      }
-
-      if (dn2Parent.isRootDN())
-      {
-        return 1;
-      }
-
-      final int result = dn1Parent.rdn.compareTo(dn2Parent.rdn);
-      if (result > 0)
-      {
-        return 1;
-      }
-      else if (result < 0)
-      {
-        return -1;
-      }
-    }
-    // What do we have here?
-    if (dn1Size > dn2Size)
-    {
-      return 1;
-    }
-    else if (dn1Size < dn2Size)
-    {
-      return -1;
-    }
-
-    return 0;
-  }
-
-
-
-  /**
    * {@inheritDoc}
    */
   @Override
@@ -435,14 +434,22 @@
     }
     else if (obj instanceof DN)
     {
-      final String s1 = toNormalizedString();
-      final String s2 = ((DN) obj).toNormalizedString();
-      return s1.equals(s2);
+      DN other = (DN)obj;
+      if(size == other.size())
+      {
+        if(size == 0)
+        {
+          return true;
+        }
+
+        if(rdn.equals(other.rdn))
+        {
+          return parent.equals(other.parent);
+        }
+      }
     }
-    else
-    {
-      return false;
-    }
+
+    return false;
   }
 
 
@@ -453,8 +460,14 @@
   @Override
   public int hashCode()
   {
-    final String s = toNormalizedString();
-    return s.hashCode();
+    if (size == 0)
+    {
+      return 0;
+    }
+    else
+    {
+      return 31 * parent.hashCode() + rdn.hashCode();
+    }
   }
 
 
@@ -773,33 +786,6 @@
 
 
   /**
-   * Returns the normalized string representation of this DN.
-   *
-   * @return The normalized string representation of this DN.
-   */
-  public String toNormalizedString()
-  {
-    if (rdn == null)
-    {
-      return "".intern();
-    }
-    if (normalizedStringValue == null)
-    {
-      final StringBuilder builder = new StringBuilder();
-      rdn.toNormalizedString(builder);
-      if (!parent.isRootDN())
-      {
-        builder.append(',');
-        builder.append(parent.toNormalizedString());
-      }
-      normalizedStringValue = builder.toString();
-    }
-    return normalizedStringValue;
-  }
-
-
-
-  /**
    * Returns the RFC 4514 string representation of this DN.
    *
    * @return The RFC 4514 string representation of this DN.
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/RDN.java b/opendj-sdk/sdk/src/org/opends/sdk/RDN.java
index 458965f..149a8e4 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/RDN.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/RDN.java
@@ -413,33 +413,6 @@
 
 
 
-  StringBuilder toNormalizedString(final StringBuilder builder)
-  {
-    final int sz = avas.length;
-    if (sz == 1)
-    {
-      return avas[0].toNormalizedString(builder);
-    }
-    else
-    {
-      // Need to sort the AVAs before comparing.
-      final AVA[] a = new AVA[sz];
-      System.arraycopy(avas, 0, a, 0, sz);
-      Arrays.sort(a);
-      // Normalize the first AVA.
-      a[0].toNormalizedString(builder);
-      for (int i = 1; i < sz; i++)
-      {
-        builder.append('+');
-        a[i].toNormalizedString(builder);
-      }
-
-      return builder;
-    }
-  }
-
-
-
   StringBuilder toString(final StringBuilder builder)
   {
     return builder.append(toString());
diff --git a/opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
index 83ae0ca..eb0a820 100644
--- a/opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -22,17 +22,18 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 package org.opends.sdk.schema;
 
 
 
-import java.util.Arrays;
-import java.util.Comparator;
+import java.util.TreeSet;
+import java.util.Iterator;
 
 import org.opends.sdk.*;
-
+import com.sun.opends.sdk.util.StaticUtils;
+import static com.sun.opends.sdk.util.StaticUtils.getBytes;
 
 
 /**
@@ -42,166 +43,175 @@
 final class DistinguishedNameEqualityMatchingRuleImpl extends
     AbstractMatchingRuleImpl
 {
-  private static final Comparator<AVA> ATV_COMPARATOR = new Comparator<AVA>()
-  {
-    public int compare(final AVA o1, final AVA o2)
-    {
-      return o1.getAttributeType().compareTo(o2.getAttributeType());
-    }
-  };
-
-
-
-  @Override
-  public Assertion getAssertion(final Schema schema, final ByteSequence value)
-      throws DecodeException
-  {
-    DN assertion;
-    try
-    {
-      assertion = DN.valueOf(value.toString(), schema);
-    }
-    catch (final LocalizedIllegalArgumentException e)
-    {
-      throw DecodeException.error(e.getMessageObject());
-    }
-
-    final DN finalAssertion = assertion;
-    return new Assertion()
-    {
-      public ConditionResult matches(final ByteSequence attributeValue)
-      {
-        try
-        {
-          final DN attribute = DN.valueOf(attributeValue.toString(), schema);
-          return matchDNs(finalAssertion, attribute);
-        }
-        catch (final LocalizedIllegalArgumentException e)
-        {
-          return ConditionResult.UNDEFINED;
-        }
-      }
-    };
-  }
-
-
-
+  /**
+   * {@inheritDoc}
+   */
   public ByteString normalizeAttributeValue(final Schema schema,
       final ByteSequence value) throws DecodeException
   {
     try
     {
-      return ByteString.valueOf(DN.valueOf(value.toString(), schema)
-          .toNormalizedString());
+      DN dn = DN.valueOf(value.toString(), schema.nonStrict());
+      StringBuilder builder = new StringBuilder(value.length());
+      return ByteString.valueOf(normalizeDN(builder, dn));
     }
     catch (final LocalizedIllegalArgumentException e)
     {
       throw DecodeException.error(e.getMessageObject());
     }
-  }
-
-
-
-  private ConditionResult matchAVAs(final AVA ava1, final AVA ava2)
-  {
-    final AttributeType type = ava1.getAttributeType();
-
-    if (!type.equals(ava2.getAttributeType()))
+    catch (final Exception e)
     {
-      return ConditionResult.FALSE;
-    }
-
-    final MatchingRule matchingRule = type.getEqualityMatchingRule();
-    if (matchingRule != null)
-    {
-      try
-      {
-        final ByteString nv1 = matchingRule.normalizeAttributeValue(ava1
-            .getAttributeValue());
-        final ByteString nv2 = matchingRule.normalizeAttributeValue(ava2
-            .getAttributeValue());
-        return nv1.equals(nv2) ? ConditionResult.TRUE : ConditionResult.FALSE;
-      }
-      catch (final DecodeException de)
-      {
-        return ConditionResult.UNDEFINED;
-      }
-    }
-
-    return ConditionResult.UNDEFINED;
-  }
-
-
-
-  private ConditionResult matchDNs(final DN dn1, final DN dn2)
-  {
-    final int sz1 = dn1.size();
-    final int sz2 = dn2.size();
-
-    if (sz1 != sz2)
-    {
-      return ConditionResult.FALSE;
-    }
-    else
-    {
-      final RDN rdn1 = dn1.rdn();
-      final RDN rdn2 = dn2.rdn();
-      while (rdn1 != null)
-      {
-        final ConditionResult result = matchRDNs(rdn1, rdn2);
-        if (result != ConditionResult.TRUE)
-        {
-          return result;
-        }
-      }
-      return ConditionResult.TRUE;
+      throw DecodeException.error(LocalizableMessage.raw(e.toString()));
     }
   }
 
-
-
-  private ConditionResult matchRDNs(final RDN rdn1, final RDN rdn2)
+  /**
+   * Returns the normalized string representation of a DN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param dn The DN.
+   * @return The normalized string representation of the provided DN.
+   */
+  private static StringBuilder normalizeDN(final StringBuilder builder,
+                                          final DN dn)
   {
-    final int sz1 = rdn1.size();
-    final int sz2 = rdn2.size();
-
-    if (sz1 != sz2)
+    if(dn.rdn() == null)
     {
-      return ConditionResult.FALSE;
+      return builder;
     }
-    else if (sz1 == 1)
+
+    int i = dn.size() - 1;
+    normalizeRDN(builder, dn.parent(i).rdn());
+    for (i--; i >= 0; i--)
     {
-      return matchAVAs(rdn1.getFirstAVA(), rdn2.getFirstAVA());
+      builder.append('\u0000');
+      normalizeRDN(builder, dn.parent(i).rdn());
+    }
+    return builder;
+  }
+
+  /**
+   * Returns the normalized string representation of a RDN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param rdn The RDN.
+   * @return The normalized string representation of the provided RDN.
+   */
+  private static StringBuilder normalizeRDN(final StringBuilder builder,
+                                           final RDN rdn)
+  {
+    final int sz = rdn.size();
+    if (sz == 1)
+    {
+      return normalizeAVA(builder, rdn.getFirstAVA());
     }
     else
     {
       // Need to sort the AVAs before comparing.
-      final AVA[] a1 = new AVA[sz1];
-      int i = 0;
-      for (final AVA ava : rdn1)
+      TreeSet<AVA> a = new TreeSet<AVA>();
+      for(AVA ava : rdn)
       {
-        a1[i++] = ava;
+        a.add(ava);
       }
-      Arrays.sort(a1, ATV_COMPARATOR);
-
-      final AVA[] a2 = new AVA[sz1];
-      i = 0;
-      for (final AVA ava : rdn2)
+      Iterator<AVA> i = a.iterator();
+      // Normalize the first AVA.
+      normalizeAVA(builder, i.next());
+      while(i.hasNext())
       {
-        a2[i++] = ava;
+        builder.append('\u0001');
+        normalizeAVA(builder, i.next());
       }
-      Arrays.sort(a2, ATV_COMPARATOR);
 
-      for (i = 0; i < sz1; i++)
+      return builder;
+    }
+  }
+
+  /**
+   * Returns the normalized string representation of an AVA.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param ava The AVA.
+   * @return The normalized string representation of the provided AVA.
+   */
+  private static StringBuilder normalizeAVA(final StringBuilder builder,
+                                           final AVA ava)
+  {
+    ByteString value = ava.getAttributeValue();
+    final MatchingRule matchingRule =
+        ava.getAttributeType().getEqualityMatchingRule();
+    if (matchingRule != null)
+    {
+      try
       {
-        final ConditionResult result = matchAVAs(a1[i], a2[i]);
-        if (result != ConditionResult.TRUE)
+        value =
+            matchingRule.normalizeAttributeValue(ava.getAttributeValue());
+      }
+      catch (final DecodeException de)
+      {
+        // Ignore - we'll drop back to the user provided value.
+      }
+    }
+
+    if (!ava.getAttributeType().getNames().iterator().hasNext())
+    {
+      builder.append(ava.getAttributeType().getOID());
+      builder.append("=#");
+      StaticUtils.toHex(value, builder);
+    }
+    else
+    {
+      final String name = ava.getAttributeType().getNameOrOID();
+      // Normalizing.
+      StaticUtils.toLowerCase(name, builder);
+
+      builder.append("=");
+
+      final Syntax syntax = ava.getAttributeType().getSyntax();
+      if (!syntax.isHumanReadable())
+      {
+        builder.append("#");
+        StaticUtils.toHex(value, builder);
+      }
+      else
+      {
+        final String str = value.toString();
+        if (str.length() == 0)
         {
-          return result;
+          return builder;
+        }
+        char c = str.charAt(0);
+        int startPos = 0;
+        if ((c == ' ') || (c == '#'))
+        {
+          builder.append('\\');
+          builder.append(c);
+          startPos = 1;
+        }
+        final int length = str.length();
+        for (int si = startPos; si < length; si++)
+        {
+          c = str.charAt(si);
+          if (c < ' ')
+          {
+            for (final byte b : getBytes(String.valueOf(c)))
+            {
+              builder.append('\\');
+              builder.append(StaticUtils.byteToLowerHex(b));
+            }
+          }
+          else
+          {
+            if ((c == ' ' && si == length - 1)
+                || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
+                    || c == '=' || c == '>' || c == '\\' || c == '\u0000'))
+            {
+              builder.append('\\');
+            }
+            builder.append(c);
+          }
         }
       }
-
-      return ConditionResult.TRUE;
     }
+    return builder;
   }
 }
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/DNTestCase.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/DNTestCase.java
index 81437a2..f4a7509 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/DNTestCase.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/DNTestCase.java
@@ -486,7 +486,6 @@
     assertEquals(c, e);
     assertEquals(c.hashCode(), e.hashCode());
 
-    assertEquals(c.toNormalizedString(), e.toNormalizedString());
     assertEquals(c.toString(), e.toString());
 
     assertEquals(c.rdn(), RDN.valueOf("dc=foo"));
@@ -799,7 +798,6 @@
     assertEquals(p, e);
     assertEquals(p.hashCode(), e.hashCode());
 
-    assertEquals(p.toNormalizedString(), e.toNormalizedString());
     assertEquals(p.toString(), e.toString());
 
     assertEquals(p.rdn(), RDN.valueOf("dc=bar"));
@@ -885,7 +883,6 @@
     final DN nullDN = DN.rootDN();
     assertTrue(nullDN.isRootDN());
     assertTrue(nullDN.size() == 0);
-    assertEquals(nullDN.toNormalizedString(), "");
   }
 
 
@@ -936,21 +933,6 @@
 
 
   /**
-   * Tests the toNoramlizedString methods.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testToNormalizedString() throws Exception
-  {
-    final DN dn = DN.valueOf("dc=example,dc=com");
-    assertEquals(dn.toNormalizedString(), "dc=example,dc=com");
-  }
-
-
-
-  /**
    * Test the RFC 4514 string representation of the DN.
    *
    * @param rawDN
@@ -988,10 +970,8 @@
   public void testValueOfString(final String rawDN, final String normDN,
       final String stringDN) throws Exception
   {
-    final DN dn = DN.valueOf(rawDN);
-    final StringBuilder buffer = new StringBuilder();
-    buffer.append(normDN);
-    Platform.normalize(buffer);
-    assertEquals(dn.toNormalizedString(), buffer.toString());
+    final DN raw = DN.valueOf(rawDN);
+    final DN string = DN.valueOf(stringDN);
+    assertEquals(raw, string);
   }
 }
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/RDNTestCase.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/RDNTestCase.java
index 584fbfb..f889e46 100644
--- a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/RDNTestCase.java
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/RDNTestCase.java
@@ -325,12 +325,8 @@
       final String stringRDN) throws Exception
   {
     final RDN rdn = RDN.valueOf(rawRDN);
-    final StringBuilder buffer = new StringBuilder();
-    buffer.append(normRDN);
-    Platform.normalize(buffer);
-    final StringBuilder normalBuffer = new StringBuilder();
-    rdn.toNormalizedString(normalBuffer);
-    assertEquals(normalBuffer.toString(), buffer.toString());
+    final RDN string = RDN.valueOf(stringRDN);
+    assertEquals(rdn, string);
   }
 
 
diff --git a/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java
new file mode 100644
index 0000000..d2054d4
--- /dev/null
+++ b/opendj-sdk/sdk/tests/unit-tests-testng/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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 2009-2010 Sun Microsystems, Inc.
+ */
+
+package org.opends.sdk.schema;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
+import org.opends.sdk.ConditionResult;
+import org.opends.sdk.ByteString;
+import static org.opends.sdk.schema.SchemaConstants.EMR_DN_OID;
+import com.sun.opends.sdk.util.Platform;
+
+/**
+ * Test the DistinguishedNameEqualityMatchingRule
+ */
+public class DistinguishedNameEqualityMatchingRuleTest extends MatchingRuleTest
+{
+  @DataProvider(name = "matchingRuleInvalidAttributeValues")
+  public Object[][] createMatchingRuleInvalidAttributeValues()
+  {
+    return new Object[][] { { "manager" }, { "manager " }, { "=Jim" },
+        { " =Jim" }, { "= Jim" },
+        { " = Jim" },
+        { "cn+Jim" },
+        { "cn + Jim" },
+        { "cn=Jim+" },
+        { "cn=Jim+manager" },
+        { "cn=Jim+manager " },
+        { "cn=Jim+manager," },// { "cn=Jim," }, { "cn=Jim,  " }, { "c[n]=Jim" },
+        { "_cn=Jim" }, { "c_n=Jim" }, { "cn\"=Jim" }, { "c\"n=Jim" },
+        { "1cn=Jim" }, { "cn+uid=Jim" }, { "-cn=Jim" }, { "/tmp=a" },
+        { "\\tmp=a" }, { "cn;lang-en=Jim" }, { "@cn=Jim" },
+        { "_name_=Jim" },
+        { "\u03c0=pi" },
+        { "v1.0=buggy" },// { "1.=buggy" }, { ".1=buggy" },
+        { "oid.1." }, { "1.3.6.1.4.1.1466..0=#04024869" }, { "cn=#a" },
+        { "cn=#ag" }, { "cn=#ga" }, { "cn=#abcdefgh" },
+        { "cn=a\\b" }, // { "cn=a\\bg" }, { "cn=\"hello" },
+        { "cn=+mail=,dc=example,dc=com" }, { "cn=xyz+sn=,dc=example,dc=com" },
+        { "cn=,dc=example,dc=com" } };
+  }
+
+  @DataProvider(name = "matchingrules")
+  public Object[][] createMatchingRuleTest()
+  {
+    return new Object[][] {
+        { "", "", ConditionResult.TRUE },
+        { "   ", "", ConditionResult.TRUE },
+        { "cn=", "cn=", ConditionResult.TRUE },
+        { "cn= ", "cn=", ConditionResult.TRUE },
+        { "cn =", "cn=", ConditionResult.TRUE },
+        { "cn = ", "cn=", ConditionResult.TRUE },
+        { "dc=com", "dc=com", ConditionResult.TRUE },
+        { "dc=com+o=com", "dc=com+o=com", ConditionResult.TRUE },
+        { "DC=COM", "dc=com", ConditionResult.TRUE },
+        { "dc = com", "dc=com", ConditionResult.TRUE },
+        { " dc = com ", "dc=com", ConditionResult.TRUE },
+        { "dc=example,dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc=example, dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc=example ,dc=com", "dc=example,dc=com", ConditionResult.TRUE },
+        { "dc =example , dc  =   com", "dc=example,dc=com",
+          ConditionResult.TRUE },
+        { "givenName=John+cn=Doe,ou=People,dc=example,dc=com",
+            "cn=doe+givenname=john,ou=people,dc=example,dc=com",
+            ConditionResult.TRUE },
+        { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com",
+            "givenname=john\\+cn\\=doe,ou=people,dc=example,dc=com",
+            ConditionResult.TRUE },
+        { "cn=Doe\\, John,ou=People,dc=example,dc=com",
+            "cn=doe\\, john,ou=people,dc=example,dc=com", ConditionResult.TRUE },
+        { "UID=jsmith,DC=example,DC=net", "uid=jsmith,dc=example,dc=net",
+          ConditionResult.TRUE },
+        { "OU=Sales+CN=J. Smith,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE },
+        { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
+            "cn=james \\\"jim\\\" smith\\, iii,dc=example,dc=net",
+            ConditionResult.TRUE },
+        { "CN=John Smith\\2C III,DC=example,DC=net",
+            "cn=john smith\\, iii,dc=example,dc=net", ConditionResult.TRUE },
+        { "CN=\\23John Smith\\20,DC=example,DC=net",
+            "cn=\\#john smith,dc=example,dc=net", ConditionResult.TRUE },
+        {
+            "CN=Before\\0dAfter,DC=example,DC=net",
+            // \0d is a hex representation of Carriage return. It is mapped
+            // to a SPACE as defined in the MAP ( RFC 4518)
+            "cn=before after,dc=example,dc=net", ConditionResult.TRUE },
+        { "2.5.4.3=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi", ConditionResult.TRUE },
+        { "1.1.1=", "1.1.1=", ConditionResult.TRUE },
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107",
+          ConditionResult.TRUE },
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius",
+            "ou=\u55b6\u696d\u90e8,o=airius", ConditionResult.TRUE },
+        { "photo=\\ john \\ ,dc=com", "photo=\\ john \\ ,dc=com",
+          ConditionResult.TRUE },
+        { "AB-global=", "ab-global=", ConditionResult.TRUE },
+        { "OU= Sales + CN = J. Smith ,DC=example,DC=net",
+            "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE },
+        { "cn=John+a=Doe", "a=Doe+cn=john", ConditionResult.TRUE },
+        { "O=\"Sue, Grabbit and Runn\",C=US", "o=sue\\, grabbit and runn,c=us",
+          ConditionResult.TRUE }, };
+  }
+
+   /**
+   * DN test data provider.
+   *
+   * @return The array of test DN strings.
+   */
+  @DataProvider(name = "testDNs")
+  public Object[][] createData()
+  {
+    return new Object[][] {
+        { "", ""},
+        { "   ", ""},
+        { "cn=", "cn="},
+        { "cn= ", "cn="},
+        { "cn =", "cn="},
+        { "cn = ", "cn="},
+        { "dc=com", "dc=com"},
+        { "dc=com+o=com", "dc=com\u0001o=com"},
+        { "DC=COM", "dc=com"},
+        { "dc = com", "dc=com"},
+        { " dc = com ", "dc=com"},
+        { "dc=example,dc=com", "dc=com\u0000dc=example"},
+        { "dc=example, dc=com", "dc=com\u0000dc=example"},
+        { "dc=example ,dc=com", "dc=com\u0000dc=example"},
+        { "dc =example , dc  =   com", "dc=com\u0000dc=example"},
+        { "givenName=John+cn=Doe,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\u0001givenname=john"},
+        { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000givenname=john\\+cn\\=doe"},
+        { "cn=Doe\\, John,ou=People,dc=example,dc=com",
+            "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\\, john"},
+        { "UID=jsmith,DC=example,DC=net", "dc=net\u0000dc=example\u0000uid=jsmith"},
+        { "OU=Sales+CN=J. Smith,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"},
+        { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=james \\\"jim\\\" smith\\, iii"},
+        { "CN=John Smith\\2C III,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=john smith\\, iii"},
+        { "CN=\\23John Smith\\20,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=\\#john smith"},
+        {
+            "CN=Before\\0dAfter,DC=example,DC=net",
+            // \0d is a hex representation of Carriage return. It is mapped
+            // to a SPACE as defined in the MAP ( RFC 4518)
+            "dc=net\u0000dc=example\u0000cn=before after"},
+        { "2.5.4.3=#04024869",
+        // Unicode codepoints from 0000-0008 are mapped to nothing.
+            "cn=hi"},
+        { "1.1.1=", "1.1.1="},
+        { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107"},
+        { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius",
+            "o=airius\u0000ou=\u55b6\u696d\u90e8"},
+        { "photo=\\ john \\ ,dc=com", "dc=com\u0000photo=\\ john \\ "},
+        { "AB-global=", "ab-global="},
+        { "OU= Sales + CN = J. Smith ,DC=example,DC=net",
+            "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"},
+        { "cn=John+a=", "a=\u0001cn=john"},
+        { "O=\"Sue, Grabbit and Runn\",C=US",
+          "c=us\u0000o=sue\\, grabbit and runn" }, };
+  }
+
+  protected MatchingRule getRule()
+  {
+    return Schema.getCoreSchema().getMatchingRule(EMR_DN_OID);
+  }
+
+
+  /**
+   * Test the normalized values
+   */
+  @Test(dataProvider = "testDNs")
+  public void matchingRules(final String value1, final String value2)
+      throws Exception
+  {
+    final MatchingRule rule = getRule();
+
+    final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString
+        .valueOf(value1));
+    StringBuilder buffer = new StringBuilder(value2);
+    Platform.normalize(buffer);
+    final ByteString expectedValue = ByteString.valueOf(buffer);
+    assertEquals(normalizedValue1, expectedValue);
+  }
+}

--
Gitblit v1.10.0