From 7f6350c7b5e7382b541df71d16bf926d7c284634 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sun, 10 Sep 2006 23:30:32 +0000
Subject: [PATCH] Rewrite the unit tests for the ASN1Element class to work better within the testng framework and to provide more complete coverage.

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java | 1784 ++++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 1,200 insertions(+), 584 deletions(-)

diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java
index 2d78c4d..270fdf1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/asn1/TestASN1Element.java
@@ -26,745 +26,1361 @@
  */
 package org.opends.server.protocols.asn1;
 
-import static org.opends.server.util.StaticUtils.listsAreEqual;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertFalse;
-import static org.testng.AssertJUnit.assertTrue;
+
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
 
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
-import org.testng.annotations.BeforeClass;
+
+import org.opends.server.types.ByteString;
+
+import static org.testng.Assert.*;
+
+import static org.opends.server.messages.ProtocolMessages.*;
+
+
 
 /**
  * This class defines a set of tests for the
  * org.opends.server.protocols.asn1.ASN1Element class.
  */
-public class TestASN1Element extends ASN1TestCase {
-  // The sets of pre-encoded ASN.1 elements that will be included in the
-  // test
-  // case.
-  private ArrayList<ArrayList<ASN1Element>> testElementSets;
-
-  // The set of pre-encoded element sets that will be used in the test
-  // cases.
-  private ArrayList<byte[]> testEncodedElementSets;
-
-  // The set of pre-encoded integer values that will be included in the
-  // test
-  // cases.
-  private ArrayList<byte[]> testEncodedIntegers;
-
-  // The set of pre-encoded lengths that will be included in the test
-  // cases.
-  private ArrayList<byte[]> testEncodedLengths;
-
-  // The set of BER types that will be included in the test cases.
-  private ArrayList<Byte> testTypes;
-
-  // The set of element values that will be included in the test cases.
-  private ArrayList<byte[]> testValues;
-
-  // The set of integer values that will be included in the test cases.
-  private ArrayList<Integer> testIntegers;
-
-  // The set of lengths that will be included in the test cases.
-  private ArrayList<Integer> testLengths;
-
+public class TestASN1Element
+       extends ASN1TestCase
+{
   /**
-   * Performs any necessary initialization for this test case.
+   * Create the values that can be used for testing BER types.
+   *
+   * @return  The values that can be used for testing BER types.
    */
-  @BeforeClass
-  public void setUp() {
-    // Initialize the set of types. It will encapsulate the entire range
-    // of
-    // possible byte values.
-    testTypes = new ArrayList<Byte>();
-    for (int i = 0; i < 0xFF; i++) {
-      testTypes.add((byte) (i & 0xFF));
+  @DataProvider(name = "testTypes")
+  public Object[][] getTestTypes()
+  {
+    // Create an array with all of the valid single-byte types.  We don't
+    // support multi-byte types, so this should be a comprehensive data set.
+    Object[][] testTypes = new Object[0xFF][1];
+    for (int i=0x00; i < 0xFF; i++)
+    {
+      testTypes[i] = new Object[] { (byte) (i & 0xFF) };
     }
 
-    // Initialize the set of values. Don't make these too big since they
-    // consume memory.
-    testValues = new ArrayList<byte[]>();
-    testValues.add(null); // The null value.
-    testValues.add(new byte[0x00]); // The zero-byte value.
-    testValues.add(new byte[0x01]); // The single-byte value.
-    testValues.add(new byte[0x7F]); // The largest 1-byte length
-    // encoding.
-    testValues.add(new byte[0x80]);
-    testValues.add(new byte[0xFF]); // The largest 2-byte length
-    // encoding.
-    testValues.add(new byte[0x0100]);
-    testValues.add(new byte[0xFFFF]); // The largest 3-byte length
-    // encoding.
-    testValues.add(new byte[0x010000]);
-
-    // Initialize the set of element lengths and their pre-encoded
-    // representations. Don't make these too big since we will create
-    // arrays
-    // with these lengths during testing.
-    testLengths = new ArrayList<Integer>();
-    testEncodedLengths = new ArrayList<byte[]>();
-
-    testLengths.add(0x00); // The zero-byte length.
-    testEncodedLengths.add(new byte[] { (byte) 0x00 });
-
-    testLengths.add(0x01); // A common 1-byte length.
-    testEncodedLengths.add(new byte[] { (byte) 0x01 });
-
-    testLengths.add(0x7F); // The largest 1-byte length encoding.
-    testEncodedLengths.add(new byte[] { (byte) 0x7F });
-
-    testLengths.add(0x80); // The smallest length that must use 2
-    // bytes.
-    testEncodedLengths.add(new byte[] { (byte) 0x81, (byte) 0x80 });
-
-    testLengths.add(0xFF); // The largest length that may use 2 bytes.
-    testEncodedLengths.add(new byte[] { (byte) 0x81, (byte) 0xFF });
-
-    testLengths.add(0x0100); // The smallest length that must use 3
-    // bytes.
-    testEncodedLengths.add(new byte[] { (byte) 0x82, (byte) 0x01,
-        (byte) 0x00 });
-
-    testLengths.add(0xFFFF); // The largest length that may use 3
-    // bytes.
-    testEncodedLengths.add(new byte[] { (byte) 0x82, (byte) 0xFF,
-        (byte) 0xFF });
-
-    testLengths.add(0x010000); // The smallest length that must use 4
-    // bytes.
-    testEncodedLengths.add(new byte[] { (byte) 0x83, (byte) 0x01,
-        (byte) 0x00, (byte) 0x00 });
-
-    // Initialize the set of integer values and their pre-encoded
-    // representations. These can get big since they will not be used to
-    // create
-    // arrays. Also, there is no need to test negative values since LDAP
-    // doesn't make use of them.
-    testIntegers = new ArrayList<Integer>();
-    testEncodedIntegers = new ArrayList<byte[]>();
-
-    testIntegers.add(0x00); // A common 1-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00 });
-
-    testIntegers.add(0x7F); // The largest 1-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x7F });
-
-    testIntegers.add(0x80); // The smallest 2-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0x80 });
-
-    testIntegers.add(0xFF); // A boundary case for 2-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0xFF });
-
-    testIntegers.add(0x0100); // A boundary case for 2-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x01, (byte) 0x00 });
-
-    testIntegers.add(0x7FFF); // The largest 2-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x7F, (byte) 0xFF });
-
-    testIntegers.add(0x8000); // The smallest 3-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0x80,
-        (byte) 0x00 });
-
-    testIntegers.add(0xFFFF); // A boundary case for 3-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0xFF,
-        (byte) 0xFF });
-
-    testIntegers.add(0x010000); // A boundary case for 3-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x01, (byte) 0x00,
-        (byte) 0x00 });
-
-    testIntegers.add(0x7FFFFF); // The largest 3-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x7F, (byte) 0xFF,
-        (byte) 0xFF });
-
-    testIntegers.add(0x800000); // The smallest 4-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0x80,
-        (byte) 0x00, (byte) 0x00 });
-
-    testIntegers.add(0xFFFFFF); // A boundary case for 4-byte encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x00, (byte) 0xFF,
-        (byte) 0xFF, (byte) 0xFF });
-
-    testIntegers.add(0x01000000); // A boundary case for 4-byte
-    // encoding.
-    testEncodedIntegers.add(new byte[] { (byte) 0x01, (byte) 0x00,
-        (byte) 0x00, (byte) 0x00 });
-
-    testIntegers.add(0x7FFFFFFF); // The largest value we will allow.
-    testEncodedIntegers.add(new byte[] { (byte) 0x7F, (byte) 0xFF,
-        (byte) 0xFF, (byte) 0xFF });
-
-    // Initialize the sets of ASN.1 elements that will be used in
-    // testing the
-    // group encode/decode operations.
-    testElementSets = new ArrayList<ArrayList<ASN1Element>>();
-    testEncodedElementSets = new ArrayList<byte[]>();
-
-    testElementSets.add(null); // The null set.
-    testEncodedElementSets.add(new byte[0]);
-
-    testElementSets.add(new ArrayList<ASN1Element>(0)); // The empty
-    // set.
-    testEncodedElementSets.add(new byte[0]);
-
-    // Sets containing from 1 to 10 elements.
-    for (int i = 1; i <= 10; i++) {
-      ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(i);
-
-      for (int j = 0; j < i; j++) {
-        elements.add(new ASN1Element((byte) 0x00));
-      }
-      testElementSets.add(elements);
-      testEncodedElementSets.add(new byte[i * 2]);
-    }
+    return testTypes;
   }
 
