package org.bouncycastle.util.encoders.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import junit.framework.TestCase;
import org.bouncycastle.util.encoders.Encoder;
public abstract class AbstractCoderTest extends TestCase
{
private static final int[] SIZES_TO_CHECK = {64, 128, 1024, 1025, 1026, 2048,
2049, 2050, 4096, 4097, 4098, 8192, 8193, 8194};
protected Encoder enc;
private Random r;
AbstractCoderTest(
String name)
{
super(name);
}
protected void setUp()
{
r = new Random();
}
private void checkArrayOfSize(int size)
throws IOException
{
byte[] original = new byte[size];
r.nextBytes(original);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
enc.encode(original, 0, original.length, bOut);
byte[] encoded = bOut.toByteArray();
assertTrue(encoded.length > original.length);
assertTrue(encoded.length <= (original.length * 2));
checkEncoding(encoded);
checkSimpleDecode(original, encoded);
checkStringDecode(original, encoded);
checkOutputStreamDecode(original, encoded);
int offset = r.nextInt(20);
byte[] offsetEncoded = new byte[offset + encoded.length];
System.arraycopy(encoded, 0, offsetEncoded, offset, encoded.length);
checkOffsetDecode(original, offsetEncoded, offset, encoded.length);
offset = r.nextInt(20);
byte[] offsetOriginal = new byte[offset + original.length];
System.arraycopy(original, 0, offsetOriginal, offset, original.length);
checkOffsetEncode(original, offsetOriginal, offset, original.length);
byte[] encodedWithSpace = addWhitespace(encoded);
checkSimpleDecode(original, encodedWithSpace);
checkStringDecode(original, encodedWithSpace);
checkOutputStreamDecode(original, encodedWithSpace);
}
public void testEncode()
throws IOException
{
for (int i = 0; i < SIZES_TO_CHECK.length; i++)
{
checkArrayOfSize(SIZES_TO_CHECK[i]);
}
}
private void checkEncoding(byte[] encoded)
{
String encString = convertBytesToString(encoded);
for (int i = 0; i < encString.length(); i++)
{
char c = encString.charAt(i);
if (c == paddingChar())
{
// should only be padding at end of string
assertTrue(i > encString.length() - 3);
continue;
}
else if (isEncodedChar(c))
{
continue;
}
fail("Unexpected encoded character " + c);
}
}
private void checkOutputStreamDecode(byte[] original, byte[] encoded)
{
String encString = convertBytesToString(encoded);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try
{
assertEquals(original.length, enc.decode(encString, out));
assertTrue(Arrays.equals(original, out.toByteArray()));
}
catch (IOException e)
{
fail("This shouldn't happen");
}
}
private void checkSimpleDecode(byte[] original, byte[] encoded)
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
enc.decode(encoded, 0, encoded.length, bOut);
assertTrue(Arrays.equals(original, bOut.toByteArray()));
}
private void checkOffsetEncode(byte[] original, byte[] offsetOriginal, int off, int length)
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
enc.encode(offsetOriginal, off, length, bOut);
byte[] encoded = bOut.toByteArray();
bOut.reset();
enc.decode(encoded, 0, encoded.length, bOut);
assertTrue(Arrays.equals(original, bOut.toByteArray()));
}
private void checkOffsetDecode(byte[] original, byte[] encoded, int off, int length)
throws IOException
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
enc.decode(encoded, off, length, bOut);
assertTrue(Arrays.equals(original, bOut.toByteArray()));
}
private void checkStringDecode(byte[] original, byte[] encoded)
throws IOException
{
String encString = convertBytesToString(encoded);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
enc.decode(encString, bOut);
assertTrue(Arrays.equals(original, bOut.toByteArray()));
}
private byte[] addWhitespace(byte[] encoded)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
addSpace(out);
for (int i = 0; i < encoded.length - 5; i++)
{
out.write(encoded, i, 1);
if (r.nextInt(100) < 5)
{
addSpace(out);
}
}
for (int i = encoded.length - 5; i < encoded.length; i++)
{
out.write(encoded, i, 1);
}
addSpace(out);
return out.toByteArray();
}
private void addSpace(ByteArrayOutputStream out)
{
do
{
switch (r.nextInt(3))
{
case 0 :
out.write((int) '\n');
break;
case 1 :
out.write((int) '\r');
break;
case 2 :
out.write((int) '\t');
break;
case 3 :
out.write((int) ' ');
break;
}
} while (r.nextBoolean());
}
private String convertBytesToString(byte[] encoded)
{
StringBuffer b = new StringBuffer();
for (int i = 0; i != encoded.length; i++)
{
b.append((char)(encoded[i] & 0xff));
}
return b.toString();
}
abstract protected char paddingChar();
abstract protected boolean isEncodedChar(char c);
}