/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.protocols.asn1;
import org.opends.server.DirectoryServerTestCase;
import static org.opends.server.protocols.asn1.ASN1Constants.*;
import org.opends.server.util.StaticUtils;
import org.opends.server.types.ByteString;
import org.opends.server.types.ByteStringBuilder;
import org.testng.annotations.Test;
import org.testng.annotations.DataProvider;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
import java.io.IOException;
/**
* An abstract base class for all ASN1Writer test cases.
*/
@Test(groups = { "precommit", "asn1" }, sequential = true)
public abstract class ASN1WriterTestCase extends DirectoryServerTestCase {
// 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.
private byte[] testTypes = new byte[0xFF];
{
for (int i=0x00; i < 0xFF; i++)
{
testTypes[i] = (byte) (i & 0xFF);
}
}
/**
* Retrieves the set of boolean values that may be used for testing.
*
* @return The set of boolean values that may be used for testing.
*/
@DataProvider(name = "booleanValues")
public Object[][] getBooleanValues()
{
return new Object[][]
{
new Object[] { false },
new Object[] { true }
};
}
/**
* Retrieves the set of int values that should be used for testing.
*
* @return The set of int values that should be used for testing.
*/
@DataProvider(name = "intValues")
public Object[][] getIntValues()
{
return new Object[][]
{
new Object[] { 0x00000000, 1 },
new Object[] { 0x00000001, 1 },
new Object[] { 0x0000000F, 1 },
new Object[] { 0x00000010, 1 },
new Object[] { 0x0000007F, 1 },
new Object[] { 0x00000080, 2 },
new Object[] { 0x000000FF, 2 },
new Object[] { 0x00000100, 2 },
new Object[] { 0x00000FFF, 2 },
new Object[] { 0x00001000, 2 },
new Object[] { 0x0000FFFF, 3 },
new Object[] { 0x00010000, 3 },
new Object[] { 0x000FFFFF, 3 },
new Object[] { 0x00100000, 3 },
new Object[] { 0x00FFFFFF, 4 },
new Object[] { 0x01000000, 4 },
new Object[] { 0x0FFFFFFF, 4 },
new Object[] { 0x10000000, 4 },
new Object[] { 0x7FFFFFFF, 4 },
new Object[] { -0x00000001, 1 },
new Object[] { -0x0000000F, 1 },
new Object[] { -0x00000010, 1 },
new Object[] { -0x0000007F, 1 },
new Object[] { -0x00000080, 1 },
new Object[] { -0x000000FF, 2 },
new Object[] { -0x00000100, 2 },
new Object[] { -0x00000FFF, 2 },
new Object[] { -0x00001000, 2 },
new Object[] { -0x0000FFFF, 3 },
new Object[] { -0x00010000, 3 },
new Object[] { -0x000FFFFF, 3 },
new Object[] { -0x00100000, 3 },
new Object[] { -0x00FFFFFF, 4 },
new Object[] { -0x01000000, 4 },
new Object[] { -0x0FFFFFFF, 4 },
new Object[] { -0x10000000, 4 },
new Object[] { -0x7FFFFFFF, 4 },
new Object[] { 0x80000000, 4 }
};
}
/**
* Retrieves the set of long values that should be used for testing.
*
* @return The set of long values that should be used for testing.
*/
@DataProvider(name = "longValues")
public Object[][] getLongValues()
{
return new Object[][]
{
new Object[] { 0x0000000000000000L, 1 },
new Object[] { 0x0000000000000001L, 1 },
new Object[] { 0x000000000000007FL, 1 },
new Object[] { 0x0000000000000080L, 2 },
new Object[] { 0x00000000000000FFL, 2 },
new Object[] { 0x0000000000000100L, 2 },
new Object[] { 0x000000000000FFFFL, 3 },
new Object[] { 0x0000000000010000L, 3 },
new Object[] { 0x0000000000FFFFFFL, 4 },
new Object[] { 0x0000000001000000L, 4 },
new Object[] { 0x00000000FFFFFFFFL, 5 },
new Object[] { 0x0000000100000000L, 5 },
new Object[] { 0x000000FFFFFFFFFFL, 6 },
new Object[] { 0x0000010000000000L, 6 },
new Object[] { 0x0000FFFFFFFFFFFFL, 7 },
new Object[] { 0x0001000000000000L, 7 },
new Object[] { 0x00FFFFFFFFFFFFFFL, 8 },
new Object[] { 0x0100000000000000L, 8 },
new Object[] { 0x7FFFFFFFFFFFFFFFL, 8 },
new Object[] { -0x0000000000000001L, 1 },
new Object[] { -0x000000000000007FL, 1 },
new Object[] { -0x0000000000000080L, 1 },
new Object[] { -0x00000000000000FFL, 2 },
new Object[] { -0x0000000000000100L, 2 },
new Object[] { -0x000000000000FFFFL, 3 },
new Object[] { -0x0000000000010000L, 3 },
new Object[] { -0x0000000000FFFFFFL, 4 },
new Object[] { -0x0000000001000000L, 4 },
new Object[] { -0x00000000FFFFFFFFL, 5 },
new Object[] { -0x0000000100000000L, 5 },
new Object[] { -0x000000FFFFFFFFFFL, 6 },
new Object[] { -0x0000010000000000L, 6 },
new Object[] { -0x0000FFFFFFFFFFFFL, 7 },
new Object[] { -0x0001000000000000L, 7 },
new Object[] { -0x00FFFFFFFFFFFFFFL, 8 },
new Object[] { -0x0100000000000000L, 8 },
new Object[] { -0x7FFFFFFFFFFFFFFFL, 8 },
new Object[] { 0x8000000000000000L, 8 }
};
}
/**
* Create byte arrays to use for element values.
*
* @return A list of byte arrays that can be used as element values.
*/
@DataProvider(name = "binaryValues")
public Object[][] getBinaryValues()
{
// NOTE -- Don't make these arrays too big since they consume memory.
return new Object[][]
{
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
};
}
/**
* Create strings to use for element values.
*
* @return A list of strings that can be used as element values.
*
* @throws Exception If an unexpected problem occurs.
*/
@DataProvider(name = "stringValues")
public Object[][] getStringValues()
throws Exception
{
return new Object[][]
{
new Object[] { null },
new Object[] { "" },
new Object[] { "\u0000" },
new Object[] { "\t" },
new Object[] { "\n" },
new Object[] { "\r\n" },
new Object[] { " " },
new Object[] { "a" },
new Object[] { "Test1\tTest2\tTest3" },
new Object[] { "Test1\nTest2\nTest3" },
new Object[] { "Test1\r\nTest2\r\nTest3" },
new Object[] { "The Quick Brown Fox Jumps Over The Lazy Dog" },
new Object[] { "\u00BFD\u00F3nde est\u00E1 el ba\u00F1o?" }
};
}
abstract ASN1Writer getWriter() throws IOException;
abstract ASN1Reader getReader(byte[] encodedBytes) throws ASN1Exception, IOException;
abstract byte[] getEncodedBytes() throws IOException, ASN1Exception;
/**
* Tests the <CODE>write/readBoolean</CODE> methods.
*
* @param b The boolean value to use in the test.
*/
@Test(dataProvider = "booleanValues")
public void testEncodeDecodeBoolean(boolean b) throws Exception
{
getWriter().writeBoolean(b);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), 1);
assertEquals(r.peekType(), UNIVERSAL_BOOLEAN_TYPE);
assertEquals(r.readBoolean(), b);
}
/**
* Tests the <CODE>write/readBoolean</CODE> methods.
*
* @param b The boolean value to use in the test.
*/
@Test(dataProvider = "booleanValues")
public void testEncodeDecodeBooleanType(boolean b) throws Exception
{
for(byte type : testTypes)
{
getWriter().writeBoolean(type, b);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), 1);
assertEquals(r.peekType(), type);
assertEquals(r.readBoolean(), b);
}
}
/**
* Tests the <CODE>write/readInteger</CODE> methods with Java ints.
*
* @param i The integer value to use for the test.
*/
@Test(dataProvider = "intValues")
public void testEncodeDecodeEnuerated(int i, int length) throws Exception
{
getWriter().writeEnumerated(i);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), length);
assertEquals(r.peekType(), UNIVERSAL_ENUMERATED_TYPE);
assertEquals(r.readInteger(), i);
}
/**
* Tests that negative integers are encoded according
* to ASN.1 BER specification.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testNegativeIntEncoding()
throws Exception
{
// Some negative integers of interest
// to test specific ranges/boundaries.
getWriter().writeInteger(-1);
byte[] value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
getWriter().writeInteger(-2);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFE);
getWriter().writeInteger(-127);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x81);
getWriter().writeInteger(-128);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
getWriter().writeInteger(-255);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x01);
getWriter().writeInteger(-256);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
getWriter().writeInteger(-65535);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x01);
getWriter().writeInteger(-65536);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
getWriter().writeInteger(-2147483647);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
assertEquals(value[5], (byte) 0x01);
getWriter().writeInteger(-2147483648);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
assertEquals(value[5], (byte) 0x00);
}
/**
* Tests that negative integers are encoded according
* to ASN.1 BER specification.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testNegativeLongEncoding()
throws Exception
{
// Some negative integers of interest
// to test specific ranges/boundaries.
getWriter().writeInteger(-1L);
byte[] value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
getWriter().writeInteger(-2L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFE);
getWriter().writeInteger(-127L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x81);
getWriter().writeInteger(-128L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
getWriter().writeInteger(-255L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x01);
getWriter().writeInteger(-256L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
getWriter().writeInteger(-65535L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x01);
getWriter().writeInteger(-65536L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0xFF);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
getWriter().writeInteger(-2147483647L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
assertEquals(value[5], (byte) 0x01);
getWriter().writeInteger(-2147483648L);
value = getEncodedBytes();
assertEquals(value[2], (byte) 0x80);
assertEquals(value[3], (byte) 0x00);
assertEquals(value[4], (byte) 0x00);
assertEquals(value[5], (byte) 0x00);
}
/**
* Tests the <CODE>write/readInteger</CODE> methods with Java ints.
*
* @param i The integer value to use for the test.
*/
@Test(dataProvider = "intValues")
public void testEncodeDecodeInteger(int i, int length) throws Exception
{
getWriter().writeInteger(i);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), length);
assertEquals(r.peekType(), UNIVERSAL_INTEGER_TYPE);
assertEquals(r.readInteger(), i);
}
/**
* Tests the <CODE>write/readInteger</CODE> methods with Java ints.
*
* @param i The integer value to use for the test.
*/
@Test(dataProvider = "intValues")
public void testEncodeDecodeIntegerType(int i, int length) throws Exception
{
for(byte type : testTypes)
{
getWriter().writeInteger(type, i);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), length);
assertEquals(r.peekType(), type);
assertEquals(r.readInteger(), i);
}
}
/**
* Tests the <CODE>write/readInteger</CODE> methods with Java longs.
*
* @param l The long value to use for the test.
*/
@Test(dataProvider = "longValues")
public void testEncodeDecodeInteger(long l, int length) throws Exception
{
getWriter().writeInteger(l);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), length);
assertEquals(r.peekType(), UNIVERSAL_INTEGER_TYPE);
assertEquals(r.readInteger(), l);
}
/**
* Tests the <CODE>write/readInteger</CODE> methods wiht JavaLongs.
*
* @param l The long value to use for the test.
*/
@Test(dataProvider = "longValues")
public void testEncodeDecodeIntegerType(long l, int length) throws Exception
{
for(byte type : testTypes)
{
getWriter().writeInteger(type, l);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), length);
assertEquals(r.peekType(), type);
assertEquals(r.readInteger(), l);
}
}
/**
* Tests the <CODE>write/readNull</CODE> methods.
*/
@Test
public void testEncodeDecodeNull() throws Exception
{
getWriter().writeNull();
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), 0);
assertEquals(r.peekType(), UNIVERSAL_NULL_TYPE);
r.readNull();
}
/**
* Tests the <CODE>write/readNull</CODE> methods.
*/
@Test
public void testEncodeDecodeNullType() throws Exception
{
for(byte type : testTypes)
{
getWriter().writeNull(type);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), 0);
assertEquals(r.peekType(), type);
r.readNull();
}
}
/**
* Tests the <CODE>write/readOctetString</CODE> methods.
*/
@Test
public void testEncodeDecodeOctetStringOffLen() throws Exception
{
byte[] b = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
for(int i = 0; i < 5; i+=2)
{
byte[] bsb = new byte[3];
System.arraycopy(b, i, bsb, 0, 3);
ByteString bs = ByteString.wrap(bsb);
getWriter().writeOctetString(b, i, 3);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), 3);
assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
assertTrue(bs.equals(r.readOctetString()));
}
}
/**
* Tests the <CODE>write/readOctetString</CODE> methods.
*/
@Test(dataProvider = "binaryValues")
public void testEncodeDecodeOctetString(byte[] b) throws Exception
{
ByteString bs = ByteString.wrap(b);
getWriter().writeOctetString(bs);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), b.length);
assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
assertTrue(bs.equals(r.readOctetString()));
getWriter().writeOctetString(b, 0, b.length);
r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), b.length);
assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
assertTrue(bs.equals(r.readOctetString()));
}
/**
* Tests the <CODE>write/readOctetString</CODE> methods.
*/
@Test(dataProvider = "binaryValues")
public void testEncodeDecodeOctetStringType(byte[] b) throws Exception
{
ByteString bs = ByteString.wrap(b);
ByteStringBuilder bsb = new ByteStringBuilder();
for(byte type : testTypes)
{
bsb.clear();
getWriter().writeOctetString(type, bs);
ASN1Reader r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), b.length);
assertEquals(r.peekType(), type);
r.readOctetString(bsb);
assertTrue(bs.equals(bsb));
bsb.clear();
getWriter().writeOctetString(type, b, 0, b.length);
r = getReader(getEncodedBytes());
assertEquals(r.peekLength(), b.length);
assertEquals(r.peekType(), type);
r.readOctetString(bsb);
assertTrue(bs.equals(bsb));
}
}
/**
* Tests the <CODE>write/readOctetString</CODE> methods.
*/
@Test(dataProvider = "stringValues")
public void testEncodeDecodeOctetString(String s) throws Exception
{
getWriter().writeOctetString(s);
ASN1Reader r = getReader(getEncodedBytes());
if(s == null)
{
assertEquals(r.peekLength(), 0);
}
else
{
assertEquals(r.peekLength(), StaticUtils.getBytes(s).length);
}
assertEquals(r.peekType(), UNIVERSAL_OCTET_STRING_TYPE);
if(s == null)
{
assertTrue(r.readOctetStringAsString("UTF-8").equals(""));
}
else
{
assertTrue(s.equals(r.readOctetStringAsString("UTF-8")));
}
}
/**
* Tests the <CODE>write/readOctetString</CODE> methods.
*/
@Test(dataProvider = "stringValues")
public void testEncodeDecodeOctetStringType(String s) throws Exception
{
for(byte type : testTypes)
{
getWriter().writeOctetString(type, s);
ASN1Reader r = getReader(getEncodedBytes());
if(s == null)
{
assertEquals(r.peekLength(), 0);
}
else
{
assertEquals(r.peekLength(), StaticUtils.getBytes(s).length);
}
assertEquals(r.peekType(), type);
if(s == null)
{
assertTrue(r.readOctetStringAsString("UTF-8").equals(""));
}
else
{
assertTrue(s.equals(r.readOctetStringAsString("UTF-8")));
}
}
}
@Test
public void testEncodeDecodeSequence() throws Exception
{
ASN1Writer writer = getWriter();
writer.writeStartSequence();
writer.writeBoolean(true);
writer.writeBoolean(false);
writer.writeInteger(0);
writer.writeInteger(10L);
writer.writeNull();
writer.writeOctetString("test value");
writer.writeOctetString("skip value");
writer.writeStartSequence();
writer.writeOctetString("nested sequence");
writer.writeEndSequence();
writer.writeStartSet();
writer.writeOctetString("nested set");
writer.writeEndSet();
writer.writeEndSequence();
ASN1Reader reader = getReader(getEncodedBytes());
assertEquals(reader.peekType(), UNIVERSAL_SEQUENCE_TYPE);
assertEquals(reader.peekLength(), 71);
assertTrue(reader.hasNextElement());
reader.readStartSequence();
assertTrue(reader.hasNextElement());
assertEquals(true, reader.readBoolean());
assertEquals(false, reader.readBoolean());
assertEquals(0, reader.readInteger());
assertEquals(10, reader.readInteger());
reader.readNull();
assertEquals("test value", reader.readOctetStringAsString());
reader.skipElement();
assertEquals(reader.peekLength(), 17);
assertEquals(reader.peekType(), UNIVERSAL_SEQUENCE_TYPE);
reader.readStartSequence();
assertEquals("nested sequence", reader.readOctetStringAsString());
reader.readEndSequence();
assertEquals(reader.peekLength(), 12);
assertEquals(reader.peekType(), UNIVERSAL_SET_TYPE);
reader.readStartSequence();
assertEquals("nested set", reader.readOctetStringAsString());
reader.readEndSequence();
assertFalse(reader.hasNextElement());
reader.readEndSequence();
assertFalse(reader.elementAvailable());
}
}