-  /**
-   * Tests the <CODE>getType</CODE> method.
-   */
-  @Test()
-  public void testGetType() {
-    for (byte type : testTypes) {
-      ASN1Element element = new ASN1Element(type);
 
-      assertEquals(type, element.getType());
-
-      for (byte[] value : testValues) {
-        element = new ASN1Element(type, value);
-
-        assertEquals(type, element.getType());
-      }
-    }
-  }
 
   /**
-   * Tests the <CODE>setType</CODE> method.
+   * Tests the <CODE>getType</CODE> and <CODE>setType</CODE> methods.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testSetType() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-
-      assertEquals(type, element.getType());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testGetAndSetType(byte type)
+  {
+    ASN1Element e = new ASN1Element((byte) 0x00);
+    e.setType(type);
+    assertEquals(type, e.getType());
   }
 
+
+
   /**
    * Tests the <CODE>isUniversal</CODE> method.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testIsUniversal() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isUniversal = (((byte) (type & 0xC0)) == ((byte) 0x00));
-
-      assertEquals(isUniversal, element.isUniversal());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testIsUniversal(byte type)
+  {
+    boolean isUniversal = (((type & 0xFF) >> 6) == 0x00);
+    assertEquals(isUniversal, new ASN1Element(type).isUniversal());
   }
 
+
+
   /**
    * Tests the <CODE>isApplicationSpecific</CODE> method.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testIsApplicationSpecific() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isApplicationSpecific = (((byte) (type & 0xC0)) == ((byte) 0x40));
-
-      assertEquals(isApplicationSpecific, element.isApplicationSpecific());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testIsApplicationSpecific(byte type)
+  {
+    boolean isApplicationSpecific = (((type & 0xFF) >> 6) == 0x01);
+    assertEquals(isApplicationSpecific,
+                 new ASN1Element(type).isApplicationSpecific());
   }
 
+
+
   /**
    * Tests the <CODE>isContextSpecific</CODE> method.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testIsContextSpecific() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isContextSpecific = (((byte) (type & 0xC0)) == ((byte) 0x80));
-
-      assertEquals(isContextSpecific, element.isContextSpecific());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testIsContextSpecific(byte type)
+  {
+    boolean isContextSpecific = (((type & 0xFF) >> 6) == 0x02);
+    assertEquals(isContextSpecific, new ASN1Element(type).isContextSpecific());
   }
 
+
+
   /**
    * Tests the <CODE>isPrivate</CODE> method.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testIsPrivate() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isPrivate = (((byte) (type & 0xC0)) == ((byte) 0xC0));
-
-      assertEquals(isPrivate, element.isPrivate());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testIsPrivate(byte type)
+  {
+    boolean isPrivate = (((type & 0xFF) >> 6) == 0x03);
+    assertEquals(isPrivate, new ASN1Element(type).isPrivate());
   }
 
+
+
   /**
    * Tests the <CODE>isPrimitive</CODE> method.
+   *
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testIsPrimitive() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isPrimitive = (((byte) (type & 0x20)) == ((byte) 0x00));
-
-      assertEquals(isPrimitive, element.isPrimitive());
-    }
+  @Test(dataProvider = "testTypes")
+  public void testIsPrimitive(byte type)
+  {
+    boolean isPrimitive = ((type & 0xDF) == (type & 0xFF));
+    assertEquals(isPrimitive, new ASN1Element(type).isPrimitive());
   }
 
+
+
   /**
    * Tests the <CODE>isConstructed</CODE> method.
-   */
-  @Test()
-  public void testIsConstructed() {
-    ASN1Element element = new ASN1Element((byte) 0x00);
-    for (byte type : testTypes) {
-      element.setType(type);
-      boolean isConstructed = (((byte) (type & 0x20)) == ((byte) 0x20));
-
-      assertEquals(isConstructed, element.isConstructed());
-    }
-  }
-
-  /**
-   * Tests the <CODE>getValue</CODE> method.
-   */
-  @Test()
-  public void testGetValue() {
-    for (byte type : testTypes) {
-      ASN1Element element = new ASN1Element(type);
-
-      assertTrue(Arrays.equals(new byte[0], element.value()));
-
-      for (byte[] value : testValues) {
-        element = new ASN1Element(type, value);
-
-        if (value == null) {
-          assertTrue(Arrays.equals(new byte[0], element.value()));
-        } else {
-          assertTrue(Arrays.equals(value, element.value()));
-        }
-      }
-    }
-  }
-
-  /**
-   * Tests the <CODE>setValue</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @param  type  The BER type to use in the test.
    */
