/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.email.codec.binary; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; /** * A series of tests of the Base64 encoder. */ @SmallTest public class Base64Test extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); } @Override protected void tearDown() throws Exception { super.tearDown(); } /** * Looking for issues with line length and trailing zeros. The code we're modeling is * in mail.internet.TextBody: * byte[] bytes = mBody.getBytes("UTF-8"); * out.write(Base64.encodeBase64Chunked(bytes)); */ public void testLineLength54() { byte[] out = Base64.encodeBase64Chunked(getByteArray(54)); checkBase64Structure(out, 1); } public void testLineLength55() { byte[] out = Base64.encodeBase64Chunked(getByteArray(55)); checkBase64Structure(out, 1); } public void testLineLength56() { byte[] out = Base64.encodeBase64Chunked(getByteArray(56)); checkBase64Structure(out, 1); } public void testLineLength57() { byte[] out = Base64.encodeBase64Chunked(getByteArray(57)); checkBase64Structure(out, 1); } public void testLineLength58() { byte[] out = Base64.encodeBase64Chunked(getByteArray(58)); checkBase64Structure(out, 2); } public void testLineLength59() { byte[] out = Base64.encodeBase64Chunked(getByteArray(59)); checkBase64Structure(out, 2); } /** * Repeat the above tests with 2x line lengths */ public void testLineLength111() { byte[] out = Base64.encodeBase64Chunked(getByteArray(111)); checkBase64Structure(out, 2); } public void testLineLength112() { byte[] out = Base64.encodeBase64Chunked(getByteArray(112)); checkBase64Structure(out, 2); } public void testLineLength113() { byte[] out = Base64.encodeBase64Chunked(getByteArray(113)); checkBase64Structure(out, 2); } public void testLineLength114() { byte[] out = Base64.encodeBase64Chunked(getByteArray(114)); checkBase64Structure(out, 2); } public void testLineLength115() { byte[] out = Base64.encodeBase64Chunked(getByteArray(115)); checkBase64Structure(out, 3); } /** * Validate that base64 output is structurally sound. Does not independently confirm * that the actual encoding is valid. */ private void checkBase64Structure(byte[] buffer, int expectedChunks) { // outer loop - divide into chunks int chunkCount = 0; int chunkStart; int nextChunkStart = 0; int limit = buffer.length; while (nextChunkStart < limit) { chunkStart = -1; int chunkEnd; for (chunkEnd = nextChunkStart; chunkEnd < limit; ++chunkEnd) { assertFalse("nulls in chunk", buffer[chunkEnd] == 0); if (buffer[chunkEnd] == '\r') { assertTrue(buffer[chunkEnd+1] == '\n'); chunkStart = nextChunkStart; break; } if (chunkEnd == limit) { chunkStart = nextChunkStart; break; } } chunkCount++; nextChunkStart = chunkEnd + 2; assertTrue("chunk not found", chunkStart >= 0); // At this point we have a single chunk from chunkStart to chunkEnd // And we can analyze it for structural correctness int chunkLen = chunkEnd - chunkStart; // Max chunk length assertTrue("chunk length <= 76", chunkLen <= 76); // Multiple of 4 (every 3 bytes of source -> 4 bytes of output) assertEquals("chunk length mod 4", 0, chunkLen % 4); // 0, 1 or 2 '=' at the end boolean lastEquals1 = buffer[chunkEnd-1] == '='; boolean lastEquals2 = buffer[chunkEnd-2] == '='; boolean lastEquals3 = buffer[chunkEnd-3] == '='; assertTrue("trailing equals", (!lastEquals1 && !lastEquals2) || // 0 (lastEquals1 && !lastEquals2) || // or 1 (lastEquals1 && lastEquals2)); // or 2 } assertEquals("total chunk count", expectedChunks, chunkCount); } /** * Generate a test sequence of a given length. */ private byte[] getByteArray(int size) { byte[] result = new byte[size]; byte fillChar = '1'; for (int i = 0; i < size; ++i) { result[i] = fillChar++; if (fillChar > '9') { fillChar = '0'; } } return result; } }