001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.codec.binary; 019 020 import static org.junit.Assert.assertTrue; 021 import static org.junit.Assert.fail; 022 023 import java.io.ByteArrayOutputStream; 024 import java.io.OutputStream; 025 import java.util.Arrays; 026 027 import org.junit.Test; 028 029 public class Base32OutputStreamTest { 030 031 private final static byte[] CRLF = {(byte) '\r', (byte) '\n'}; 032 033 private final static byte[] LF = {(byte) '\n'}; 034 035 036 037 // /** 038 // * Test the Base32OutputStream implementation against the special NPE inducing input 039 // * identified in the CODEC-98 bug. 040 // * 041 // * @throws Exception for some failure scenarios. 042 // */ 043 // @Test 044 // public void testCodec98NPE() throws Exception { 045 // byte[] codec98 = StringUtils.getBytesUtf8(Base32TestData.CODEC_98_NPE); 046 // byte[] codec98_1024 = new byte[1024]; 047 // System.arraycopy(codec98, 0, codec98_1024, 0, codec98.length); 048 // ByteArrayOutputStream data = new ByteArrayOutputStream(1024); 049 // Base32OutputStream stream = new Base32OutputStream(data, false); 050 // stream.write(codec98_1024, 0, 1024); 051 // stream.close(); 052 // 053 // byte[] decodedBytes = data.toByteArray(); 054 // String decoded = StringUtils.newStringUtf8(decodedBytes); 055 // assertEquals( 056 // "codec-98 NPE Base32OutputStream", Base32TestData.CODEC_98_NPE_DECODED, decoded 057 // ); 058 // } 059 060 061 /** 062 * Test the Base32OutputStream implementation against empty input. 063 * 064 * @throws Exception 065 * for some failure scenarios. 066 */ 067 @Test 068 public void testBase32EmptyOutputStreamMimeChunkSize() throws Exception { 069 testBase32EmptyOutputStream(BaseNCodec.MIME_CHUNK_SIZE); 070 } 071 072 /** 073 * Test the Base32OutputStream implementation against empty input. 074 * 075 * @throws Exception 076 * for some failure scenarios. 077 */ 078 @Test 079 public void testBase32EmptyOutputStreamPemChunkSize() throws Exception { 080 testBase32EmptyOutputStream(BaseNCodec.PEM_CHUNK_SIZE); 081 } 082 083 private void testBase32EmptyOutputStream(int chunkSize) throws Exception { 084 byte[] emptyEncoded = new byte[0]; 085 byte[] emptyDecoded = new byte[0]; 086 testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CRLF); 087 testByChunk(emptyEncoded, emptyDecoded, chunkSize, CRLF); 088 } 089 090 /** 091 * Test the Base32OutputStream implementation 092 * 093 * @throws Exception 094 * for some failure scenarios. 095 */ 096 @Test 097 public void testBase32OutputStreamByChunk() throws Exception { 098 // Hello World test. 099 byte[] encoded = StringUtils.getBytesUtf8(Base32TestData.BASE32_FIXTURE); 100 byte[] decoded = StringUtils.getBytesUtf8(Base32TestData.STRING_FIXTURE); 101 testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF); 102 103 // // Single Byte test. 104 // encoded = StringUtils.getBytesUtf8("AA==\r\n"); 105 // decoded = new byte[]{(byte) 0}; 106 // testByChunk(encoded, decoded, Base32.MIME_CHUNK_SIZE, CRLF); 107 108 109 // // Single Line test. 110 // String singleLine = Base32TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", ""); 111 // encoded = StringUtils.getBytesUtf8(singleLine); 112 // decoded = Base32TestData.DECODED; 113 // testByChunk(encoded, decoded, 0, LF); 114 115 // test random data of sizes 0 thru 150 116 BaseNCodec codec = new Base32(); 117 for (int i = 0; i <= 150; i++) { 118 byte[][] randomData = Base32TestData.randomData(codec, i); 119 encoded = randomData[1]; 120 decoded = randomData[0]; 121 testByChunk(encoded, decoded, 0, LF); 122 } 123 } 124 125 /** 126 * Test the Base32OutputStream implementation 127 * 128 * @throws Exception 129 * for some failure scenarios. 130 */ 131 @Test 132 public void testBase32OutputStreamByteByByte() throws Exception { 133 // Hello World test. 134 byte[] encoded = StringUtils.getBytesUtf8(Base32TestData.BASE32_FIXTURE); 135 byte[] decoded = StringUtils.getBytesUtf8(Base32TestData.STRING_FIXTURE); 136 testByteByByte(encoded, decoded, 76, CRLF); 137 138 // // Single Byte test. 139 // encoded = StringUtils.getBytesUtf8("AA==\r\n"); 140 // decoded = new byte[]{(byte) 0}; 141 // testByteByByte(encoded, decoded, 76, CRLF); 142 143 144 // // Single Line test. 145 // String singleLine = Base32TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", ""); 146 // encoded = StringUtils.getBytesUtf8(singleLine); 147 // decoded = Base32TestData.DECODED; 148 // testByteByByte(encoded, decoded, 0, LF); 149 150 // test random data of sizes 0 thru 150 151 BaseNCodec codec = new Base32(); 152 for (int i = 0; i <= 150; i++) { 153 byte[][] randomData = Base32TestData.randomData(codec, i); 154 encoded = randomData[1]; 155 decoded = randomData[0]; 156 testByteByByte(encoded, decoded, 0, LF); 157 } 158 } 159 160 /** 161 * Test method does three tests on the supplied data: 1. encoded ---[DECODE]--> decoded 2. decoded ---[ENCODE]--> 162 * encoded 3. decoded ---[WRAP-WRAP-WRAP-etc...] --> decoded 163 * <p/> 164 * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the Base32OutputStream wraps itself in encode and decode 165 * mode over and over again. 166 * 167 * @param encoded 168 * Base32 encoded data 169 * @param decoded 170 * the data from above, but decoded 171 * @param chunkSize 172 * chunk size (line-length) of the Base32 encoded data. 173 * @param seperator 174 * Line separator in the Base32 encoded data. 175 * @throws Exception 176 * Usually signifies a bug in the Base32 commons-codec implementation. 177 */ 178 private void testByChunk(byte[] encoded, byte[] decoded, int chunkSize, byte[] seperator) throws Exception { 179 180 // Start with encode. 181 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 182 OutputStream out = new Base32OutputStream(byteOut, true, chunkSize, seperator); 183 out.write(decoded); 184 out.close(); 185 byte[] output = byteOut.toByteArray(); 186 assertTrue("Streaming chunked Base32 encode", Arrays.equals(output, encoded)); 187 188 // Now let's try decode. 189 byteOut = new ByteArrayOutputStream(); 190 out = new Base32OutputStream(byteOut, false); 191 out.write(encoded); 192 out.close(); 193 output = byteOut.toByteArray(); 194 assertTrue("Streaming chunked Base32 decode", Arrays.equals(output, decoded)); 195 196 // I always wanted to do this! (wrap encoder with decoder etc etc). 197 byteOut = new ByteArrayOutputStream(); 198 out = byteOut; 199 for (int i = 0; i < 10; i++) { 200 out = new Base32OutputStream(out, false); 201 out = new Base32OutputStream(out, true, chunkSize, seperator); 202 } 203 out.write(decoded); 204 out.close(); 205 output = byteOut.toByteArray(); 206 207 assertTrue("Streaming chunked Base32 wrap-wrap-wrap!", Arrays.equals(output, decoded)); 208 } 209 210 /** 211 * Test method does three tests on the supplied data: 1. encoded ---[DECODE]--> decoded 2. decoded ---[ENCODE]--> 212 * encoded 3. decoded ---[WRAP-WRAP-WRAP-etc...] --> decoded 213 * <p/> 214 * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the Base32OutputStream wraps itself in encode and decode 215 * mode over and over again. 216 * 217 * @param encoded 218 * Base32 encoded data 219 * @param decoded 220 * the data from above, but decoded 221 * @param chunkSize 222 * chunk size (line-length) of the Base32 encoded data. 223 * @param seperator 224 * Line separator in the Base32 encoded data. 225 * @throws Exception 226 * Usually signifies a bug in the Base32 commons-codec implementation. 227 */ 228 private void testByteByByte(byte[] encoded, byte[] decoded, int chunkSize, byte[] seperator) throws Exception { 229 230 // Start with encode. 231 ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); 232 OutputStream out = new Base32OutputStream(byteOut, true, chunkSize, seperator); 233 for (byte element : decoded) { 234 out.write(element); 235 } 236 out.close(); 237 byte[] output = byteOut.toByteArray(); 238 assertTrue("Streaming byte-by-byte Base32 encode", Arrays.equals(output, encoded)); 239 240 // Now let's try decode. 241 byteOut = new ByteArrayOutputStream(); 242 out = new Base32OutputStream(byteOut, false); 243 for (byte element : encoded) { 244 out.write(element); 245 } 246 out.close(); 247 output = byteOut.toByteArray(); 248 assertTrue("Streaming byte-by-byte Base32 decode", Arrays.equals(output, decoded)); 249 250 // Now let's try decode with tonnes of flushes. 251 byteOut = new ByteArrayOutputStream(); 252 out = new Base32OutputStream(byteOut, false); 253 for (byte element : encoded) { 254 out.write(element); 255 out.flush(); 256 } 257 out.close(); 258 output = byteOut.toByteArray(); 259 assertTrue("Streaming byte-by-byte flush() Base32 decode", Arrays.equals(output, decoded)); 260 261 // I always wanted to do this! (wrap encoder with decoder etc etc). 262 byteOut = new ByteArrayOutputStream(); 263 out = byteOut; 264 for (int i = 0; i < 10; i++) { 265 out = new Base32OutputStream(out, false); 266 out = new Base32OutputStream(out, true, chunkSize, seperator); 267 } 268 for (byte element : decoded) { 269 out.write(element); 270 } 271 out.close(); 272 output = byteOut.toByteArray(); 273 274 assertTrue("Streaming byte-by-byte Base32 wrap-wrap-wrap!", Arrays.equals(output, decoded)); 275 } 276 277 /** 278 * Tests Base32OutputStream.write for expected IndexOutOfBoundsException conditions. 279 * 280 * @throws Exception 281 * for some failure scenarios. 282 */ 283 @Test 284 public void testWriteOutOfBounds() throws Exception { 285 byte[] buf = new byte[1024]; 286 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 287 Base32OutputStream out = new Base32OutputStream(bout); 288 289 try { 290 out.write(buf, -1, 1); 291 fail("Expected Base32OutputStream.write(buf, -1, 1) to throw a IndexOutOfBoundsException"); 292 } catch (IndexOutOfBoundsException ioobe) { 293 // Expected 294 } 295 296 try { 297 out.write(buf, 1, -1); 298 fail("Expected Base32OutputStream.write(buf, 1, -1) to throw a IndexOutOfBoundsException"); 299 } catch (IndexOutOfBoundsException ioobe) { 300 // Expected 301 } 302 303 try { 304 out.write(buf, buf.length + 1, 0); 305 fail("Expected Base32OutputStream.write(buf, buf.length + 1, 0) to throw a IndexOutOfBoundsException"); 306 } catch (IndexOutOfBoundsException ioobe) { 307 // Expected 308 } 309 310 try { 311 out.write(buf, buf.length - 1, 2); 312 fail("Expected Base32OutputStream.write(buf, buf.length - 1, 2) to throw a IndexOutOfBoundsException"); 313 } catch (IndexOutOfBoundsException ioobe) { 314 // Expected 315 } 316 out.close(); 317 } 318 319 /** 320 * Tests Base32OutputStream.write(null). 321 * 322 * @throws Exception 323 * for some failure scenarios. 324 */ 325 @Test 326 public void testWriteToNullCoverage() throws Exception { 327 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 328 Base32OutputStream out = new Base32OutputStream(bout); 329 try { 330 out.write(null, 0, 0); 331 fail("Expcted Base32OutputStream.write(null) to throw a NullPointerException"); 332 } catch (NullPointerException e) { 333 // Expected 334 } 335 out.close(); 336 } 337 338 }