-  @Test()
-  public void testSetValue() throws Exception {
-    ASN1Element element = new ASN1Element((byte) 0x00);
+  @Test(dataProvider = "testTypes")
+  public void testIsConstructed(byte type)
+  {
+    boolean isConstructed = ((type & 0xDF) != (type & 0xFF));
+    assertEquals(isConstructed, new ASN1Element(type).isConstructed());
+  }
 
-    for (byte[] value : testValues) {
-      element.setValue(value);
-      if (value == null) {
-        assertTrue(Arrays.equals(new byte[0], element.value()));
-      } else {
-        assertTrue(Arrays.equals(value, element.value()));
-      }
+
+
+  /**
+   * Create byte arrays to use for element values.
+   *
+   * @return  A list of byte arrays that can be used as element values.
+   */
+  @DataProvider(name = "testValues")
+  public Object[][] getTestValues()
+  {
+    // NOTE -- Don't make these arrays too big since they consume memory.
+    return new Object[][]
+    {
+      new Object[] { null },              // The null value
+      new Object[] { new byte[0x00] },    // The zero-byte value
+      new Object[] { new byte[0x01] },    // The single-byte value
+      new Object[] { new byte[0x7F] },    // The largest 1-byte length encoding
+      new Object[] { new byte[0x80] },    // The smallest 2-byte length encoding
+      new Object[] { new byte[0xFF] },    // The largest 2-byte length encoding
+      new Object[] { new byte[0x0100] },  // The smallest 3-byte length encoding
+      new Object[] { new byte[0xFFFF] },  // The largest 3-byte length encoding
+      new Object[] { new byte[0x010000] } // The smallest 4-byte length encoding
+    };
+  }
+
+
+
+  /**
+   * Tests the <CODE>getValue</CODE> and <CODE>setValue</CODE> methods.
+   *
+   * @param  value  The value to use in the test.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "testValues")
+  public void testGetAndSetValue(byte[] value)
+         throws Exception
+  {
+    ASN1Element e = new ASN1Element((byte) 0x00);
+    e.setValue(value);
+
+    if (value == null)
+    {
+      assertEquals(new byte[0], e.value());
+    }
+    else
+    {
+      assertEquals(value, e.value());
     }
   }
 
+
+
+  /**
+   * Create decoded and encoded lengths.
+   *
+   * @return  A list of decoded and encoded lengths.
+   */
+  @DataProvider(name = "testLengths")
+  public Object[][] getTestLengths()
+  {
+    return new Object[][]
+    {
+      new Object[] { 0x00, new byte[] { 0x00 } },
+      new Object[] { 0x01, new byte[] { 0x01 } },
+      new Object[] { 0x7F, new byte[] { 0x7F } },
+      new Object[] { 0x80, new byte[] { (byte) 0x81, (byte) 0x80 } },
+      new Object[] { 0xFF, new byte[] { (byte) 0x81, (byte) 0xFF } },
+      new Object[] { 0x0100, new byte[] { (byte) 0x82, 0x01, 0x00 } },
+      new Object[] { 0xFFFF,
+                     new byte[] { (byte) 0x82, (byte) 0xFF, (byte) 0xFF } },
+      new Object[] { 0x010000, new byte[] { (byte) 0x83, 0x01, 0x00, 0x00 } },
+      new Object[] { 0xFFFFFF,
+                     new byte[] { (byte) 0x83, (byte) 0xFF, (byte) 0xFF,
+                                  (byte) 0xFF } },
+      new Object[] { 0x01000000,
+                     new byte[] { (byte) 0x84, 0x01, 0x00, 0x00, 0x00 } },
+      new Object[] { 0x7FFFFFFF,
+                     new byte[] { (byte) 0x84, (byte) 0x7F, (byte) 0xFF,
+                                  (byte) 0xFF, (byte) 0xFF } },
+    };
+  }
+
+
   /**
    * Tests the <CODE>encodeLength</CODE> method.
+   *
+   * @param  decodedLength  The decoded length to encode.
+   * @param  encodedLength  The encoded representation of the length.
    */
-  @Test()
-  public void testEncodeLength() {
-    int numLengths = testLengths.size();
-    for (int i = 0; i < numLengths; i++) {
-      int length = testLengths.get(i);
-      byte[] encodedLength = testEncodedLengths.get(i);
-
-      assertTrue(Arrays.equals(encodedLength, ASN1Element
-          .encodeLength(length)));
-    }
+  @Test(dataProvider = "testLengths")
+  public void testEncodeLength(int decodedLength, byte[] encodedLength)
+  {
+    assertEquals(encodedLength, ASN1Element.encodeLength(decodedLength));
   }
 
+
+
   /**
    * Tests the <CODE>encode</CODE> and <CODE>decode</CODE> methods.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test()
-  public void testEncodeAndDecode() throws Exception {
-    for (byte type : testTypes) {
-      for (byte[] value : testValues) {
-        int length;
-        byte[] encodedLength;
-        if (value == null) {
-          length = 0;
-          encodedLength = new byte[] { (byte) 0x00 };
-        } else {
-          length = value.length;
-          encodedLength = ASN1Element.encodeLength(length);
-        }
-
-        byte[] encodedElement = new byte[1 + length + encodedLength.length];
-        encodedElement[0] = type;
-        System.arraycopy(encodedLength, 0, encodedElement, 1,
-            encodedLength.length);
-        if (value != null) {
-          System.arraycopy(value, 0, encodedElement,
-              1 + encodedLength.length, length);
-        }
-
-        ASN1Element element = new ASN1Element(type, value);
-
-        assertTrue(Arrays.equals(encodedElement, element.encode()));
-
-        assertTrue(element.equals(ASN1Element.decode(encodedElement)));
-      }
-
-      int numLengths = testLengths.size();
-      for (int i = 0; i < numLengths; i++) {
-        int length = testLengths.get(i);
-        byte[] encodedLength = testEncodedLengths.get(i);
-        byte[] value = new byte[length];
-
-        byte[] encodedElement = new byte[1 + length + encodedLength.length];
-        encodedElement[0] = type;
-        System.arraycopy(encodedLength, 0, encodedElement, 1,
-            encodedLength.length);
-
-        ASN1Element element = new ASN1Element(type, value);
-
-        assertTrue(Arrays.equals(encodedElement, element.encode()));
-
-        assertTrue(element.equals(ASN1Element.decode(encodedElement)));
-      }
-    }
-  }
-
-  /**
-   * Tests the <CODE>encodeValue</CODE> method with a single boolean
-   * argument.
-   */
-  @Test()
-  public void testEncodeBooleanValue() {
-    byte[] encodedFalse = new byte[] { (byte) 0x00 };
-    byte[] encodedTrue = new byte[] { (byte) 0xFF };
-
-    assertTrue(Arrays.equals(encodedFalse, ASN1Element.encodeValue(false)));
-
-    assertTrue(Arrays.equals(encodedTrue, ASN1Element.encodeValue(true)));
-  }
-
-  /**
-   * Tests the <CODE>encodeValue</CODE> method with a single int
-   * argument.
-   */
-  @Test()
-  public void testEncodeIntValue() {
-    int numIntValues = testIntegers.size();
-    for (int i = 0; i < numIntValues; i++) {
-      int intValue = testIntegers.get(i);
-      byte[] encodedInt = testEncodedIntegers.get(i);
-
-      assertTrue(Arrays.equals(encodedInt, ASN1Element
-          .encodeValue(intValue)));
-    }
-  }
-
-  /**
-   * Tests the <CODE>encodeValue</CODE> method with a set of ASN.1
-   * elements.
+   * @param  value  The value to use in the test.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @throws  Exception  If the test failed unexpectedly.
    */
-  @Test()
-  public void testEncodeAndDecodeElements() throws Exception {
-    int numElementSets = testElementSets.size();
-    for (int i = 0; i < numElementSets; i++) {
-      ArrayList<ASN1Element> elementSet = testElementSets.get(i);
-      byte[] encodedElementSet = testEncodedElementSets.get(i);
+  @Test(dataProvider = "testValues")
+  public void testEncodeAndDecode(byte[] value)
+         throws Exception
+  {
+    for (int i=0x00; i < 0xFF; i++)
+    {
+      byte type = (byte) i;
+      ASN1Element e = new ASN1Element(type, value);
+      byte[] encodedElement = e.encode();
 
-      assertTrue(Arrays.equals(encodedElementSet, ASN1Element
-          .encodeValue(elementSet)));
+      ASN1Element d = ASN1Element.decode(encodedElement);
+      assertEquals(d, e);
+      assertEquals(type, d.getType());
+      assertTrue(e.equalsElement(d));
 
-      ArrayList<ASN1Element> decodedElementSet;
-      decodedElementSet = ASN1Element.decodeElements(encodedElementSet);
-
-      ArrayList<ASN1Element> compareSet;
-      if (elementSet == null) {
-        compareSet = new ArrayList<ASN1Element>(0);
-      } else {
-        compareSet = elementSet;
+      if (value == null)
+      {
+        assertEquals(new byte[0], d.value());
+      }
+      else
+      {
+        assertEquals(value, d.value());
       }
 
-      assertTrue(listsAreEqual(compareSet, decodedElementSet));
+      d = ASN1Element.decode(encodedElement, 0, encodedElement.length);
+      assertEquals(d, e);
+      assertEquals(type, d.getType());
+      assertTrue(e.equalsElement(d));
+
+      if (value == null)
+      {
+        assertEquals(new byte[0], d.value());
+      }
+      else
+      {
+        assertEquals(value, d.value());
+      }
     }
   }
 
+
+
+  /**
+   * Tests to ensure that there is a failure when trying to decode a null as an
+   * element.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeFailureNull()
+         throws Exception
+  {
+    ASN1Element.decode(null);
+  }
+
+
+
   /**
    * Tests the <CODE>decodeAsBoolean</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @throws  Exception  If the test failed unexpectedly.
    */
   @Test()
-  public void testDecodeAsBoolean() throws Exception {
-    for (int i = 0; i < 256; i++) {
-      byte[] valueByte = new byte[] { (byte) i };
-      ASN1Element element = new ASN1Element((byte) 0x00, valueByte);
-      boolean booleanValue = (i != 0);
+  public void testDecodeAsBoolean()
+         throws Exception
+  {
+    // First, make sure that we can decode actual Boolean elements as Boolean
+    // elements, using both the standard type as well as a nonstandard type.
+    boolean[] booleanValues = new boolean[] { true, false };
+    for (boolean b : booleanValues)
+    {
+      ASN1Element e = new ASN1Boolean(b);
+      ASN1Boolean booleanElement = e.decodeAsBoolean();
+      assertEquals(b, booleanElement.booleanValue());
 
-      assertEquals(booleanValue, element.decodeAsBoolean().booleanValue());
+      e = new ASN1Boolean((byte) 0x50, b);
+      booleanElement = e.decodeAsBoolean();
+      assertEquals(b, booleanElement.booleanValue());
+    }
 
-      element = new ASN1Element((byte) 0x01, valueByte);
 
-      assertEquals(booleanValue, element.decodeAsBoolean().booleanValue());
+    // Next, make sure we can decode generic ASN.1 elements with a single-byte
+    // value as a Boolean element.
+    for (int i=0; i < 256; i++)
+    {
+      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE,
+                                      new byte[] { (byte) i });
+      ASN1Boolean b = e.decodeAsBoolean();
+      assertEquals((i != 0), b.booleanValue());
+
+      e = new ASN1Element((byte) 0x50, new byte[] { (byte) i });
+      b = e.decodeAsBoolean();
+      assertEquals((i != 0), b.booleanValue());
     }
   }
 
+
+
   /**
    * Tests the <CODE>decodeAsEnumerated</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @throws  Exception  If the test failed unexpectedly.
    */
   @Test()
-  public void testDecodeAsEnumerated() throws Exception {
-    int numIntValues = testIntegers.size();
-    for (int i = 0; i < numIntValues; i++) {
-      int intValue = testIntegers.get(i);
-      byte[] encodedInt = testEncodedIntegers.get(i);
+  public void testDecodeAsEnumerated()
+         throws Exception
+  {
+    int[] intValues =
+    {
+      0x00000000,
+      0x00000001,
+      0x0000000F,
+      0x00000010,
+      0x0000007F,
+      0x00000080,
+      0x000000FF,
+      0x00000100,
+      0x00000FFF,
+      0x00001000,
+      0x0000FFFF,
+      0x00010000,
+      0x000FFFFF,
+      0x00100000,
+      0x00FFFFFF,
+      0x01000000,
+      0x0FFFFFFF,
+      0x10000000,
+      0x7FFFFFFF
+    };
 
-      ASN1Element element = new ASN1Element((byte) 0x00, encodedInt);
+    // First, make sure that we can decode actual enumerated elements as
+    // enumerated elements, using both the standard type as well as a
+    // nonstandard type.
+    for (int i : intValues)
+    {
+      ASN1Element e = new ASN1Enumerated(i);
+      ASN1Enumerated enumeratedElement = e.decodeAsEnumerated();
+      assertEquals(i, enumeratedElement.intValue());
 
-      assertEquals(intValue, element.decodeAsEnumerated().intValue());
+      e = new ASN1Enumerated((byte) 0x50, i);
+      enumeratedElement = e.decodeAsEnumerated();
+      assertEquals(i, enumeratedElement.intValue());
+    }
 
-      element = new ASN1Element((byte) 0x0A, encodedInt);
 
-      assertEquals(intValue, element.decodeAsEnumerated().intValue());
+    // Next, make sure we can decode generic ASN.1 elements as enumerated
+    // elements.
+    for (int i : intValues)
+    {
+      byte[] encoding;
+      if ((i & 0xFF) == i)
+      {
+        encoding = new byte[1];
+        encoding[0] = (byte) (i & 0xFF);
+      }
+      else if ((i & 0xFFFF) == i)
+      {
+        encoding = new byte[2];
+        encoding[0] = (byte) ((i >> 8) & 0xFF);
+        encoding[1] = (byte) (i & 0xFF);
+      }
+      else if ((i & 0xFFFFFF) == i)
+      {
+        encoding = new byte[3];
+        encoding[0] = (byte) ((i >> 16) & 0xFF);
+        encoding[1] = (byte) ((i >> 8) & 0xFF);
+        encoding[2] = (byte) (i & 0xFF);
+      }
+      else
+      {
+        encoding = new byte[4];
+        encoding[0] = (byte) ((i >> 24) & 0xFF);
+        encoding[1] = (byte) ((i >> 16) & 0xFF);
+        encoding[2] = (byte) ((i >> 8) & 0xFF);
+        encoding[3] = (byte) (i & 0xFF);
+      }
+
+      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE,
+                                      encoding);
+      ASN1Enumerated enumeratedElement = e.decodeAsEnumerated();
+      assertEquals(i, enumeratedElement.intValue());
+
+      e = new ASN1Element((byte) 0x50, encoding);
+      enumeratedElement = e.decodeAsEnumerated();
+      assertEquals(i, enumeratedElement.intValue());
     }
   }
 
+
+
   /**
    * Tests the <CODE>decodeAsInteger</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @throws  Exception  If the test failed unexpectedly.
    */
   @Test()
-  public void testDecodeAsInteger() throws Exception {
-    int numIntValues = testIntegers.size();
-    for (int i = 0; i < numIntValues; i++) {
-      int intValue = testIntegers.get(i);
-      byte[] encodedInt = testEncodedIntegers.get(i);
+  public void testDecodeAsInteger()
+         throws Exception
+  {
+    int[] intValues =
+    {
+      0x00000000,
+      0x00000001,
+      0x0000000F,
+      0x00000010,
+      0x0000007F,
+      0x00000080,
+      0x000000FF,
+      0x00000100,
+      0x00000FFF,
+      0x00001000,
+      0x0000FFFF,
+      0x00010000,
+      0x000FFFFF,
+      0x00100000,
+      0x00FFFFFF,
+      0x01000000,
+      0x0FFFFFFF,
+      0x10000000,
+      0x7FFFFFFF,
+      -0x00000001,
+      -0x0000000F,
+      -0x00000010,
+      -0x0000007F,
+      -0x00000080,
+      -0x000000FF,
+      -0x00000100,
+      -0x00000FFF,
+      -0x00001000,
+      -0x0000FFFF,
+      -0x00010000,
+      -0x000FFFFF,
+      -0x00100000,
+      -0x00FFFFFF,
+      -0x01000000,
+      -0x0FFFFFFF,
+      -0x10000000,
+      -0x7FFFFFFF,
+      0x80000000
+    };
 
-      ASN1Element element = new ASN1Element((byte) 0x00, encodedInt);
+    // First, make sure that we can decode actual integer elements as integer
+    // elements, using both the standard type as well as a nonstandard type.
+    for (int i : intValues)
+    {
+      ASN1Element e = new ASN1Integer(i);
+      ASN1Integer integerElement = e.decodeAsInteger();
+      assertEquals(i, integerElement.intValue());
 
-      assertEquals(intValue, element.decodeAsInteger().intValue());
+      e = new ASN1Integer((byte) 0x50, i);
+      integerElement = e.decodeAsInteger();
+      assertEquals(i, integerElement.intValue());
+    }
 
-      element = new ASN1Element((byte) 0x02, encodedInt);
 
-      assertEquals(intValue, element.decodeAsInteger().intValue());
+    // Next, make sure we can decode generic ASN.1 elements as integer elements.
+    for (int i : intValues)
+    {
+      byte[] encoding;
+      if ((i & 0x7F) == i)
+      {
+        encoding = new byte[1];
+        encoding[0] = (byte) (i & 0xFF);
+      }
+      else if ((i & 0x7FFF) == i)
+      {
+        encoding = new byte[2];
+        encoding[0] = (byte) ((i >> 8) & 0xFF);
+        encoding[1] = (byte) (i & 0xFF);
+      }
+      else if ((i & 0x7FFFFF) == i)
+      {
+        encoding = new byte[3];
+        encoding[0] = (byte) ((i >> 16) & 0xFF);
+        encoding[1] = (byte) ((i >> 8) & 0xFF);
+        encoding[2] = (byte) (i & 0xFF);
+      }
+      else
+      {
+        encoding = new byte[4];
+        encoding[0] = (byte) ((i >> 24) & 0xFF);
+        encoding[1] = (byte) ((i >> 16) & 0xFF);
+        encoding[2] = (byte) ((i >> 8) & 0xFF);
+        encoding[3] = (byte) (i & 0xFF);
+      }
+
+      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
+                                      encoding);
+      ASN1Integer integerElement = e.decodeAsInteger();
+      assertEquals(i, integerElement.intValue());
+
+      e = new ASN1Element((byte) 0x50, encoding);
+      integerElement = e.decodeAsInteger();
+      assertEquals(i, integerElement.intValue());
     }
   }
 
+
+
+  /**
+   * Tests the <CODE>decodeAsLong</CODE> method.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test()
+  public void testDecodeAsLong()
+         throws Exception
+  {
+    long[] longValues =
+    {
+      0x0000000000000000L,
+      0x0000000000000001L,
+      0x000000000000007FL,
+      0x0000000000000080L,
+      0x00000000000000FFL,
+      0x0000000000000100L,
+      0x000000000000FFFFL,
+      0x0000000000010000L,
+      0x0000000000FFFFFFL,
+      0x0000000001000000L,
+      0x00000000FFFFFFFFL,
+      0x0000000100000000L,
+      0x000000FFFFFFFFFFL,
+      0x0000010000000000L,
+      0x0000FFFFFFFFFFFFL,
+      0x0001000000000000L,
+      0x00FFFFFFFFFFFFFFL,
+      0x0100000000000000L,
+      0x7FFFFFFFFFFFFFFFL,
+      -0x0000000000000001L,
+      -0x000000000000007FL,
+      -0x0000000000000080L,
+      -0x00000000000000FFL,
+      -0x0000000000000100L,
+      -0x000000000000FFFFL,
+      -0x0000000000010000L,
+      -0x0000000000FFFFFFL,
+      -0x0000000001000000L,
+      -0x00000000FFFFFFFFL,
+      -0x0000000100000000L,
+      -0x000000FFFFFFFFFFL,
+      -0x0000010000000000L,
+      -0x0000FFFFFFFFFFFFL,
+      -0x0001000000000000L,
+      -0x00FFFFFFFFFFFFFFL,
+      -0x0100000000000000L,
+      -0x7FFFFFFFFFFFFFFFL,
+      0x8000000000000000L
+    };
+
+    // First, make sure that we can decode actual long elements as long
+    // elements, using both the standard type as well as a nonstandard type.
+    for (long l : longValues)
+    {
+      ASN1Element e = new ASN1Long(l);
+      ASN1Long longElement = e.decodeAsLong();
+      assertEquals(l, longElement.longValue());
+
+      e = new ASN1Long((byte) 0x50, l);
+      longElement = e.decodeAsLong();
+      assertEquals(l, longElement.longValue());
+    }
+
+
+    // Next, make sure we can decode generic ASN.1 elements as long elements.
+    for (long l : longValues)
+    {
+      byte[] encoding;
+      if ((l & 0x7FL) == l)
+      {
+        encoding = new byte[1];
+        encoding[0] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFL) == l)
+      {
+        encoding = new byte[2];
+        encoding[0] = (byte) ((l >> 8) & 0xFF);
+        encoding[1] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFFFL) == l)
+      {
+        encoding = new byte[3];
+        encoding[0] = (byte) ((l >> 16) & 0xFF);
+        encoding[1] = (byte) ((l >> 8) & 0xFF);
+        encoding[2] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFFFFFL) == l)
+      {
+        encoding = new byte[4];
+        encoding[0] = (byte) ((l >> 24) & 0xFF);
+        encoding[1] = (byte) ((l >> 16) & 0xFF);
+        encoding[2] = (byte) ((l >> 8) & 0xFF);
+        encoding[3] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFFFFFFFL) == l)
+      {
+        encoding = new byte[5];
+        encoding[0] = (byte) ((l >> 32) & 0xFF);
+        encoding[1] = (byte) ((l >> 24) & 0xFF);
+        encoding[2] = (byte) ((l >> 16) & 0xFF);
+        encoding[3] = (byte) ((l >> 8) & 0xFF);
+        encoding[4] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFFFFFFFFFL) == l)
+      {
+        encoding = new byte[6];
+        encoding[0] = (byte) ((l >> 40) & 0xFF);
+        encoding[1] = (byte) ((l >> 32) & 0xFF);
+        encoding[2] = (byte) ((l >> 24) & 0xFF);
+        encoding[3] = (byte) ((l >> 16) & 0xFF);
+        encoding[4] = (byte) ((l >> 8) & 0xFF);
+        encoding[5] = (byte) (l & 0xFF);
+      }
+      else if ((l & 0x7FFFFFFFFFFFFFL) == l)
+      {
+        encoding = new byte[7];
+        encoding[0] = (byte) ((l >> 48) & 0xFF);
+        encoding[1] = (byte) ((l >> 40) & 0xFF);
+        encoding[2] = (byte) ((l >> 32) & 0xFF);
+        encoding[3] = (byte) ((l >> 24) & 0xFF);
+        encoding[4] = (byte) ((l >> 16) & 0xFF);
+        encoding[5] = (byte) ((l >> 8) & 0xFF);
+        encoding[6] = (byte) (l & 0xFF);
+      }
+      else
+      {
+        encoding = new byte[8];
+        encoding[0] = (byte) ((l >> 56) & 0xFF);
+        encoding[1] = (byte) ((l >> 48) & 0xFF);
+        encoding[2] = (byte) ((l >> 40) & 0xFF);
+        encoding[3] = (byte) ((l >> 32) & 0xFF);
+        encoding[4] = (byte) ((l >> 24) & 0xFF);
+        encoding[5] = (byte) ((l >> 16) & 0xFF);
+        encoding[6] = (byte) ((l >> 8) & 0xFF);
+        encoding[7] = (byte) (l & 0xFF);
+      }
+
+      ASN1Element e = new ASN1Element(ASN1Constants.UNIVERSAL_INTEGER_TYPE,
+                                      encoding);
+      ASN1Long longElement = e.decodeAsLong();
+      assertEquals(l, longElement.longValue());
+
+      e = new ASN1Element((byte) 0x50, encoding);
+      longElement = e.decodeAsLong();
+      assertEquals(l, longElement.longValue());
+    }
+  }
+
+
+
   /**
    * Tests the <CODE>decodeAsNull</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @throws  Exception  If the test failed unexpectedly.
    */
   @Test()
-  public void testDecodeAsNull() throws Exception {
-    for (byte type : testTypes) {
-      ASN1Element element = new ASN1Element(type);
-      ASN1Null nullElement = new ASN1Null(type);
+  public void testDecodeAsNull()
+         throws Exception
+  {
+    // First, make sure that we can decode actual null elements as null
+    // elements, using both the standard type as well as a nonstandard type.
+    ASN1Element e = new ASN1Null();
+    e.decodeAsNull();
 
-      assertEquals(nullElement, element.decodeAsNull());
-    }
+    e = new ASN1Null((byte) 0x50);
+    e.decodeAsNull();
+
+
+    // Next, make sure we can decode generic ASN.1 elements with a zero-byte
+    // value as a null element.
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE);
+    e.decodeAsNull();
+
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE, null);
+    e.decodeAsNull();
+
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_NULL_TYPE, new byte[0]);
+    e.decodeAsNull();
+
+    e = new ASN1Element((byte) 0x50);
+    e.decodeAsNull();
+
+    e = new ASN1Element((byte) 0x50, null);
+    e.decodeAsNull();
+
+    e = new ASN1Element((byte) 0x50, new byte[0]);
+    e.decodeAsNull();
   }
 
+
+
   /**
    * Tests the <CODE>decodeAsOctetString</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @param  value  The value to use for the octet string element.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
    */
-  @Test()
-  public void testDecodeAsOctetString() throws Exception {
-    for (byte[] value : testValues) {
-      ASN1Element element = new ASN1Element((byte) 0x00, value);
+  @Test(dataProvider = "testValues")
+  public void testDecodeAsOctetString(byte[] value)
+         throws Exception
+  {
+    // First, make sure that we can decode actual octet string elements as octet
+    // string elements, using both the standard type as well as a nonstandard
+    // type.
+    ASN1Element e = new ASN1OctetString(value);
+    ASN1OctetString octetStringElement = e.decodeAsOctetString();
+    if (value == null)
+    {
+      assertEquals(new byte[0], octetStringElement.value());
+    }
+    else
+    {
+      assertEquals(value, octetStringElement.value());
+    }
 
-      byte[] compareValue;
-      if (value == null) {
-        compareValue = new byte[0];
-      } else {
-        compareValue = value;
-      }
+    e = new ASN1OctetString((byte) 0x50, value);
+    octetStringElement = e.decodeAsOctetString();
+    if (value == null)
+    {
+      assertEquals(new byte[0], octetStringElement.value());
+    }
+    else
+    {
+      assertEquals(value, octetStringElement.value());
+    }
 
-      assertTrue(Arrays.equals(compareValue, element.decodeAsOctetString()
-          .value()));
 
-      element = new ASN1Element((byte) 0x04, value);
+    // Next, make sure that we can decode a generic ASN.1 element as an octet
+    // string element.
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
+    octetStringElement = e.decodeAsOctetString();
+    if (value == null)
+    {
+      assertEquals(new byte[0], octetStringElement.value());
+    }
+    else
+    {
+      assertEquals(value, octetStringElement.value());
+    }
 
-      assertTrue(Arrays.equals(compareValue, element.decodeAsOctetString()
-          .value()));
+    e = new ASN1Element((byte) 0x50, value);
+    octetStringElement = e.decodeAsOctetString();
+    if (value == null)
+    {
+      assertEquals(new byte[0], octetStringElement.value());
+    }
+    else
+    {
+      assertEquals(value, octetStringElement.value());
     }
   }
 
+
+
+  /**
+   * Retrieves arrays of ASN.1 elements for use in testing with sequences and
+   * sets.
+   *
+   * @return  Arrays of ASN.1 elements for use in testing with sequences and
+   *          sets.
+   */
+  @DataProvider(name = "elementArrays")
+  public Object[][] getElementArrays()
+  {
+    ArrayList<ASN1Element[]> arrays = new ArrayList<ASN1Element[]>();
+    arrays.add(null);
+    arrays.add(new ASN1Element[0]);
+    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50) });
+    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, null) });
+    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, new byte[0]) });
+    arrays.add(new ASN1Element[] { new ASN1Element((byte) 0x50, new byte[1]) });
+    arrays.add(new ASN1Element[] { new ASN1Boolean(true) });
+    arrays.add(new ASN1Element[] { new ASN1Enumerated(0) });
+    arrays.add(new ASN1Element[] { new ASN1Integer(0) });
+    arrays.add(new ASN1Element[] { new ASN1Long(0) });
+    arrays.add(new ASN1Element[] { new ASN1OctetString() });
+    arrays.add(new ASN1Element[] { new ASN1OctetString(),
+                                   new ASN1OctetString() });
+    arrays.add(new ASN1Element[] { new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString() });
+    arrays.add(new ASN1Element[] { new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString() });
+    arrays.add(new ASN1Element[] { new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString(),
+                                   new ASN1OctetString() });
+    arrays.add(new ASN1Element[] { new ASN1Integer(1),
+                                   new ASN1Null((byte) 0x42) });
+
+    Object[][] objects = new Object[arrays.size()][];
+    for (int i=0; i < arrays.size(); i++)
+    {
+      objects[i] = new Object[] { arrays.get(i) };
+    }
+
+    return objects;
+  }
+
+
+
   /**
    * Tests the <CODE>decodeAsSequence</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @param  elements  The set of ASN.1 elements to use in the tests.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
    */
