package org.springframework.crypto.digest; import junit.framework.TestCase; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * @author Rob Harrop */ public class MessageDigestTemplateTests extends TestCase { private static final String TEST_DATA = "The quick brown fox jumped over the lazy dog"; public void testDigestWithClone() throws Exception { MessageDigest md = getDigest(); byte[] input = TEST_DATA.getBytes(); md.update(input); byte[] desiredOutput = md.digest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(getDigest()); template.afterPropertiesSet(); byte[] actualOutput = template.digest(TEST_DATA.getBytes()); assertTrue("Output is incorrect", Arrays.equals(desiredOutput, actualOutput)); } public void testNonCloneableDigest() throws Exception { NonCloneableDigest md = new NonCloneableDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); byte[] input = TEST_DATA.getBytes(); byte[] output = template.digest(input); assertTrue("Reset method wasn't invoked.", md.isResetCalled()); } public void testCallbackWithCloneable() throws Exception { final MessageDigest md = getDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); Boolean called = (Boolean) template.execute(new MessageDigestCallback() { public Object doWithMessageDigest(MessageDigest messageDigest) { assertTrue("Should have different instances of MessageDigest", md != messageDigest); return Boolean.TRUE; } }); assertTrue("execute() was not called.", called.booleanValue()); } public void testCallbackWithNonCloneable() throws Exception { final NonCloneableDigest md = new NonCloneableDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); Boolean called = (Boolean) template.execute(new MessageDigestCallback() { public Object doWithMessageDigest(MessageDigest messageDigest) { assertTrue("Should have same instances of MessageDigest", md == messageDigest); return Boolean.TRUE; } }); assertTrue("execute() was not called.", called.booleanValue()); } public void testDigestString() throws Exception { MessageDigest md = getDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); md.update(TEST_DATA.getBytes()); byte[] desiredOutput = md.digest(); byte[] actualOutput = template.digest(TEST_DATA); assertTrue("Digest output incorrect.", Arrays.equals(desiredOutput, actualOutput)); } public void testDigestStringWithSpecificEncoding() throws Exception { String encoding = "ASCII"; MessageDigest md = getDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); md.update(TEST_DATA.getBytes(encoding)); byte[] desiredOutput = md.digest(); byte[] actualOutput = template.digest(TEST_DATA, encoding); assertTrue("Digest output incorrect.", Arrays.equals(desiredOutput, actualOutput)); } public void testInvalidEncoding() throws Exception { String encoding = "FOO"; MessageDigest md = getDigest(); MessageDigestTemplate template = new MessageDigestTemplate(); template.setMessageDigest(md); template.afterPropertiesSet(); try { byte[] bytes = template.digest(TEST_DATA, encoding); fail("Invalid encoding should throw IllegalArgumentException"); } catch(IllegalArgumentException ex) { // success } } private MessageDigest getDigest() throws NoSuchAlgorithmException { return MessageDigest.getInstance("SHA"); } private class NonCloneableDigest extends MessageDigest { public NonCloneableDigest() { super("SHA"); } protected NonCloneableDigest(String s) { super(s); } private boolean resetCalled = false; protected void engineUpdate(byte b) { } protected void engineUpdate(byte[] bytes, int i, int i1) { } protected byte[] engineDigest() { return new byte[0]; } protected void engineReset() { resetCalled = true; } public boolean isResetCalled() { return resetCalled; } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } } }