Home | History | Annotate | Download | only in security
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 /**
     19 * @author Vladimir N. Molotkov
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.tests.java.security;
     24 
     25 import java.io.ByteArrayOutputStream;
     26 import java.io.IOException;
     27 import java.io.OutputStream;
     28 import java.security.DigestOutputStream;
     29 import java.security.MessageDigest;
     30 import java.security.NoSuchAlgorithmException;
     31 import java.util.Arrays;
     32 import junit.framework.TestCase;
     33 import org.apache.harmony.security.tests.support.MDGoldenData;
     34 import org.apache.harmony.security.tests.support.MyMessageDigest1;
     35 import tests.support.Support_OutputStream;
     36 
     37 /**
     38  * Tests for fields and methods of class <code>DigestInputStream</code>
     39  *
     40  */
     41 public class DigestOutputStreamTest extends TestCase {
     42 
     43     /**
     44      * Message digest algorithm name used during testing
     45      */
     46     private static final String algorithmName[] = {
     47             "SHA-1",
     48             "SHA",
     49             "SHA1",
     50             "SHA-256",
     51             "SHA-384",
     52             "SHA-512",
     53             "MD5",
     54     };
     55     /**
     56      * Chunk size for read(byte, off, len) tests
     57      */
     58     private static final int CHUNK_SIZE = 32;
     59     /**
     60      * Test message for digest computations
     61      */
     62     private static final byte[] myMessage = MDGoldenData.getMessage();
     63     /**
     64      * The length of test message
     65      */
     66     private static final int MY_MESSAGE_LEN = myMessage.length;
     67 
     68     //
     69     // Tests
     70     //
     71 
     72     /**
     73      * java.security.DigestOutputStream#DigestOutputStream(java.io.OutputStream,
     74      *        java.security.MessageDigest)
     75      */
     76     public void test_CtorLjava_io_OutputStreamLjava_security_MessageDigest() {
     77 
     78         // non-null parameters
     79         MessageDigest md = new MyMessageDigest1();
     80         MyOutputStream out = new MyOutputStream();
     81 
     82         MyDigestOutputStream dos = new MyDigestOutputStream(out, md);
     83         assertSame(out, dos.myOutputStream());
     84         assertSame(md, dos.myMessageDigest());
     85 
     86         // null parameters
     87         dos = new MyDigestOutputStream(null, null);
     88         assertNull(dos.myOutputStream());
     89         assertNull(dos.myMessageDigest());
     90 
     91         dos = new MyDigestOutputStream(null, md);
     92         assertNull(dos.myOutputStream());
     93         assertNotNull(dos.myMessageDigest());
     94 
     95         dos = new MyDigestOutputStream(out, null);
     96         assertNotNull(dos.myOutputStream());
     97         assertNull(dos.myMessageDigest());
     98     }
     99 
    100     /**
    101      * java.security.DigestOutputStream#getMessageDigest()
    102      */
    103     public void test_getMessageDigest() {
    104 
    105         MessageDigest digest = new MyMessageDigest1();
    106         OutputStream out = new MyOutputStream();
    107 
    108         // non-null parameter
    109         DigestOutputStream dos = new DigestOutputStream(out, digest);
    110         assertSame(digest, dos.getMessageDigest());
    111 
    112         // null parameter
    113         dos = new DigestOutputStream(out, null);
    114         assertNull("getMessageDigest should have returned null", dos.getMessageDigest());
    115     }
    116 
    117     /**
    118      * java.security.DigestOutputStream#setMessageDigest(MessageDigest)
    119      */
    120     public void test_setMessageDigestLjava_security_MessageDigest() {
    121 
    122         MessageDigest digest = new MyMessageDigest1();
    123         OutputStream out = new MyOutputStream();
    124 
    125         DigestOutputStream dos = new DigestOutputStream(out, null);
    126 
    127         // non-null parameter
    128         dos.setMessageDigest(digest);
    129         assertSame(digest, dos.getMessageDigest());
    130 
    131         // null parameter
    132         dos.setMessageDigest(null);
    133         assertNull("getMessageDigest should have returned null", dos.getMessageDigest());
    134     }
    135 
    136 
    137     /**
    138      * Test #1 for <code>write(int)</code> method<br>
    139      *
    140      * Assertion: writes the byte to the output stream<br>
    141      * Assertion: updates associated digest<br>
    142      */
    143     public final void testWriteint01()
    144         throws IOException {
    145         for (int k=0; k<algorithmName.length; k++) {
    146             try {
    147                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    148                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    149                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    150                 for (int i=0; i<MY_MESSAGE_LEN; i++) {
    151                     dos.write(myMessage[i]);
    152                 }
    153                 // check that bytes have been written correctly
    154                 assertTrue("write", Arrays.equals(MDGoldenData.getMessage(), bos.toByteArray()));
    155                 // check that associated digest has been updated properly
    156                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    157                                                    MDGoldenData.getDigest(algorithmName[k])));
    158                 return;
    159             } catch (NoSuchAlgorithmException e) {
    160                 // allowed failure
    161             }
    162         }
    163         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    164     }
    165 
    166     /**
    167      * Test #2 for <code>write(int)</code> method<br>
    168      * Test #1 for <code>on(boolean)</code> method<br>
    169      *
    170      * Assertion: <code>write(int)</code> must not update digest if it is off<br>
    171      * Assertion: <code>on(boolean)</code> turns digest functionality on
    172      * if <code>true</code> passed as a parameter or off if <code>false</code>
    173      * passed
    174      */
    175     public final void testWriteint02()
    176         throws IOException {
    177         for (int k=0; k<algorithmName.length; k++) {
    178             try {
    179                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    180                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    181                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    182 
    183                 // turn digest off
    184                 dos.on(false);
    185 
    186                 for (int i=0; i<MY_MESSAGE_LEN; i++) {
    187                     dos.write(myMessage[i]);
    188                 }
    189 
    190                 // check that bytes have been written correctly
    191                 assertTrue("write", Arrays.equals(MDGoldenData.getMessage(), bos.toByteArray()));
    192                 // check that digest value has not been updated by write()
    193                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    194                                                    MDGoldenData.getDigest(algorithmName[k]+"_NU")));
    195                 return;
    196             } catch (NoSuchAlgorithmException e) {
    197                 // allowed failure
    198             }
    199         }
    200         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    201     }
    202 
    203     /**
    204      * Test #3 for <code>write(int)</code> method<br>
    205      *
    206      * Assertion: broken <code>DigestOutputStream</code>instance:
    207      * <code>OutputStream</code> not set. <code>write(int)</code> must
    208      * not work
    209      */
    210     public final void testWriteint03() throws IOException {
    211         for (int k=0; k<algorithmName.length; k++) {
    212             try {
    213                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    214                 DigestOutputStream dos = new DigestOutputStream(null, md);
    215                 // must result in an exception
    216                 try {
    217                     for (int i=0; i<MY_MESSAGE_LEN; i++) {
    218                         dos.write(myMessage[i]);
    219                     }
    220                     fail("OutputStream not set. write(int) must not work");
    221                 } catch (Exception e) {
    222                     return;
    223                 }
    224             } catch (NoSuchAlgorithmException e) {
    225                 // allowed failure
    226             }
    227         }
    228         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    229     }
    230 
    231     /**
    232      * Test #4 for <code>write(int)</code> method<br>
    233      *
    234      * Assertion: broken <code>DigestOutputStream</code>instance:
    235      * associated <code>MessageDigest</code> not set.
    236      * <code>write(int)</code> must not work when digest
    237      * functionality is on
    238      */
    239     public final void testWriteint04() throws IOException {
    240         OutputStream os = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    241         DigestOutputStream dos = new DigestOutputStream(os, null);
    242 
    243         // must result in an exception
    244         try {
    245             for (int i=0; i<MY_MESSAGE_LEN; i++) {
    246                 dos.write(myMessage[i]);
    247             }
    248             fail("OutputStream not set. write(int) must not work");
    249         } catch (Exception e) {
    250             return;
    251         }
    252     }
    253 
    254     /**
    255      * Test #5 for <code>write(int)</code> method<br>
    256      * Test #2 for <code>on(boolean)</code> method<br>
    257      *
    258      * Assertion: broken <code>DigestOutputStream</code>instance:
    259      * associated <code>MessageDigest</code> not set.
    260      * <code>write(int)</code> must work when digest
    261      * functionality is off
    262      */
    263     public final void testWriteint05() throws IOException {
    264         ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    265         DigestOutputStream dos = new DigestOutputStream(bos, null);
    266         // set digest functionality to off
    267         dos.on(false);
    268         // the following must pass without any exception
    269         for (int i=0; i<MY_MESSAGE_LEN; i++) {
    270             dos.write(myMessage[i]);
    271         }
    272         // check that bytes have been written correctly
    273         assertTrue(Arrays.equals(MDGoldenData.getMessage(), bos.toByteArray()));
    274     }
    275 
    276     /**
    277      * Test #1 for <code>write(byte[],int,int)</code> method<br>
    278      *
    279      * Assertion: put bytes into output stream<br>
    280      *
    281      * Assertion: updates associated digest<br>
    282      */
    283     public final void test_write$BII_1() throws IOException {
    284         for (int k=0; k<algorithmName.length; k++) {
    285             try {
    286                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    287                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    288                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    289 
    290                 // write message at once
    291                 dos.write(myMessage, 0, MY_MESSAGE_LEN);
    292 
    293                 // check write
    294                 assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
    295                 // check that associated digest has been updated properly
    296                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    297                                                    MDGoldenData.getDigest(algorithmName[k])));
    298                 return;
    299             } catch (NoSuchAlgorithmException e) {
    300                 // allowed failure
    301             }
    302         }
    303         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    304     }
    305 
    306     /**
    307      * Test #2 for <code>write(byte[],int,int)</code> method<br>
    308      *
    309      * Assertion: put bytes into output stream<br>
    310      *
    311      * Assertion: updates associated digest<br>
    312      */
    313     public final void test_write$BII_2() throws IOException {
    314         // check precondition
    315         assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
    316         for (int k=0; k<algorithmName.length; k++) {
    317             try {
    318 
    319                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    320                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    321                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    322 
    323                 // write message by chunks
    324                 for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
    325                     dos.write(myMessage, i*CHUNK_SIZE, CHUNK_SIZE);
    326                 }
    327                 // check write
    328                 assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
    329                 // check that associated digest has been updated properly
    330                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    331                         MDGoldenData.getDigest(algorithmName[k])));
    332                 return;
    333             } catch (NoSuchAlgorithmException e) {
    334                 // allowed failure
    335             }
    336         }
    337         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    338     }
    339 
    340 
    341     /**
    342      * Test #3 for <code>write(byte[],int,int)</code> method<br>
    343      *
    344      * Assertion: put bytes into output stream<br>
    345      *
    346      * Assertion: updates associated digest<br>
    347      */
    348     public final void test_write$BII_3()
    349         throws NoSuchAlgorithmException,
    350                IOException {
    351         // check precondition
    352         assertTrue(MY_MESSAGE_LEN % (CHUNK_SIZE+1) != 0);
    353 
    354         for (int k=0; k<algorithmName.length; k++) {
    355             try {
    356                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    357                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    358                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    359 
    360                 // write message by chunks
    361                 for (int i=0; i<MY_MESSAGE_LEN/(CHUNK_SIZE+1); i++) {
    362                     dos.write(myMessage, i*(CHUNK_SIZE+1), CHUNK_SIZE+1);
    363                 }
    364                 // write remaining bytes
    365                 dos.write(myMessage,
    366                         MY_MESSAGE_LEN/(CHUNK_SIZE+1)*(CHUNK_SIZE+1),
    367                         MY_MESSAGE_LEN % (CHUNK_SIZE+1));
    368                 // check write
    369                 assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
    370                 // check that associated digest has been updated properly
    371                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    372                         MDGoldenData.getDigest(algorithmName[k])));
    373                 return;
    374             } catch (NoSuchAlgorithmException e) {
    375                 // allowed failure
    376             }
    377         }
    378         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    379     }
    380 
    381     /**
    382      * Test #4 for <code>write(byte[],int,int)</code> method<br>
    383      *
    384      * Assertion: put bytes into output stream<br>
    385      *
    386      * Assertion: does not update associated digest if digest
    387      * functionality is off<br>
    388      */
    389     public final void test_write$BII_4()
    390         throws NoSuchAlgorithmException,
    391                IOException {
    392         // check precondition
    393         assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
    394 
    395         for (int k=0; k<algorithmName.length; k++) {
    396             try {
    397                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    398                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    399                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    400 
    401                 // set digest functionality off
    402                 dos.on(false);
    403 
    404                 // write message by chunks
    405                 for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
    406                     dos.write(myMessage, i*CHUNK_SIZE, CHUNK_SIZE);
    407                 }
    408 
    409                 // check write
    410                 assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
    411                 // check that associated digest has not been updated
    412                 assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
    413                         MDGoldenData.getDigest(algorithmName[k]+"_NU")));
    414                 return;
    415             } catch (NoSuchAlgorithmException e) {
    416                 // allowed failure
    417             }
    418         }
    419         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    420     }
    421 
    422     /**
    423      * java.security.DigestOutputStream#write(byte[], int, int)
    424      */
    425     public void test_write$BII_6() throws Exception {
    426 
    427         // Regression form HARMONY-1091.
    428         MessageDigest md = new MyMessageDigest1();
    429         byte[] bytes = new byte[] { 1, 2 };
    430         DigestOutputStream dig = new DigestOutputStream(
    431                 new ByteArrayOutputStream(), md);
    432         // buf == null
    433         try {
    434             dig.write(null, -1, 0);
    435             fail("No expected IllegalArgumentException");
    436         } catch (IllegalArgumentException e) {
    437         }
    438         // offset + len > buf.length
    439         try {
    440             dig.write(bytes, 0, bytes.length + 1);
    441             fail("No expected IllegalArgumentException");
    442         } catch (IllegalArgumentException e) {
    443         }
    444         // offset < 0
    445         try {
    446             dig.write(bytes, -1, 1);
    447             fail("No expected IndexOutOfBoundsException");
    448         } catch (IndexOutOfBoundsException e) {
    449         }
    450         // len < 0
    451         try {
    452             dig.write(bytes, 0, -1);
    453             fail("No expected IndexOutOfBoundsException");
    454         } catch (IndexOutOfBoundsException e) {
    455         }
    456     }
    457 
    458     /**
    459      * java.io.DigestOutputStream#write(byte[], int, int)
    460      */
    461     public void test_write$BII_7()
    462         throws IOException, NoSuchAlgorithmException {
    463         Support_OutputStream sos = new Support_OutputStream(MY_MESSAGE_LEN);
    464         MessageDigest md = MessageDigest.getInstance(algorithmName[0]);
    465         DigestOutputStream dos = new DigestOutputStream(sos, md);
    466 
    467         dos.write(myMessage, 0, MY_MESSAGE_LEN);
    468 
    469         try {
    470             // Support_OutputStream throws an IOException if the internal
    471             // buffer is full, which it should be now.
    472             dos.write(myMessage, 0, MY_MESSAGE_LEN);
    473             fail("Test 1: IOException expected.");
    474         } catch (IOException e) {
    475             // Expected.
    476         }
    477     }
    478 
    479     /**
    480      * Test for <code>on()</code> method<br>
    481      * Assertion: turns digest functionality on or off
    482      */
    483     public final void testOn() throws IOException {
    484         for (int k=0; k<algorithmName.length; k++) {
    485             try {
    486                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    487                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    488                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    489 
    490                 // turn digest off
    491                 dos.on(false);
    492 
    493                 for (int i=0; i<MY_MESSAGE_LEN-1; i++) {
    494                     dos.write(myMessage[i]);
    495                 }
    496 
    497                 // turn digest on
    498                 dos.on(true);
    499 
    500                 // read remaining byte
    501                 dos.write(myMessage[MY_MESSAGE_LEN-1]);
    502 
    503                 byte[] digest = dos.getMessageDigest().digest();
    504 
    505                 // check that digest value has been
    506                 // updated by the last write(int) call
    507                 assertFalse(Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[k])));
    508                 assertFalse(Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[k]+"_NU")));
    509                 return;
    510             } catch (NoSuchAlgorithmException e) {
    511                 // allowed failure
    512             }
    513         }
    514         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    515     }
    516 
    517     /**
    518      * Test for <code>toString()</code> method<br>
    519      * Assertion: returns <code>String</code> representation of this object
    520      */
    521     public final void testToString() throws NoSuchAlgorithmException {
    522         for (int k=0; k<algorithmName.length; k++) {
    523             try {
    524                 ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
    525                 MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
    526                 DigestOutputStream dos = new DigestOutputStream(bos, md);
    527 
    528                 assertNotNull(dos.toString());
    529                 return;
    530             } catch (NoSuchAlgorithmException e) {
    531                 // allowed failure
    532             }
    533         }
    534         fail(getName() + ": no MessageDigest algorithms available - test not performed");
    535     }
    536 
    537     /**
    538      * java.security.DigestOutputStream#on(boolean)
    539      */
    540     public void test_onZ() throws Exception {
    541         // Test for method void java.security.DigestOutputStream.on(boolean)
    542         DigestOutputStream dos = new DigestOutputStream(
    543                 new ByteArrayOutputStream(), MessageDigest.getInstance("SHA"));
    544         dos.on(false);
    545         byte digestArray[] = { 23, 43, 44 };
    546         dos.write(digestArray, 1, 1);
    547         byte digestResult[] = dos.getMessageDigest().digest();
    548         byte expected[] = { -38, 57, -93, -18, 94, 107, 75, 13, 50, 85,
    549                 -65, -17, -107, 96, 24, -112, -81, -40, 7, 9 };
    550         assertTrue("Digest did not return expected result.",
    551                    Arrays.equals(digestResult, expected));
    552         // now turn on processing and re-run
    553         dos.on(true);
    554         dos.write(digestArray, 1, 1);
    555         digestResult = dos.getMessageDigest().digest();
    556         byte expected1[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33,
    557                 107, -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
    558 
    559         assertTrue("Digest did not return expected result.",
    560                    Arrays.equals(digestResult, expected1));
    561     }
    562 
    563     /**
    564      * java.security.DigestOutputStream#write(byte[], int, int)
    565      */
    566     public void test_write$BII_5() throws Exception {
    567         // Test for method void java.security.DigestOutputStream.write(byte [],
    568         // int, int)
    569             DigestOutputStream dos = new DigestOutputStream(
    570                 new ByteArrayOutputStream(), MessageDigest.getInstance("SHA"));
    571             byte digestArray[] = { 23, 43, 44 };
    572             dos.write(digestArray, 1, 1);
    573             byte digestResult[] = dos.getMessageDigest().digest();
    574             byte expected[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33, 107,
    575                     -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
    576 
    577             assertTrue("Digest did not return expected result.",
    578                        Arrays.equals(digestResult, expected));
    579     }
    580 
    581     /**
    582      * java.security.DigestOutputStream#write(int)
    583      */
    584     public void test_writeI() throws Exception {
    585         // Test for method void java.security.DigestOutputStream.write(int)
    586             DigestOutputStream dos = new DigestOutputStream(
    587                 new ByteArrayOutputStream(), MessageDigest.getInstance("SHA"));
    588             dos.write((byte) 43);
    589             byte digestResult[] = dos.getMessageDigest().digest();
    590             byte expected[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33, 107,
    591                     -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
    592 
    593             assertTrue("Digest did not return expected result.",
    594                        Arrays.equals(digestResult, expected));
    595     }
    596 
    597     private class MessageDigestWithUnsupportedUpdate extends MessageDigest {
    598         private MessageDigestWithUnsupportedUpdate() {
    599             super("SomeAlgorithm");
    600         }
    601 
    602         @Override
    603         protected void engineUpdate(byte input) {
    604             throw new UnsupportedOperationException();
    605         }
    606 
    607         @Override
    608         protected void engineUpdate(byte[] input, int offset, int len) {
    609             throw new UnsupportedOperationException();
    610         }
    611 
    612         @Override
    613         protected byte[] engineDigest() {
    614             return new byte[0];
    615         }
    616 
    617         @Override
    618         protected void engineReset() {
    619 
    620         }
    621     }
    622 
    623     public void test_write_writeToUnderlyingStreamBeforeUpdatingDigest() {
    624         MessageDigest messageDigestWithUnsupportedUpdate = new MessageDigestWithUnsupportedUpdate();
    625         OutputStream outputStreamThatThrowsIOException = new OutputStream() {
    626             @Override
    627             public void write(int b) throws IOException {
    628                 throw new IOException();
    629             }
    630         };
    631 
    632         DigestOutputStream digestOutputStream = new DigestOutputStream(
    633                 outputStreamThatThrowsIOException, messageDigestWithUnsupportedUpdate);
    634 
    635         // Writing throws an IOException (and not an UnsupportedOperationException) meaning than
    636         // it tried to write to the underlying stream before updating the digest.
    637         digestOutputStream.on(true);
    638         try {
    639             digestOutputStream.write(3);
    640             fail();
    641         } catch (IOException expected) {
    642         }
    643 
    644         digestOutputStream.on(true);
    645         try {
    646             digestOutputStream.write(new byte[10], 0, 10);
    647             fail();
    648         } catch (IOException expected) {
    649         }
    650 
    651         digestOutputStream.on(true);
    652         try {
    653             digestOutputStream.write(new byte[10]);
    654             fail();
    655         } catch (IOException expected) {
    656         }
    657     }
    658 
    659     private class MyOutputStream extends OutputStream {
    660         @Override
    661         public void write(int arg0) throws IOException {
    662         }
    663     }
    664 
    665     private class MyDigestOutputStream extends DigestOutputStream {
    666         public MyDigestOutputStream(OutputStream out, MessageDigest digest) {
    667             super(out, digest);
    668         }
    669 
    670         public MessageDigest myMessageDigest() {
    671             return digest;
    672         }
    673 
    674         public OutputStream myOutputStream() {
    675             return out;
    676         }
    677     }
    678 }
    679