-  @Test()
-  public void testDecodeAsSequence() throws Exception {
-    int numElementSets = testElementSets.size();
-    for (int i = 0; i < numElementSets; i++) {
-      ArrayList<ASN1Element> elementSet = testElementSets.get(i);
-      byte[] encodedElementSet = testEncodedElementSets.get(i);
-
-      ArrayList<ASN1Element> compareList;
-      if (elementSet == null) {
-        compareList = new ArrayList<ASN1Element>(0);
-      } else {
-        compareList = elementSet;
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeAsSequence(ASN1Element[] elements)
+         throws Exception
+  {
+    ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>();
+    if (elements == null)
+    {
+      elementList = null;
+    }
+    else
+    {
+      for (ASN1Element e : elements)
+      {
+        elementList.add(e);
       }
+    }
 
-      ASN1Element element = new ASN1Element((byte) 0x00, encodedElementSet);
 
-      assertTrue(listsAreEqual(compareList, element.decodeAsSequence()
-          .elements()));
+    // First, make sure that we can decode actual sequence elements as sequence
+    // elements, using both the standard type as well as a nonstandard type.
+    ASN1Element e = new ASN1Sequence(elementList);
+    ASN1Sequence sequenceElement = e.decodeAsSequence();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), sequenceElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, sequenceElement.elements());
+    }
 
-      element = new ASN1Element((byte) 0x30, encodedElementSet);
+    e = new ASN1Sequence((byte) 0x50, elementList);
+    sequenceElement = e.decodeAsSequence();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), sequenceElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, sequenceElement.elements());
+    }
 
