/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * muCommander is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.commons.io.base64; import org.testng.annotations.Test; import java.io.IOException; import java.util.Random; /** * A test case for the <code>com.mucommander.commons.io.base64</code> package. * * @author Maxence Bernard, Nicolas Rinaudo */ public class Base64Test { /** * Tests base64 encoding and decoding on known sequences, ensuring that base 64 encoding and decoding produces * the expected results. * * @throws IOException should not happen */ @Test public void testKnownSequences() throws IOException { // On an ASCII sequence testKnownSequence("The quick brown fox jumps over the lazy dog.", "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4="); // On a Unicode sequence. Note that the string has been encoded using UTF-8 bytes. testKnownSequence("どうもありがとうミスターロボット", "44Gp44GG44KC44GC44KK44GM44Go44GG44Of44K544K/44O844Ot44Oc44OD44OI"); } /** * Tests base64 encoding and decoding on a known sequence, ensuring that base 64 encoding and decoding produces * the expected results. * * @param decodedSequence the base64-decoded string * @param encodedSequence the base64-encoding string * @throws IOException should not happen */ private void testKnownSequence(String decodedSequence, String encodedSequence) throws IOException { assert encodedSequence.equals(Base64Encoder.encode(decodedSequence, "UTF-8", Base64Table.STANDARD_TABLE)); assert decodedSequence.equals(Base64Decoder.decode(encodedSequence, "UTF-8", Base64Table.STANDARD_TABLE)); } /** * Successively encodes and decodes randomly-generated strings of varying length and content, and verifies that * the resulting string remains the same as the original. * * @throws IOException should not happen */ @Test public void testRandomStringIntegrity() throws IOException { Random random = new Random(); StringBuffer sb; String s; int slen; // Repeats the test for(int i=0; i<100; i++) { // Generates a string with: // - a random length of up to 1000 characters // - random contents, where each byte's value is randomly chosen between 0 and 255 slen = random.nextInt(1000); sb = new StringBuffer(); for(int j=0; j<slen; j++) sb.append((char)random.nextInt(256)); s = sb.toString(); assert s.equals(Base64Decoder.decode(Base64Encoder.encode(s, "UTF-8", Base64Table.STANDARD_TABLE))); } } /** * Validates that <code>java.io.IOException</code> is properly thrown by {@link Base64InputStream} * when a character out of the base64 range is encountered. All such characters are successively tested. */ @Test public void testInvalidCharacters() { char c; boolean exceptionCaught; for(c=0; c<256; c++) { // Skip allowed Base64 characters, including the special '=' character used for padding if((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='+' || c=='/' || c=='=') continue; exceptionCaught = false; try { Base64Decoder.decode(c+"==="); // Add padding at the end } catch(IOException e) { exceptionCaught = true; } assert exceptionCaught; } } /** * Validates that <code>java.io.IOException</code> is properly thrown by {@link Base64InputStream} * when the provided Base64 string's length is not a multiple of 4 (i.e. is not properly padded with '='). */ @Test public void testInvalidLength() { String invalidLengthStrings[] = { "a", "ab", "abc", "=", "a=", "a==", "ab=", "0000a", "0000ab", "0000abc", "0000a=", "0000a==", "0000ab=" }; boolean exceptionCaught; for (String invalidLengthString : invalidLengthStrings) { exceptionCaught = false; try { Base64Decoder.decode(invalidLengthString); } catch (IOException e) { exceptionCaught = true; } assert exceptionCaught; } } /** * Tests {@link Base64Table} preset instances. * * @throws IOException should not happen */ @Test public void testPresetTables() throws IOException { Base64Table[] tables = new Base64Table[] { Base64Table.STANDARD_TABLE, Base64Table.URL_SAFE_TABLE, Base64Table.FILENAME_SAFE_TABLE, Base64Table.REGEXP_SAFE_TABLE, }; String sample = "The quick brown fox jumps over the lazy dog."; for(Base64Table table: tables) { // Ensure that the table passes Base64Table constructor's tests new Base64Table(table.getEncodingTable(), table.getPaddingChar()); // Ensures that encoding followed by decoding yields the original string assert sample.equals(Base64Decoder.decode(Base64Encoder.encode(sample, "UTF-8", table), "UTF-8", table)); } } /** * Tests {@link Base64Table#Base64Table(byte[], byte)} with invalid parameter values. */ @Test public void testCustomBase64Table() { testInvalidBase64Table(null, (byte)'a'); testInvalidBase64Table(new byte[]{}, (byte)'a'); byte[] validEncodingTable = Base64Table.STANDARD_TABLE.getEncodingTable(); testInvalidBase64Table(validEncodingTable, (byte)'a'); byte[] invalidEncodingTable = new byte[63]; System.arraycopy(validEncodingTable, 0, invalidEncodingTable, 0, 63); testInvalidBase64Table(invalidEncodingTable, (byte)'a'); invalidEncodingTable = new byte[64]; System.arraycopy(validEncodingTable, 0, invalidEncodingTable, 0, 64); invalidEncodingTable[63] = 'b'; testInvalidBase64Table(invalidEncodingTable, (byte)'a'); // Test a valid custom Base64 table new Base64Table(new byte[]{ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','@','!' }, (byte)'%'); } /** * Tries to create a <code>Base64Table</code> with the specified parameters and asserts that it throws * an {@link IllegalArgumentException}. * * @param table the base64 character table. The array must be 64 bytes long and must not contain any duplicate values. * @param paddingChar the ASCII character used for padding. This character must not already be used in the table. */ private void testInvalidBase64Table(byte[] table, byte paddingChar) { boolean exceptionThrown = false; try { new Base64Table(table, paddingChar); } catch(IllegalArgumentException e) { exceptionThrown = true; } assert exceptionThrown; } }