// Copyright (c) 2003 Dustin Sallings <dustin@spy.net> package net.spy.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Base64 test. Derived from the python base64 tests. */ public class Base64Test extends TestCase { private static final String CHARSET="UTF-8"; private Map<String, String> cases=null; /** * Get an instance of Base64Test. */ public Base64Test(String name) { super(name); } /** * Get the test suite. */ public static Test suite() { return new TestSuite(Base64Test.class); } @Override protected void setUp() { cases=new HashMap<String, String>(); cases.put("d3d3LnB5dGhvbi5vcmc=", "www.python.org"); cases.put("YQ==", "a"); cases.put("YWI=", "ab"); cases.put("YWJj", "abc"); cases.put("", ""); cases.put("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQ" + "kNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\r\n" + "NTY3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789!@#0^&*();:<>,. []{}"); } /** * Test the singleton semantics. */ public void testSingleton() { assertSame(Base64.getInstance(), Base64.getInstance()); } private String encode(String s) throws Exception { Base64 b64=Base64.getInstance(); String rv=b64.encode(s.getBytes(CHARSET)); return(rv); } /** * Test base64 encoding of strings. */ @SuppressWarnings("unchecked") public void testEncode() throws Exception { for(Iterator i=cases.entrySet().iterator(); i.hasNext();) { Map.Entry me=(Map.Entry)i.next(); assertEquals("Encode " + me.getValue(), me.getKey(), encode((String)me.getValue())); } } private String decode(String s) throws Exception { Base64 b64=Base64.getInstance(); return(new String(b64.decode(s), CHARSET)); } /** * Test base64 decodes. */ @SuppressWarnings("unchecked") public void testDecode() throws Exception { for(Iterator i=cases.entrySet().iterator(); i.hasNext();) { Map.Entry me=(Map.Entry)i.next(); assertEquals("Decode " + me.getKey(), me.getValue(), decode((String)me.getKey())); } } /** * Test the isValidBase64Char implementation. */ @SuppressWarnings("unchecked") public void testAlphabet() { Base64 b64=Base64.getInstance(); char[] CHARMAP={ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; Map<Character, Boolean> allChars=new HashMap<Character, Boolean>(); for(int i=0; i<65535; i++) { allChars.put( new Character((char)i), Boolean.FALSE); } for(int i=0; i<CHARMAP.length; i++) { allChars.put(new Character(CHARMAP[i]), Boolean.TRUE); } for(Iterator i=allChars.entrySet().iterator(); i.hasNext();) { Map.Entry me=(Map.Entry)i.next(); assertEquals(((Boolean)me.getValue()).booleanValue(), b64.isValidBase64Char(((Character)me.getKey()).charValue())); } } /** * Test output stream implementation. */ @SuppressWarnings("unchecked") public void testOutputStream() throws Exception { ByteArrayOutputStream bos=new ByteArrayOutputStream(); for(Iterator i=cases.entrySet().iterator(); i.hasNext();) { Map.Entry me=(Map.Entry)i.next(); bos.reset(); Base64OutputStream b64os=new Base64OutputStream(bos); b64os.write(((String)me.getValue()).getBytes(CHARSET)); b64os.close(); String result=new String(bos.toByteArray(), CHARSET); // The stream adds a newline to everything that doesn't end in a // newline. String expected=me.getKey() + "\r\n"; if(((String)me.getKey()).length() % 76 == 0) { expected=(String)me.getKey(); } assertEquals("Stream Encode ``" + expected + "'' got ``" + result + "''", expected, result); } bos.close(); } /** * Test input stream implementation. */ @SuppressWarnings("unchecked") public void testInputStream() throws Exception { byte[] buffer=new byte[1024]; for(Iterator i=cases.entrySet().iterator(); i.hasNext();) { Map.Entry me=(Map.Entry)i.next(); byte[] input=((String)me.getKey()).getBytes(CHARSET); ByteArrayInputStream bis=new ByteArrayInputStream(input); Base64InputStream b64is=new Base64InputStream(bis); assertFalse(b64is.markSupported()); int expectedAvailable=input.length * 3 / 4; assertEquals("available() failed for ``" + me.getKey() + "''", expectedAvailable, b64is.available()); int bytesread=b64is.read(buffer, 0, buffer.length); b64is.close(); String result=new String(buffer, 0, bytesread); String expected=(String)me.getValue(); assertEquals("Stream decode ``" + expected + "'' got ``" + result + "''", expected, result); } } /** * Test that streaming base64 yields the same result as whole chunk * encoding. */ @SuppressWarnings("unchecked") public void testBlockOutput() throws Exception { HashMap<String, Comparable> hm=new HashMap<String, Comparable>(); hm.put("Some Key", new Integer(13)); hm.put("Some Other Key", "Another value"); ByteArrayOutputStream bos1=new ByteArrayOutputStream(); Base64OutputStream b64os=new Base64OutputStream(bos1); ObjectOutputStream oos1=new ObjectOutputStream(b64os); oos1.writeObject(hm); oos1.close(); b64os.close(); bos1.close(); String encoded1=new String(bos1.toByteArray()); ByteArrayOutputStream bos2=new ByteArrayOutputStream(); ObjectOutputStream oos2=new ObjectOutputStream(bos2); oos2.writeObject(hm); oos2.close(); bos2.close(); String encoded2=Base64.getInstance().encode(bos2.toByteArray()); assertEquals(encoded2.trim(), encoded1.trim()); } /** * Test that streaming base64 in yields the same result as whole chunk * decoding. */ @SuppressWarnings("unchecked") public void testBlockInput() throws Exception { HashMap<String, Comparable> hm=new HashMap<String, Comparable>(); hm.put("Some Key", new Integer(13)); hm.put("Some Other Key", "Another value"); // This will produce our seed data. ByteArrayOutputStream bos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(hm); String src=Base64.getInstance().encode(bos.toByteArray()); byte[] b1=Base64.getInstance().decode(src); ByteArrayInputStream bis=new ByteArrayInputStream( src.getBytes(CHARSET)); Base64InputStream b64is=new Base64InputStream(bis); byte[] b2=new byte[b1.length]; int bytesRead=b64is.read(b2); assertEquals(b1.length, bytesRead); for(int i=0; i<bytesRead; i++) { assertEquals("Differs at " + i, b1[i], b2[i]); } } /** * Test object serialization and compression and all that into base64. * This particular case failed in the field. */ @SuppressWarnings("unchecked") public void testSerializingStream() throws Exception { ByteArrayOutputStream bos=new ByteArrayOutputStream(); Base64OutputStream b64os=new Base64OutputStream(bos); GZIPOutputStream gzos=new GZIPOutputStream(b64os); ObjectOutputStream oos=new ObjectOutputStream(gzos); HashMap<String, Comparable> hm=new HashMap<String, Comparable>(); hm.put("Some Key", new Integer(13)); hm.put("Some Other Key", "Another value"); oos.writeObject(hm); oos.close(); gzos.close(); b64os.close(); bos.close(); String encoded=new String(bos.toByteArray()); // Now try to pull them back ByteArrayInputStream bis=new ByteArrayInputStream( encoded.getBytes(CHARSET)); Base64InputStream b64is=new Base64InputStream(bis); GZIPInputStream gzis=new GZIPInputStream(b64is); ObjectInputStream ois=new ObjectInputStream(gzis); HashMap readMap=(HashMap)ois.readObject(); ois.close(); gzis.close(); b64is.close(); bis.close(); assertEquals(hm, readMap); } }