Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.util.Arrays;
     22 import junit.framework.TestCase;
     23 
     24 import java.io.ByteArrayInputStream;
     25 import java.io.ByteArrayOutputStream;
     26 import java.util.Random;
     27 
     28 public class Base64Test extends TestCase {
     29     private static final String TAG = "Base64Test";
     30 
     31     /** Decodes a string, returning a string. */
     32     private String decodeString(String in) throws Exception {
     33         byte[] out = Base64.decode(in, 0);
     34         return new String(out);
     35     }
     36 
     37     /**
     38      * Encodes the string 'in' using 'flags'.  Asserts that decoding
     39      * gives the same string.  Returns the encoded string.
     40      */
     41     private String encodeToString(String in, int flags) throws Exception {
     42         String b64 = Base64.encodeToString(in.getBytes(), flags);
     43         String dec = decodeString(b64);
     44         assertEquals(in, dec);
     45         return b64;
     46     }
     47 
     48     /** Assert that decoding 'in' throws IllegalArgumentException. */
     49     private void assertBad(String in) throws Exception {
     50         try {
     51             byte[] out = Base64.decode(in, 0);
     52             fail("should have failed to decode");
     53         } catch (IllegalArgumentException e) {
     54         }
     55     }
     56 
     57     /** Assert that actual equals the first len bytes of expected. */
     58     private void assertEquals(byte[] expected, int len, byte[] actual) {
     59         assertEquals(len, actual.length);
     60         for (int i = 0; i < len; ++i) {
     61             assertEquals(expected[i], actual[i]);
     62         }
     63     }
     64 
     65     /** Assert that actual equals the first len bytes of expected. */
     66     private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
     67         assertEquals(len, alen);
     68         for (int i = 0; i < len; ++i) {
     69             assertEquals(expected[i], actual[i]);
     70         }
     71     }
     72 
     73     /** Assert that actual equals the first len bytes of expected. */
     74     private void assertEquals(byte[] expected, byte[] actual) {
     75         assertEquals(expected.length, actual.length);
     76         for (int i = 0; i < expected.length; ++i) {
     77             assertEquals(expected[i], actual[i]);
     78         }
     79     }
     80 
     81     public void testDecodeExtraChars() throws Exception {
     82         // padding 0
     83         assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
     84         assertBad("aGVsbG8sIHdvcmxk=");
     85         assertBad("aGVsbG8sIHdvcmxk==");
     86         assertBad("aGVsbG8sIHdvcmxk =");
     87         assertBad("aGVsbG8sIHdvcmxk = = ");
     88         assertEquals("hello, world", decodeString(" aGVs bG8s IHdv cmxk  "));
     89         assertEquals("hello, world", decodeString(" aGV sbG8 sIHd vcmx k "));
     90         assertEquals("hello, world", decodeString(" aG VsbG 8sIH dvcm xk "));
     91         assertEquals("hello, world", decodeString(" a GVsb G8sI Hdvc mxk "));
     92         assertEquals("hello, world", decodeString(" a G V s b G 8 s I H d v c m x k "));
     93         assertEquals("hello, world", decodeString("_a*G_V*s_b*G_8*s_I*H_d*v_c*m_x*k_"));
     94         assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
     95 
     96         // padding 1
     97         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE="));
     98         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPyE"));
     99         assertBad("aGVsbG8sIHdvcmxkPyE==");
    100         assertBad("aGVsbG8sIHdvcmxkPyE ==");
    101         assertBad("aGVsbG8sIHdvcmxkPyE = = ");
    102         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E="));
    103         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E"));
    104         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E ="));
    105         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E "));
    106         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E = "));
    107         assertEquals("hello, world?!", decodeString("aGVsbG8sIHdvcmxkPy E   "));
    108 
    109         // padding 2
    110         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg=="));
    111         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkLg"));
    112         assertBad("aGVsbG8sIHdvcmxkLg=");
    113         assertBad("aGVsbG8sIHdvcmxkLg =");
    114         assertBad("aGVsbG8sIHdvcmxkLg = ");
    115         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g=="));
    116         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g"));
    117         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g =="));
    118         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g "));
    119         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g = = "));
    120         assertEquals("hello, world.", decodeString("aGVsbG8sIHdvcmxkL g   "));
    121     }
    122 
    123     private static final byte[] BYTES = { (byte) 0xff, (byte) 0xee, (byte) 0xdd,
    124                                           (byte) 0xcc, (byte) 0xbb, (byte) 0xaa,
    125                                           (byte) 0x99, (byte) 0x88, (byte) 0x77 };
    126 
    127     public void testBinaryDecode() throws Exception {
    128         assertEquals(BYTES, 0, Base64.decode("", 0));
    129         assertEquals(BYTES, 1, Base64.decode("/w==", 0));
    130         assertEquals(BYTES, 2, Base64.decode("/+4=", 0));
    131         assertEquals(BYTES, 3, Base64.decode("/+7d", 0));
    132         assertEquals(BYTES, 4, Base64.decode("/+7dzA==", 0));
    133         assertEquals(BYTES, 5, Base64.decode("/+7dzLs=", 0));
    134         assertEquals(BYTES, 6, Base64.decode("/+7dzLuq", 0));
    135         assertEquals(BYTES, 7, Base64.decode("/+7dzLuqmQ==", 0));
    136         assertEquals(BYTES, 8, Base64.decode("/+7dzLuqmYg=", 0));
    137     }
    138 
    139     public void testWebSafe() throws Exception {
    140         assertEquals(BYTES, 0, Base64.decode("", Base64.URL_SAFE));
    141         assertEquals(BYTES, 1, Base64.decode("_w==", Base64.URL_SAFE));
    142         assertEquals(BYTES, 2, Base64.decode("_-4=", Base64.URL_SAFE));
    143         assertEquals(BYTES, 3, Base64.decode("_-7d", Base64.URL_SAFE));
    144         assertEquals(BYTES, 4, Base64.decode("_-7dzA==", Base64.URL_SAFE));
    145         assertEquals(BYTES, 5, Base64.decode("_-7dzLs=", Base64.URL_SAFE));
    146         assertEquals(BYTES, 6, Base64.decode("_-7dzLuq", Base64.URL_SAFE));
    147         assertEquals(BYTES, 7, Base64.decode("_-7dzLuqmQ==", Base64.URL_SAFE));
    148         assertEquals(BYTES, 8, Base64.decode("_-7dzLuqmYg=", Base64.URL_SAFE));
    149 
    150         assertEquals("", Base64.encodeToString(BYTES, 0, 0, Base64.URL_SAFE));
    151         assertEquals("_w==\n", Base64.encodeToString(BYTES, 0, 1, Base64.URL_SAFE));
    152         assertEquals("_-4=\n", Base64.encodeToString(BYTES, 0, 2, Base64.URL_SAFE));
    153         assertEquals("_-7d\n", Base64.encodeToString(BYTES, 0, 3, Base64.URL_SAFE));
    154         assertEquals("_-7dzA==\n", Base64.encodeToString(BYTES, 0, 4, Base64.URL_SAFE));
    155         assertEquals("_-7dzLs=\n", Base64.encodeToString(BYTES, 0, 5, Base64.URL_SAFE));
    156         assertEquals("_-7dzLuq\n", Base64.encodeToString(BYTES, 0, 6, Base64.URL_SAFE));
    157         assertEquals("_-7dzLuqmQ==\n", Base64.encodeToString(BYTES, 0, 7, Base64.URL_SAFE));
    158         assertEquals("_-7dzLuqmYg=\n", Base64.encodeToString(BYTES, 0, 8, Base64.URL_SAFE));
    159     }
    160 
    161     public void testFlags() throws Exception {
    162         assertEquals("YQ==\n",       encodeToString("a", 0));
    163         assertEquals("YQ==",         encodeToString("a", Base64.NO_WRAP));
    164         assertEquals("YQ\n",         encodeToString("a", Base64.NO_PADDING));
    165         assertEquals("YQ",           encodeToString("a", Base64.NO_PADDING | Base64.NO_WRAP));
    166         assertEquals("YQ==\r\n",     encodeToString("a", Base64.CRLF));
    167         assertEquals("YQ\r\n",       encodeToString("a", Base64.CRLF | Base64.NO_PADDING));
    168 
    169         assertEquals("YWI=\n",       encodeToString("ab", 0));
    170         assertEquals("YWI=",         encodeToString("ab", Base64.NO_WRAP));
    171         assertEquals("YWI\n",        encodeToString("ab", Base64.NO_PADDING));
    172         assertEquals("YWI",          encodeToString("ab", Base64.NO_PADDING | Base64.NO_WRAP));
    173         assertEquals("YWI=\r\n",     encodeToString("ab", Base64.CRLF));
    174         assertEquals("YWI\r\n",      encodeToString("ab", Base64.CRLF | Base64.NO_PADDING));
    175 
    176         assertEquals("YWJj\n",       encodeToString("abc", 0));
    177         assertEquals("YWJj",         encodeToString("abc", Base64.NO_WRAP));
    178         assertEquals("YWJj\n",       encodeToString("abc", Base64.NO_PADDING));
    179         assertEquals("YWJj",         encodeToString("abc", Base64.NO_PADDING | Base64.NO_WRAP));
    180         assertEquals("YWJj\r\n",     encodeToString("abc", Base64.CRLF));
    181         assertEquals("YWJj\r\n",     encodeToString("abc", Base64.CRLF | Base64.NO_PADDING));
    182 
    183         assertEquals("YWJjZA==\n",   encodeToString("abcd", 0));
    184         assertEquals("YWJjZA==",     encodeToString("abcd", Base64.NO_WRAP));
    185         assertEquals("YWJjZA\n",     encodeToString("abcd", Base64.NO_PADDING));
    186         assertEquals("YWJjZA",       encodeToString("abcd", Base64.NO_PADDING | Base64.NO_WRAP));
    187         assertEquals("YWJjZA==\r\n", encodeToString("abcd", Base64.CRLF));
    188         assertEquals("YWJjZA\r\n",   encodeToString("abcd", Base64.CRLF | Base64.NO_PADDING));
    189     }
    190 
    191     public void testLineLength() throws Exception {
    192         String in_56 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd";
    193         String in_57 = in_56 + "e";
    194         String in_58 = in_56 + "ef";
    195         String in_59 = in_56 + "efg";
    196         String in_60 = in_56 + "efgh";
    197         String in_61 = in_56 + "efghi";
    198 
    199         String prefix = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5emFi";
    200         String out_56 = prefix + "Y2Q=\n";
    201         String out_57 = prefix + "Y2Rl\n";
    202         String out_58 = prefix + "Y2Rl\nZg==\n";
    203         String out_59 = prefix + "Y2Rl\nZmc=\n";
    204         String out_60 = prefix + "Y2Rl\nZmdo\n";
    205         String out_61 = prefix + "Y2Rl\nZmdoaQ==\n";
    206 
    207         // no newline for an empty input array.
    208         assertEquals("", encodeToString("", 0));
    209 
    210         assertEquals(out_56, encodeToString(in_56, 0));
    211         assertEquals(out_57, encodeToString(in_57, 0));
    212         assertEquals(out_58, encodeToString(in_58, 0));
    213         assertEquals(out_59, encodeToString(in_59, 0));
    214         assertEquals(out_60, encodeToString(in_60, 0));
    215         assertEquals(out_61, encodeToString(in_61, 0));
    216 
    217         assertEquals(out_56.replaceAll("=", ""), encodeToString(in_56, Base64.NO_PADDING));
    218         assertEquals(out_57.replaceAll("=", ""), encodeToString(in_57, Base64.NO_PADDING));
    219         assertEquals(out_58.replaceAll("=", ""), encodeToString(in_58, Base64.NO_PADDING));
    220         assertEquals(out_59.replaceAll("=", ""), encodeToString(in_59, Base64.NO_PADDING));
    221         assertEquals(out_60.replaceAll("=", ""), encodeToString(in_60, Base64.NO_PADDING));
    222         assertEquals(out_61.replaceAll("=", ""), encodeToString(in_61, Base64.NO_PADDING));
    223 
    224         assertEquals(out_56.replaceAll("\n", ""), encodeToString(in_56, Base64.NO_WRAP));
    225         assertEquals(out_57.replaceAll("\n", ""), encodeToString(in_57, Base64.NO_WRAP));
    226         assertEquals(out_58.replaceAll("\n", ""), encodeToString(in_58, Base64.NO_WRAP));
    227         assertEquals(out_59.replaceAll("\n", ""), encodeToString(in_59, Base64.NO_WRAP));
    228         assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP));
    229         assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP));
    230     }
    231 
    232     /**
    233      * Tests that Base64.Encoder.encode() does correct handling of the
    234      * tail for each call.
    235      *
    236      * This test is disabled because while it passes if you can get it
    237      * to run, android's test infrastructure currently doesn't allow
    238      * us to get at package-private members (Base64.Encoder in
    239      * this case).
    240      */
    241     public void XXXtestEncodeInternal() throws Exception {
    242         byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
    243         byte[] output = new byte[100];
    244 
    245         Base64.Encoder encoder = new Base64.Encoder(Base64.NO_PADDING | Base64.NO_WRAP,
    246                                                     output);
    247 
    248         encoder.process(input, 0, 3, false);
    249         assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
    250         assertEquals(0, encoder.tailLen);
    251 
    252         encoder.process(input, 0, 3, false);
    253         assertEquals("YWJj".getBytes(), 4, encoder.output, encoder.op);
    254         assertEquals(0, encoder.tailLen);
    255 
    256         encoder.process(input, 0, 1, false);
    257         assertEquals(0, encoder.op);
    258         assertEquals(1, encoder.tailLen);
    259 
    260         encoder.process(input, 0, 1, false);
    261         assertEquals(0, encoder.op);
    262         assertEquals(2, encoder.tailLen);
    263 
    264         encoder.process(input, 0, 1, false);
    265         assertEquals("YWFh".getBytes(), 4, encoder.output, encoder.op);
    266         assertEquals(0, encoder.tailLen);
    267 
    268         encoder.process(input, 0, 2, false);
    269         assertEquals(0, encoder.op);
    270         assertEquals(2, encoder.tailLen);
    271 
    272         encoder.process(input, 0, 2, false);
    273         assertEquals("YWJh".getBytes(), 4, encoder.output, encoder.op);
    274         assertEquals(1, encoder.tailLen);
    275 
    276         encoder.process(input, 0, 2, false);
    277         assertEquals("YmFi".getBytes(), 4, encoder.output, encoder.op);
    278         assertEquals(0, encoder.tailLen);
    279 
    280         encoder.process(input, 0, 1, true);
    281         assertEquals("YQ".getBytes(), 2, encoder.output, encoder.op);
    282     }
    283 
    284     private static final String lipsum =
    285             "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
    286             "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " +
    287             "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " +
    288             "urna, pharetra vitae consequat eget, adipiscing eu ante. " +
    289             "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " +
    290             "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " +
    291             "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " +
    292             "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " +
    293             "aliquet dui sapien a turpis. Donec ultricies varius ligula, " +
    294             "ut hendrerit arcu malesuada at. Praesent sed elit pretium " +
    295             "eros luctus gravida. In ac dolor lorem. Cras condimentum " +
    296             "convallis elementum. Phasellus vel felis in nulla ultrices " +
    297             "venenatis. Nam non tortor non orci convallis convallis. " +
    298             "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " +
    299             "tristique senectus et netus et malesuada fames ac turpis " +
    300             "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " +
    301             "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " +
    302             "Phasellus posuere, leo at ultricies vehicula, massa risus " +
    303             "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " +
    304             "molestie dapibus commodo. Ut vel tellus at massa gravida " +
    305             "semper non sed orci.";
    306 
    307     public void testInputStream() throws Exception {
    308         int[] flagses = { Base64.DEFAULT,
    309                           Base64.NO_PADDING,
    310                           Base64.NO_WRAP,
    311                           Base64.NO_PADDING | Base64.NO_WRAP,
    312                           Base64.CRLF,
    313                           Base64.URL_SAFE };
    314         int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
    315         Random rng = new Random(32176L);
    316 
    317         // Test input needs to be at least 2048 bytes to fill up the
    318         // read buffer of Base64InputStream.
    319         byte[] plain = (lipsum + lipsum + lipsum + lipsum + lipsum).getBytes();
    320 
    321         for (int flags: flagses) {
    322             byte[] encoded = Base64.encode(plain, flags);
    323 
    324             ByteArrayInputStream bais;
    325             Base64InputStream b64is;
    326             byte[] actual = new byte[plain.length * 2];
    327             int ap;
    328             int b;
    329 
    330             // ----- test decoding ("encoded" -> "plain") -----
    331 
    332             // read as much as it will give us in one chunk
    333             bais = new ByteArrayInputStream(encoded);
    334             b64is = new Base64InputStream(bais, flags);
    335             ap = 0;
    336             while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
    337                 ap += b;
    338             }
    339             assertEquals(actual, ap, plain);
    340 
    341             // read individual bytes
    342             bais = new ByteArrayInputStream(encoded);
    343             b64is = new Base64InputStream(bais, flags);
    344             ap = 0;
    345             while ((b = b64is.read()) != -1) {
    346                 actual[ap++] = (byte) b;
    347             }
    348             assertEquals(actual, ap, plain);
    349 
    350             // mix reads of variously-sized arrays with one-byte reads
    351             bais = new ByteArrayInputStream(encoded);
    352             b64is = new Base64InputStream(bais, flags);
    353             ap = 0;
    354             readloop: while (true) {
    355                 int l = writeLengths[rng.nextInt(writeLengths.length)];
    356                 if (l >= 0) {
    357                     b = b64is.read(actual, ap, l);
    358                     if (b == -1) break readloop;
    359                     ap += b;
    360                 } else {
    361                     for (int i = 0; i < -l; ++i) {
    362                         if ((b = b64is.read()) == -1) break readloop;
    363                         actual[ap++] = (byte) b;
    364                     }
    365                 }
    366             }
    367             assertEquals(actual, ap, plain);
    368 
    369             // ----- test encoding ("plain" -> "encoded") -----
    370 
    371             // read as much as it will give us in one chunk
    372             bais = new ByteArrayInputStream(plain);
    373             b64is = new Base64InputStream(bais, flags, true);
    374             ap = 0;
    375             while ((b = b64is.read(actual, ap, actual.length-ap)) != -1) {
    376                 ap += b;
    377             }
    378             assertEquals(actual, ap, encoded);
    379 
    380             // read individual bytes
    381             bais = new ByteArrayInputStream(plain);
    382             b64is = new Base64InputStream(bais, flags, true);
    383             ap = 0;
    384             while ((b = b64is.read()) != -1) {
    385                 actual[ap++] = (byte) b;
    386             }
    387             assertEquals(actual, ap, encoded);
    388 
    389             // mix reads of variously-sized arrays with one-byte reads
    390             bais = new ByteArrayInputStream(plain);
    391             b64is = new Base64InputStream(bais, flags, true);
    392             ap = 0;
    393             readloop: while (true) {
    394                 int l = writeLengths[rng.nextInt(writeLengths.length)];
    395                 if (l >= 0) {
    396                     b = b64is.read(actual, ap, l);
    397                     if (b == -1) break readloop;
    398                     ap += b;
    399                 } else {
    400                     for (int i = 0; i < -l; ++i) {
    401                         if ((b = b64is.read()) == -1) break readloop;
    402                         actual[ap++] = (byte) b;
    403                     }
    404                 }
    405             }
    406             assertEquals(actual, ap, encoded);
    407         }
    408     }
    409 
    410     /** http://b/3026478 */
    411     public void testSingleByteReads() throws IOException {
    412         InputStream in = new Base64InputStream(
    413                 new ByteArrayInputStream("/v8=".getBytes()), Base64.DEFAULT);
    414         assertEquals(254, in.read());
    415         assertEquals(255, in.read());
    416     }
    417 
    418     /**
    419      * Tests that Base64OutputStream produces exactly the same results
    420      * as calling Base64.encode/.decode on an in-memory array.
    421      */
    422     public void testOutputStream() throws Exception {
    423         int[] flagses = { Base64.DEFAULT,
    424                           Base64.NO_PADDING,
    425                           Base64.NO_WRAP,
    426                           Base64.NO_PADDING | Base64.NO_WRAP,
    427                           Base64.CRLF,
    428                           Base64.URL_SAFE };
    429         int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
    430         Random rng = new Random(32176L);
    431 
    432         // Test input needs to be at least 1024 bytes to test filling
    433         // up the write(int) buffer of Base64OutputStream.
    434         byte[] plain = (lipsum + lipsum).getBytes();
    435 
    436         for (int flags: flagses) {
    437             byte[] encoded = Base64.encode(plain, flags);
    438 
    439             ByteArrayOutputStream baos;
    440             Base64OutputStream b64os;
    441             byte[] actual;
    442             int p;
    443 
    444             // ----- test encoding ("plain" -> "encoded") -----
    445 
    446             // one large write(byte[]) of the whole input
    447             baos = new ByteArrayOutputStream();
    448             b64os = new Base64OutputStream(baos, flags);
    449             b64os.write(plain);
    450             b64os.close();
    451             actual = baos.toByteArray();
    452             assertEquals(encoded, actual);
    453 
    454             // many calls to write(int)
    455             baos = new ByteArrayOutputStream();
    456             b64os = new Base64OutputStream(baos, flags);
    457             for (int i = 0; i < plain.length; ++i) {
    458                 b64os.write(plain[i]);
    459             }
    460             b64os.close();
    461             actual = baos.toByteArray();
    462             assertEquals(encoded, actual);
    463 
    464             // intermixed sequences of write(int) with
    465             // write(byte[],int,int) of various lengths.
    466             baos = new ByteArrayOutputStream();
    467             b64os = new Base64OutputStream(baos, flags);
    468             p = 0;
    469             while (p < plain.length) {
    470                 int l = writeLengths[rng.nextInt(writeLengths.length)];
    471                 l = Math.min(l, plain.length-p);
    472                 if (l >= 0) {
    473                     b64os.write(plain, p, l);
    474                     p += l;
    475                 } else {
    476                     l = Math.min(-l, plain.length-p);
    477                     for (int i = 0; i < l; ++i) {
    478                         b64os.write(plain[p+i]);
    479                     }
    480                     p += l;
    481                 }
    482             }
    483             b64os.close();
    484             actual = baos.toByteArray();
    485             assertEquals(encoded, actual);
    486 
    487             // ----- test decoding ("encoded" -> "plain") -----
    488 
    489             // one large write(byte[]) of the whole input
    490             baos = new ByteArrayOutputStream();
    491             b64os = new Base64OutputStream(baos, flags, false);
    492             b64os.write(encoded);
    493             b64os.close();
    494             actual = baos.toByteArray();
    495             assertEquals(plain, actual);
    496 
    497             // many calls to write(int)
    498             baos = new ByteArrayOutputStream();
    499             b64os = new Base64OutputStream(baos, flags, false);
    500             for (int i = 0; i < encoded.length; ++i) {
    501                 b64os.write(encoded[i]);
    502             }
    503             b64os.close();
    504             actual = baos.toByteArray();
    505             assertEquals(plain, actual);
    506 
    507             // intermixed sequences of write(int) with
    508             // write(byte[],int,int) of various lengths.
    509             baos = new ByteArrayOutputStream();
    510             b64os = new Base64OutputStream(baos, flags, false);
    511             p = 0;
    512             while (p < encoded.length) {
    513                 int l = writeLengths[rng.nextInt(writeLengths.length)];
    514                 l = Math.min(l, encoded.length-p);
    515                 if (l >= 0) {
    516                     b64os.write(encoded, p, l);
    517                     p += l;
    518                 } else {
    519                     l = Math.min(-l, encoded.length-p);
    520                     for (int i = 0; i < l; ++i) {
    521                         b64os.write(encoded[p+i]);
    522                     }
    523                     p += l;
    524                 }
    525             }
    526             b64os.close();
    527             actual = baos.toByteArray();
    528             assertEquals(plain, actual);
    529         }
    530     }
    531 }
    532