From e7796c7cc4a2da1e22d62d21b4189e1f7e50b672 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 23 Feb 2007 19:42:02 +0000
Subject: [PATCH] Add a new org.opends.server.interop package where we can place source code that we don't need in the core server but can help other applications interoperate with OpenDS.

---
 opends/src/server/org/opends/server/types/DN.java                                        |   10 
 opends/src/server/org/opends/server/interop/LazyDN.java                                  |  380 ++++++++++++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/interop/InteropTestCase.java |   46 ++
 opends/src/server/org/opends/server/interop/package-info.java                            |   38 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/interop/LazyDNTestCase.java  |  785 +++++++++++++++++++++++++++++++++++++
 5 files changed, 1,259 insertions(+), 0 deletions(-)

diff --git a/opends/src/server/org/opends/server/interop/LazyDN.java b/opends/src/server/org/opends/server/interop/LazyDN.java
new file mode 100644
index 0000000..2af7b5a
--- /dev/null
+++ b/opends/src/server/org/opends/server/interop/LazyDN.java
@@ -0,0 +1,380 @@
+/*
+ * 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
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.interop;
+
+
+
+import org.opends.server.types.DN;
+import org.opends.server.types.RDN;
+
+import static org.opends.server.loggers.Debug.*;
+import static org.opends.server.util.StaticUtils.*;
+
+
+
+/**
+ * This class provides an implementation of a {@code DN} which is lazily
+ * initialized.  It may be created using only a string representation and no
+ * decoding will be performed as long as only the string representation is
+ * accessed.  If any methods are called which require the decoded DN, this class
+ * will attempt to decode the DN string as a DN and then invoke the
+ * corresponding method on the decoded version.  If any error occurs while
+ * trying to decode the provided string as a DN, then a {@code RuntimeException}
+ * will be thrown.
+ * <BR><BR>
+ * Note that this implementation is only intended for use in cases in which the
+ * DN is only needed as a string representation (in particular, only the
+ * {@code toString} methods will be used).  For cases in which any other methods
+ * will need to be invoked on the object, the {@code org.opends.server.types.DN}
+ * class should be used instead.
+ */
+public class LazyDN
+       extends DN
+{
+  /**
+   * The fully-qualified name of this class for debugging purposes.
+   */
+  private static final String CLASS_NAME = "org.opends.server.interop.LazyDN";
+
+
+
+  /**
+   * The serial version identifier required to satisfy the compiler because this
+   * class implements the {@code java.io.Serializable} interface.  This value
+   * was generated using the {@code serialver} command-line utility included
+   * with the Java SDK.
+   */
+  private static final long serialVersionUID = -7461952029886247893L;
+
+
+
+  // The decoded form of this DN.
+  private DN decodedDN;
+
+  // The string representation of this DN.
+  private String dnString;
+
+
+
+  /**
+   * Creates a new lazily-initialized DN with the provided string
+   * representation.
+   *
+   * @param  dnString  The string representation to use for this
+   *                   lazily-initialized DN.
+   */
+  public LazyDN(String dnString)
+  {
+    assert debugConstructor(CLASS_NAME, String.valueOf(dnString));
+
+    this.dnString  = dnString;
+    this.decodedDN = null;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean isNullDN()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "isNullDN");
+
+    return getDecodedDN().isNullDN();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public int getNumComponents()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getNumComponents");
+
+    return getDecodedDN().getNumComponents();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public RDN getRDN()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getRDN");
+
+    return getDecodedDN().getRDN();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public RDN getRDN(int pos)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getRDN", String.valueOf(pos));
+
+    return getDecodedDN().getRDN(pos);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public DN getParent()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getParent");
+
+    return getDecodedDN().getParent();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public DN getParentDNInSuffix()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getParentDNInSuffix");
+
+    return getDecodedDN().getParentDNInSuffix();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public DN concat(RDN rdn)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "concat", String.valueOf(rdn));
+
+    return getDecodedDN().concat(rdn);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public DN concat(RDN[] rdnComponents)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "concat", String.valueOf(rdnComponents));
+
+    return getDecodedDN().concat(rdnComponents);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public DN concat(DN relativeBaseDN)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "concat", String.valueOf(relativeBaseDN));
+
+    return getDecodedDN().concat(relativeBaseDN);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean isDescendantOf(DN dn)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "isDescendantOf", String.valueOf(dn));
+
+    return getDecodedDN().isDescendantOf(dn);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean isAncestorOf(DN dn)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "isAncestorOf", String.valueOf(dn));
+
+    return getDecodedDN().isAncestorOf(dn);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean equals(Object o)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "equals", String.valueOf(o));
+
+    return getDecodedDN().equals(o);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public int hashCode()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "hashCode");
+
+    return getDecodedDN().hashCode();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public String toString()
+  {
+    assert debugEnter(CLASS_NAME, "toString");
+
+    return dnString;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void toString(StringBuilder buffer)
+  {
+    assert debugEnter(CLASS_NAME, "toString", "java.lang.StringBuilder");
+
+    buffer.append(dnString);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public String toNormalizedString()
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "toNormalizedString");
+
+    return getDecodedDN().toNormalizedString();
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void toNormalizedString(StringBuilder buffer)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "toNormalizedString",
+                      "java.lang.StringBuilder");
+
+    getDecodedDN().toNormalizedString(buffer);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public int compareTo(DN dn)
+         throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "compareTo", String.valueOf(dn));
+
+    return getDecodedDN().compareTo(dn);
+  }
+
+
+
+  /**
+   * Retrieves a {@code DN} object that is decoded from the string
+   * representation.
+   *
+   * @throws  RuntimeException  If an error occurs while attempting to decode
+   *                            the DN string as a DN.
+   */
+  private DN getDecodedDN()
+          throws RuntimeException
+  {
+    assert debugEnter(CLASS_NAME, "getDecodedDN");
+
+    if (decodedDN == null)
+    {
+      try
+      {
+        decodedDN = DN.decode(dnString);
+      }
+      catch (Exception e)
+      {
+        assert debugException(CLASS_NAME, "getDecodedDN", e);
+
+        throw new RuntimeException(stackTraceToSingleLineString(e));
+      }
+    }
+
+    return decodedDN;
+  }
+}
+
diff --git a/opends/src/server/org/opends/server/interop/package-info.java b/opends/src/server/org/opends/server/interop/package-info.java
new file mode 100644
index 0000000..b57fa70
--- /dev/null
+++ b/opends/src/server/org/opends/server/interop/package-info.java
@@ -0,0 +1,38 @@
+/*
+ * 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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+
+
+/**
+ * This package is intended to hold classes which may be used to help OpenDS
+ * integrate with or interoperate with other applications.  In general, classes
+ * within this package are not intended for general-purpose use, and individuals
+ * or projects that wish to use them are encouraged to check with the OpenDS
+ * developers first to ensure that they are suitable for the intended purpose.
+ */
+package org.opends.server.interop;
+
diff --git a/opends/src/server/org/opends/server/types/DN.java b/opends/src/server/org/opends/server/types/DN.java
index c6d3aae..e860873 100644
--- a/opends/src/server/org/opends/server/types/DN.java
+++ b/opends/src/server/org/opends/server/types/DN.java
@@ -28,6 +28,16 @@
 
 
 