-      assertTrue(listsAreEqual(compareList, element.decodeAsSequence()
-          .elements()));
+
+    // Next, make sure that we can decode a generic ASN.1 element as an octet
+    // string element.
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE,
+                        ASN1Element.encodeValue(elementList));
+    sequenceElement = e.decodeAsSequence();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), sequenceElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, sequenceElement.elements());
+    }
+
+    e = new ASN1Element((byte) 0x50, ASN1Element.encodeValue(elementList));
+    sequenceElement = e.decodeAsSequence();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), sequenceElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, sequenceElement.elements());
     }
   }
 
+
+
   /**
    * Tests the <CODE>decodeAsSet</CODE> method.
    *
-   * @throws Exception
-   *           If the test failed unexpectedly.
+   * @param  elements  The set of ASN.1 elements to use in the tests.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
    */
-  @Test()
-  public void testDecodeAsSet() throws Exception {
-    int numElementSets = testElementSets.size();
-    for (int i = 0; i < numElementSets; i++) {
-      ArrayList<ASN1Element> elementSet = testElementSets.get(i);
-      byte[] encodedElementSet = testEncodedElementSets.get(i);
-
-      ArrayList<ASN1Element> compareList;
-      if (elementSet == null) {
-        compareList = new ArrayList<ASN1Element>(0);
-      } else {
-        compareList = elementSet;
+  @Test(dataProvider = "elementArrays")
+  public void testDecodeAsSet(ASN1Element[] elements)
+         throws Exception
+  {
+    ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>();
+    if (elements == null)
+    {
+      elementList = null;
+    }
+    else
+    {
+      for (ASN1Element e : elements)
+      {
+        elementList.add(e);
       }
+    }
 
-      ASN1Element element = new ASN1Element((byte) 0x00, encodedElementSet);
 
-      assertTrue(listsAreEqual(compareList, element.decodeAsSet()
-          .elements()));
+    // First, make sure that we can decode actual set elements as set elements,
+    // using both the standard type as well as a nonstandard type.
+    ASN1Element e = new ASN1Set(elementList);
+    ASN1Set setElement = e.decodeAsSet();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), setElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, setElement.elements());
+    }
 
-      element = new ASN1Element((byte) 0x31, encodedElementSet);
+    e = new ASN1Set((byte) 0x50, elementList);
+    setElement = e.decodeAsSet();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), setElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, setElement.elements());
+    }
 
-      assertTrue(listsAreEqual(compareList, element.decodeAsSet()
-          .elements()));
+
+    // Next, make sure that we can decode a generic ASN.1 element as an octet
+    // string element.
+    e = new ASN1Element(ASN1Constants.UNIVERSAL_SET_TYPE,
+                        ASN1Element.encodeValue(elementList));
+    setElement = e.decodeAsSet();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), setElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, setElement.elements());
+    }
+
+    e = new ASN1Element((byte) 0x50, ASN1Element.encodeValue(elementList));
+    setElement = e.decodeAsSet();
+    if (elements == null)
+    {
+      assertEquals(new ArrayList<ASN1Element>(), setElement.elements());
+    }
+    else
+    {
+      assertEquals(elementList, setElement.elements());
     }
   }
 
+
+
   /**
-   * Tests the <CODE>equals</CODE> and <CODE>hashCode</CODE>
-   * methods.
+   * Tests the <CODE>equals</CODE>, <CODE>equalsElement</CODE>, and
+   * <CODE>equalsIgnoreType</CODE> methods.
+   *
+   * @param  value  The value to use in the test.
+   */
+  @Test(dataProvider = "testValues")
+  public void testEquals(byte[] value)
+  {
+    ASN1Element controlElement = new ASN1Element((byte) 0x00, value);
+
+    for (int i=0x00; i < 0xFF; i++)
+    {
+      ASN1Element e = new ASN1Element((byte) i, value);
+
+      if (i == 0x00)
+      {
+        assertTrue(controlElement.equals(e));
+        assertTrue(e.equals(controlElement));
+        assertTrue(controlElement.equalsElement(e));
+        assertTrue(e.equalsElement(controlElement));
+      }
+      else
+      {
+        assertFalse(controlElement.equals(e));
+        assertFalse(e.equals(controlElement));
+        assertFalse(controlElement.equalsElement(e));
+        assertFalse(e.equalsElement(controlElement));
+      }
+
+      assertTrue(e.equals(e));
+      assertTrue(e.equalsElement(e));
+      assertTrue(e.equalsIgnoreType(e));
+      assertTrue(e.equalsIgnoreType((ByteString) new ASN1OctetString(value)));
+      assertTrue(controlElement.equalsIgnoreType(e));
+      assertTrue(e.equalsIgnoreType(controlElement));
+      assertFalse(e.equals(null));
+      assertFalse(e.equals("notanelement"));
+    }
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array argument with an
+   * invalid element that is too short to be valid.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeShortElement1()
+         throws Exception
+  {
+    ASN1Element.decode(new byte[1]);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array and two integer
+   * arguments with an invalid element that is too short to be valid.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeShortElement2()
+         throws Exception
+  {
+    ASN1Element.decode(new byte[1], 0, 1);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array argument with a null
+   * element.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeNull1()
+         throws Exception
+  {
+    ASN1Element.decode(null);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array and two integer
+   * arguments with a null element.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeNull2()
+         throws Exception
+  {
+    ASN1Element.decode(null, 0, 0);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array argument with an
+   * element indicating that it takes more than four bytes to describe the
+   * length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLongLength1()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x85,
+      0x00,
+      0x00,
+      0x00,
+      0x00,
+      0x00
+    };
+
+    ASN1Element.decode(elementBytes);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array and two integer
+   * arguments with an indicating that it takes more than four bytes to describe
+   * the length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLongLength2()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x85,
+      0x00,
+      0x00,
+      0x00,
+      0x00,
+      0x00
+    };
+
+    ASN1Element.decode(elementBytes, 0, elementBytes.length);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array argument with an
+   * element that isn't long enough to fully decode the length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeTruncatedLength1()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x82,
+      0x00
+   };
+
+    ASN1Element.decode(elementBytes);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array and two integer
+   * arguments with an element that isn't long enough to fully decode the
+   * length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeTruncatedLength2()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x82,
+      0x00
+   };
+
+    ASN1Element.decode(elementBytes, 0, elementBytes.length);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array argument with an
+   * element whose decoded length doesn't match the number of bytes remaining.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLengthMismatch1()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      0x01,
+      0x00,
+      0x00
+   };
+
+    ASN1Element.decode(elementBytes);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decode</CODE> method taking an array and two integer
+   * arguments with an element whose decoded length doesn't match the number of
+   * bytes remaining.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeLengthMismatch2()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      0x01,
+      0x00,
+      0x00
+   };
+
+    ASN1Element.decode(elementBytes, 0, elementBytes.length);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeElements</CODE> method taking an array with a null
+   * array.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeElementsNull()
+         throws Exception
+  {
+    ASN1Element.decodeElements(null);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeElements</CODE> method taking an array with an array
+   * containing an element with too many bytes used to describe the length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeElementsLongLength()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x85,
+      0x00,
+      0x00,
+      0x00,
+      0x00,
+      0x00
+    };
+
+    ASN1Element.decodeElements(elementBytes);
+  }
+
+
+
+  /**
+   * Tests the <CODE>decodeElements</CODE> method taking an array with an array
+   * containing an element without enough bytes to fully decode the length.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = { ASN1Exception.class })
+  public void testDecodeElementsTruncatedLength()
+         throws Exception
+  {
+    byte[] elementBytes =
+    {
+      0x04,
+      (byte) 0x82,
+      0x00,
+    };
+
+    ASN1Element.decodeElements(elementBytes);
+  }
+
+
+
+  /**
+   * Tests the <CODE>equalsElement</CODE> method taking an array with a null
+   * array.
+   *
+   * @throws  Exception  If the test failed unexpectedly.
    */
   @Test()
-  public void testEqualsAndHashCode() {
-    // Perform simple tests for two basic elements that should be the
-    // same, one
-    // that should differ in type, one that should differ in value, and
-    // one that
-    // should differ in both.
-    ASN1Element e1 = new ASN1Element((byte) 0x00);
-    ASN1Element e2 = new ASN1Element((byte) 0x00, new byte[0]);
-    ASN1Element e3 = new ASN1Element((byte) 0x01);
-    ASN1Element e4 = new ASN1Element((byte) 0x00,
-        new byte[] { (byte) 0x00 });
-    ASN1Element e5 = new ASN1Element((byte) 0x01,
-        new byte[] { (byte) 0x00 });
-    ASN1Element e6 = new ASN1Element((byte) 0x00,
-        new byte[] { (byte) 0x01 });
+  public void testEqualsElementNull()
+         throws Exception
+  {
+    ASN1Element e = new ASN1OctetString();
+    assertFalse(e.equalsElement(null));
+  }
 
-    assertTrue(e1.equals(e2)); // Basic equality test.
 
-    assertTrue(e2.equals(e1)); // Reflexive equality test.
 
-    assertFalse(e1.equals(e3)); // Difference in type.
-
-    assertFalse(e1.equals(e4)); // Difference in value.
-
-    assertFalse(e1.equals(e5)); // Differences in type and value.
-
-    assertFalse(e4.equals(e6)); // Difference in values with the same
-    // length.
-
-    // Make sure that equal elements have equal hash codes.
-    assertEquals(e1.hashCode(), e2.hashCode()); // Hash code equality
-    // test.
-
-    // Test equals against a null element.
-    assertFalse(e1.equals(null));
-
-    // Test boolean elements against equivalent generic elements.
-    ASN1Element trueElement = new ASN1Element((byte) 0x01,
-        new byte[] { (byte) 0xFF });
-    ASN1Element falseElement = new ASN1Element((byte) 0x01,
-        new byte[] { (byte) 0x00 });
-    ASN1Boolean trueBoolean = new ASN1Boolean(true);
-    ASN1Boolean falseBoolean = new ASN1Boolean(false);
-
-    assertTrue(trueElement.equals(trueBoolean));
-
-    assertTrue(trueBoolean.equals(trueElement));
-
-    assertEquals(trueElement.hashCode(), trueBoolean.hashCode());
-
-    assertTrue(falseElement.equals(falseBoolean));
-
-    assertTrue(falseBoolean.equals(falseElement));
-
-    assertEquals(falseElement.hashCode(), falseBoolean.hashCode());
-
-    // Test integer elements against equivalent generic elements.
-    int numIntegers = testIntegers.size();
-    for (int i = 0; i < numIntegers; i++) {
-      int intValue = testIntegers.get(i);
-      byte[] encodedIntValue = testEncodedIntegers.get(i);
-
-      ASN1Element genericElement = new ASN1Element((byte) 0x02,
-          encodedIntValue);
-      ASN1Integer integerElement = new ASN1Integer(intValue);
-
-      assertTrue(genericElement.equals(integerElement));
-
-      assertTrue(integerElement.equals(genericElement)); // Reflexive
-      // test.
-
-      // Test for matching hash codes.
-      assertEquals(genericElement.hashCode(), integerElement.hashCode());
+  /**
+   * Tests miscellaneous methods, including <CODE>toString</CODE> and
+   * <CODE>getProtocolElementName</CODE> that don't fit in anywhere else.
+   *
+   * @param  value  The value to use in the test.
+   */
+  @Test(dataProvider = "testValues")
+  public void testMiscellaneous(byte[] value)
+  {
+    for (int i=0x00; i < 0xFF; i++)
+    {
+      byte type = (byte) i;
+      ASN1Element e = new ASN1Element(type, value);
+      e.toString();
+      e.toString(new StringBuilder());
+      e.toString(new StringBuilder(), 1);
+      assertEquals("ASN.1", e.getProtocolElementName());
     }
   }
 }
+

--
Gitblit v1.10.0