+/********************
+ * NOTE:  Any changes to the set of public methods defined in this
+ *        class or the arguments that they contain must also be made
+ *        in the org.opends.server.interop.LazyDN package to ensure
+ *        continued interoperability with third-party applications
+ *        that rely on that functionality.
+ ********************/
+
+
+
 import java.io.Serializable;
 import java.util.ArrayList;
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/InteropTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/InteropTestCase.java
new file mode 100644
index 0000000..a39a01e
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/InteropTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.interop;
+
+
+
+import org.testng.annotations.Test;
+
+import org.opends.server.DirectoryServerTestCase;
+
+
+
+/**
+ * An abstract base class for all test cases covering interoperability classes.
+ */
+@Test(groups = { "precommit", "interop" })
+public abstract class InteropTestCase
+       extends DirectoryServerTestCase
+{
+  // No implementation required.
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/LazyDNTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/LazyDNTestCase.java
new file mode 100644
index 0000000..02a3437
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/interop/LazyDNTestCase.java
@@ -0,0 +1,785 @@
+/*
+ * 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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.interop;
+
+
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.types.DN;
+import org.opends.server.types.RDN;
+
+import static org.testng.Assert.*;
+
+import static org.opends.server.util.ServerConstants.*;
+
+
+
+/**
+ * This class is used to ensure that the LazyDN class provides parity with the
+ * DN class, and that the set of public members for the DN class have not
+ * changed unexpectedly.
+ */
+public class LazyDNTestCase
+       extends InteropTestCase
+{
+  /**
+   * Make sure that the Directory Server is running so we have access to schema
+   * information and other necessary facilities.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer()
+         throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  /**
+   * Ensures that the public methods exposed in the DN class have not changed in
+   * an unexpected way that could adversely impact the LazyDN class.
+   */
+  @Test()
+  public void testDNPublicMethods()
+  {
+    // Create a set of string arrays containing the signatures of all non-static
+    // public and protected methods in the DN class.  The first element should
+    // be the method name.  The second element should be the return type.  The
+    // remaining elements should be the types of the arguments.
+    LinkedList<String[]> sigs = new LinkedList<String[]>();
+    sigs.add(new String[] { "isNullDN",
+                            "boolean" });
+    sigs.add(new String[] { "getNumComponents",
+                            "int" });
+    sigs.add(new String[] { "getRDN",
+                            "org.opends.server.types.RDN" });
+    sigs.add(new String[] { "getRDN",
+                            "org.opends.server.types.RDN",
+                            "int" });
+    sigs.add(new String[] { "getParent",
+                            "org.opends.server.types.DN" });
+    sigs.add(new String[] { "getParentDNInSuffix",
+                            "org.opends.server.types.DN" });
+    sigs.add(new String[] { "concat",
+                            "org.opends.server.types.DN",
+                            "org.opends.server.types.RDN" });
+    sigs.add(new String[] { "concat",
+                            "org.opends.server.types.DN",
+                            "[Lorg.opends.server.types.RDN;" });
+    sigs.add(new String[] { "concat",
+                            "org.opends.server.types.DN",
+                            "org.opends.server.types.DN" });
+    sigs.add(new String[] { "isDescendantOf",
+                            "boolean",
+                            "org.opends.server.types.DN" });
+    sigs.add(new String[] { "isAncestorOf",
+                            "boolean",
+                            "org.opends.server.types.DN" });
+    sigs.add(new String[] { "equals",
+                            "boolean",
+                            "java.lang.Object" });
+    sigs.add(new String[] { "hashCode",
+                            "int" });
+    sigs.add(new String[] { "toString",
+                            "java.lang.String" });
+    sigs.add(new String[] { "toString",
+                            "void",
+                            "java.lang.StringBuilder" });
+    sigs.add(new String[] { "toNormalizedString",
+                            "java.lang.String" });
+    sigs.add(new String[] { "toNormalizedString",
+                            "void",
+                            "java.lang.StringBuilder" });
+    sigs.add(new String[] { "compareTo",
+                            "int",
+                            "org.opends.server.types.DN" });
+
+    // This one is a little weird, but we need it because of the way that
+    // generics works.
+    sigs.add(new String[] { "compareTo",
+                            "int",
+                            "java.lang.Object" });
+
+
+    // Iterate through all the methods in the DN class and try to find the
+    // corresponding signature in the list.
+    LinkedList<String[]> unexpectedMethods = new LinkedList<String[]>();
+    Method[] superclassMethods = DN.class.getSuperclass().getMethods();
+methodLoop:
+    for (Method m : DN.class.getMethods())
+    {
+      // If the method is not "public" or "protected", then we don't care about
+      // it.
+      int modifiers = m.getModifiers();
+      if (! (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)))
+      {
+        continue;
+      }
+
+      // If the method is "static", then we don't care about it.
+      if (Modifier.isStatic(modifiers))
+      {
+        continue;
+      }
+
+      // If the method was also defined in the superclass, then we don't care
+      // about it unless it was the "toString" method because that is important.
+      for (Method superclassMethod : superclassMethods)
+      {
+        if (m.equals(superclassMethod))
+        {
+          continue methodLoop;
+        }
+      }
+
+
+      // Create an array containing the elements of the method signature and see
+      // if it's present in the set.
+      LinkedList<String> signatureElements = new LinkedList<String>();
+      signatureElements.add(m.getName());
+      signatureElements.add(m.getReturnType().getName());
+      for (Class c : m.getParameterTypes())
+      {
+        signatureElements.add(c.getName());
+      }
+
+      String[] signatureArray = new String[signatureElements.size()];
+      signatureElements.toArray(signatureArray);
+
+      boolean found = false;
+      Iterator<String[]> iterator = sigs.iterator();
+      while (iterator.hasNext())
+      {
+        String[] sigArray = iterator.next();
+        if (Arrays.equals(signatureArray, sigArray))
+        {
+          iterator.remove();
+          found = true;
+          break;
+        }
+      }
+
+      if (! found)
+      {
+        unexpectedMethods.add(signatureArray);
+      }
+    }
+
+
+    // If there were any unexpected methods found, or if there were any expected
+    // methods not found, then fail.
+    if (! (unexpectedMethods.isEmpty() && sigs.isEmpty()))
+    {
+      StringBuilder buffer = new StringBuilder();
+      if (! unexpectedMethods.isEmpty())
+      {
+        buffer.append("Unexpected methods found in the DN class:" + EOL);
+        for (String[] sig : unexpectedMethods)
+        {
+          buffer.append("     ");
+          buffer.append(sig[1]);
+          buffer.append(" ");
+          buffer.append(sig[0]);
+          buffer.append("(");
+          for (int i=2; i < sig.length; i++)
+          {
+            if (i > 2)
+            {
+              buffer.append(", ");
+            }
+
+            buffer.append(sig[i]);
+          }
+          buffer.append(")" + EOL);
+        }
+      }
+
+      if (! sigs.isEmpty())
+      {
+        buffer.append("Expected methods not found in the DN class:" + EOL);
+        for (String[] sig : sigs)
+        {
+          buffer.append("     ");
+          buffer.append(sig[1]);
+          buffer.append(" ");
+          buffer.append(sig[0]);
+          buffer.append("(");
+          for (int i=2; i < sig.length; i++)
+          {
+            if (i > 2)
+            {
+              buffer.append(", ");
+            }
+
+            buffer.append(sig[i]);
+          }
+          buffer.append(")" + EOL);
+        }
+      }
+
+      buffer.append("If these changes to the DN public API were intentional, " +
+                    "then update the LazyDNTestCase.testDNPublicMethods " +
+                    "method to reflect the new API.  Also make sure that "+
+                    "the LazyDN method has been updated to reflect the " +
+                    "change as well.");
+
+      fail(buffer.toString());
+    }
+  }
+
+
+
+  /**
+   * Tests the {@code isNullDN} method with valid DN strings.
+   */
+  @Test()
+  public void testIsNullDN()
+  {
+    assertTrue(new LazyDN("").isNullDN());
+    assertFalse(new LazyDN("dc=example,dc=com").isNullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code isNullDN} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testIsNullDNInvalid()
+  {
+    new LazyDN("invalid").isNullDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getNumComponents} method with valid DN strings.
+   */
+  @Test()
+  public void testGetNumComponents()
+  {
+    assertEquals(new LazyDN("").getNumComponents(), 0);
+    assertEquals(new LazyDN("dc=example,dc=com").getNumComponents(), 2);
+  }
+
+
+
+  /**
+   * Tests the {@code getNumComponents} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testGetNumComponentsInvalid()
+  {
+    new LazyDN("invalid").getNumComponents();
+  }
+
+
+
+  /**
+   * Tests the first {@code getRDN} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetRDN1()
+         throws Exception
+  {
+    assertNull(new LazyDN("").getRDN());
+    assertEquals(new LazyDN("dc=example,dc=com").getRDN(),
+                 RDN.decode("dc=example"));
+  }
+
+
+
+  /**
+   * Tests the first {@code getRDN} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testGetRDN1Invalid()
+  {
+    new LazyDN("invalid").getRDN();
+  }
+
+
+
+  /**
+   * Tests the second {@code getRDN} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetRDN2()
+         throws Exception
+  {
+    assertEquals(new LazyDN("dc=example,dc=com").getRDN(1),
+                 RDN.decode("dc=com"));
+  }
+
+
+
+  /**
+   * Tests the second {@code getRDN} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testGetRDN2Invalid()
+  {
+    new LazyDN("invalid").getRDN(1);
+  }
+
+
+
+  /**
+   * Tests the {@code getParent} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetParent()
+         throws Exception
+  {
+    assertNull(new LazyDN("").getParent());
+    assertEquals(new LazyDN("dc=example,dc=com").getParent(),
+                 DN.decode("dc=com"));
+  }
+
+
+
+  /**
+   * Tests the {@code getParent} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testGetParentInvalid()
+  {
+    new LazyDN("invalid").getParent();
+  }
+
+
+
+  /**
+   * Tests the {@code getParentDNInSuffix} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetParentDNInSuffix()
+         throws Exception
+  {
+    assertNull(new LazyDN("").getParentDNInSuffix());
+    assertNull(new LazyDN("dc=example,dc=com").getParentDNInSuffix());
+    assertEquals(
+         new LazyDN("ou=People,dc=example,dc=com").getParentDNInSuffix(),
+         DN.decode("dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the {@code getParentDNInSuffix} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testGetParentDNInSuffixInvalid()
+  {
+    new LazyDN("invalid").getParentDNInSuffix();
+  }
+
+
+
+  /**
+   * Tests the first {@code concat} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testConcat1()
+         throws Exception
+  {
+    assertEquals(new LazyDN("").concat(RDN.decode("dc=com")),
+                 DN.decode("dc=com"));
+    assertEquals(
+         new LazyDN("dc=example,dc=com").concat(RDN.decode("ou=People")),
+         DN.decode("ou=People,dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the first {@code concat} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testConcat1Invalid()
+         throws Exception
+  {
+    new LazyDN("invalid").concat(RDN.decode("dc=com"));
+  }
+
+
+
+  /**
+   * Tests the second {@code concat} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testConcat2()
+         throws Exception
+  {
+    RDN[] rdnArray = { RDN.decode("dc=example"), RDN.decode("dc=com") };
+
+    assertEquals(new LazyDN("").concat(rdnArray),
+                 DN.decode("dc=example,dc=com"));
+    assertEquals(new LazyDN("dc=example,dc=com").concat(rdnArray),
+                 DN.decode("dc=example,dc=com,dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the second {@code concat} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testConcat2Invalid()
+         throws Exception
+  {
+    RDN[] rdnArray = { RDN.decode("dc=example"), RDN.decode("dc=com") };
+
+    new LazyDN("invalid").concat(rdnArray);
+  }
+
+
+
+  /**
+   * Tests the third {@code concat} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testConcat3()
+         throws Exception
+  {
+    assertEquals(new LazyDN("").concat(DN.decode("dc=example,dc=com")),
+                 DN.decode("dc=example,dc=com"));
+    assertEquals(new LazyDN("dc=example,dc=com").concat(DN.decode("ou=People")),
+                 DN.decode("ou=People,dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the third {@code concat} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testConcat3Invalid()
+         throws Exception
+  {
+    new LazyDN("invalid").concat(DN.decode("ou=People"));
+  }
+
+
+
+  /**
+   * Tests the {@code isDescendantOf} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testIsDescendantOf()
+         throws Exception
+  {
+    assertFalse(new LazyDN("").isDescendantOf(DN.decode("dc=example,dc=com")));
+    assertTrue(new LazyDN("ou=People,dc=example,dc=com").isDescendantOf(
+                    DN.decode("dc=example,dc=com")));
+  }
+
+
+
+  /**
+   * Tests the {@code isDescendantOf} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testIsDescendantOfInvalid()
+         throws Exception
+  {
+    new LazyDN("invalid").isDescendantOf(DN.decode("dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the {@code isAncestorOf} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testIsAncestorOf()
+         throws Exception
+  {
+    assertTrue(new LazyDN("").isAncestorOf(DN.decode("dc=example,dc=com")));
+    assertTrue(new LazyDN("dc=example,dc=com").isAncestorOf(
+                    DN.decode("ou=People,dc=example,dc=com")));
+  }
+
+
+
+  /**
+   * Tests the {@code isAncestorOf} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testIsAncestorOfInvalid()
+         throws Exception
+  {
+    new LazyDN("invalid").isAncestorOf(DN.decode("dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the {@code equals} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testEquals()
+         throws Exception
+  {
+    assertTrue(new LazyDN("").equals(DN.nullDN()));
+    assertTrue(new LazyDN("dc=example,dc=com").equals(
+                    DN.decode("dc=example,dc=com")));
+  }
+
+
+
+  /**
+   * Tests the {@code equals} method with an invalid DN string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testEqualsInvalid()
+         throws Exception
+  {
+    new LazyDN("invalid").equals(DN.decode("dc=example,dc=com"));
+  }
+
+
+
+  /**
+   * Tests the {@code hashCode} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testHashCode()
+         throws Exception
+  {
+    assertEquals(new LazyDN("").hashCode(), DN.nullDN().hashCode());
+    assertEquals(new LazyDN("dc=example,dc=com").hashCode(),
+                 DN.decode("dc=example,dc=com").hashCode());
+  }
+
+
+
+  /**
+   * Tests the {@code hashCode} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testHashCodeInvalid()
+  {
+    new LazyDN("invalid").hashCode();
+  }
+
+
+
+  /**
+   * Tests the first {@code toString} method with valid DN strings.
+   */
+  @Test()
+  public void testToString1()
+  {
+    assertEquals(new LazyDN("").toString(), "");
+    assertEquals(new LazyDN("dc=example,dc=com").toString(),
+                 "dc=example,dc=com");
+    assertEquals(new LazyDN("ou=People, dc=example, dc=com").toString(),
+                 "ou=People, dc=example, dc=com");
+  }
+
+
+
+  /**
+   * Tests the first {@code toString} method with an invalid DN string.
+   */
+  @Test()
+  public void testToString1Invalid()
+  {
+    assertEquals(new LazyDN("invalid").toString(), "invalid");
+  }
+
+
+
+  /**
+   * Tests the second {@code toString} method with valid DN strings.
+   */
+  @Test()
+  public void testToString2()
+  {
+    StringBuilder buffer = new StringBuilder();
+    new LazyDN("").toString(buffer);
+    assertEquals(buffer.toString(), "");
+
+    buffer = new StringBuilder();
+    new LazyDN("dc=example,dc=com").toString(buffer);
+    assertEquals(buffer.toString(), "dc=example,dc=com");
+
+    buffer = new StringBuilder();
+    new LazyDN("ou=People, dc=example, dc=com").toString(buffer);
+    assertEquals(buffer.toString(), "ou=People, dc=example, dc=com");
+  }
+
+
+
+  /**
+   * Tests the second {@code toString} method with an invalid DN string.
+   */
+  @Test()
+  public void testToString2Invalid()
+  {
+    StringBuilder buffer = new StringBuilder();
+    new LazyDN("invalid").toString(buffer);
+    assertEquals(buffer.toString(), "invalid");
+  }
+
+
+
+  /**
+   * Tests the first {@code toNormalizedString} method with valid DN strings.
+   */
+  @Test()
+  public void testToNormalizedString1()
+  {
+    assertEquals(new LazyDN("").toNormalizedString(), "");
+    assertEquals(new LazyDN("dc=example,dc=com").toNormalizedString(),
+                 "dc=example,dc=com");
+    assertEquals(
+         new LazyDN("ou=People, dc=example, dc=com").toNormalizedString(),
+         "ou=people,dc=example,dc=com");
+  }
+
+
+
+  /**
+   * Tests the first {@code toNormalizedString} method with an invalid DN
+   * string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testToNormalizedString1Invalid()
+  {
+    new LazyDN("invalid").toNormalizedString();
+  }
+
+
+
+  /**
+   * Tests the second {@code toNormalizedString} method with valid DN strings.
+   */
+  @Test()
+  public void testToNormalizedString2()
+  {
+    StringBuilder buffer = new StringBuilder();
+    new LazyDN("").toNormalizedString(buffer);
+    assertEquals(buffer.toString(), "");
+
+    buffer = new StringBuilder();
+    new LazyDN("dc=example,dc=com").toNormalizedString(buffer);
+    assertEquals(buffer.toString(), "dc=example,dc=com");
+
+    buffer = new StringBuilder();
+    new LazyDN("ou=People, dc=example, dc=com").toNormalizedString(buffer);
+    assertEquals(buffer.toString(), "ou=people,dc=example,dc=com");
+  }
+
+
+
+  /**
+   * Tests the second {@code toNormalizedString} method with an invalid DN
+   * string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testToNormalizedString2Invalid()
+  {
+    new LazyDN("invalid").toNormalizedString(new StringBuilder());
+  }
+
+
+
+  /**
+   * Tests the {@code compareTo} method with valid DN strings.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testCompareTo()
+         throws Exception
+  {
+    DN dn = DN.nullDN();
+    assertEquals(new LazyDN("").compareTo(dn), 0);
+
+    dn = DN.decode("dc=example,dc=com");
+    assertEquals(new LazyDN("dc=example,dc=com").compareTo(dn), 0);
+  }
+
+
+
+  /**
+   * Tests the {@code compareTo} method with an invalid DN string.
+   */
+  @Test(expectedExceptions = { RuntimeException.class })
+  public void testCompareToInvalid()
+  {
+    new LazyDN("invalid").compareTo(DN.nullDN());
+  }
+}
+

--
Gitblit v1.10.0