// Copyright 2006 Google Inc. // // 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.google.enterprise.connector.util; import com.google.enterprise.connector.jcr.JcrConnector; import com.google.enterprise.connector.mock.MockRepository; import com.google.enterprise.connector.mock.MockRepositoryEventList; import com.google.enterprise.connector.mock.jcr.MockJcrRepository; import com.google.enterprise.connector.spi.Document; import com.google.enterprise.connector.spi.SpiConstants; import com.google.enterprise.connector.spi.TraversalManager; import com.google.enterprise.connector.spi.Value; import com.google.enterprise.connector.spiimpl.BinaryValue; import junit.framework.Assert; import junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; /** * Test for Base64FilterInputStream */ public class Base64FilterInputStreamTest extends TestCase { public void testRead() throws IOException { byte[] bytes = new byte[]{ 'a', 'b', 'c'}; ByteArrayInputStream bais = new ByteArrayInputStream(bytes); Base64FilterInputStream is = new Base64FilterInputStream(bais); int val; byte[] expectedBytes = new byte[]{ 'Y', 'W', 'J', 'j' }; byte[] resultBytes = new byte[expectedBytes.length]; int index = 0; while (-1 != (val = is.read())) { resultBytes[index] = (byte) val; index++; } Assert.assertTrue(Arrays.equals(expectedBytes, resultBytes)); } public void testReadArray() throws IOException { byte[] bytes = new byte[]{ 'a', 'b', 'c', 'd' }; ByteArrayInputStream bais = new ByteArrayInputStream(bytes); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] expectedBytes = new byte[]{ 'Y', 'W', 'J', 'j', 'Z', 'A', '=', '=' }; byte[] resultBytes = new byte[expectedBytes.length]; int bytesRead = is.read(resultBytes, 0, resultBytes.length); Assert.assertEquals(expectedBytes.length, bytesRead); Assert.assertTrue(Arrays.equals(expectedBytes, resultBytes)); } /** * Compare results from read() and read(bytes[], int, int) methods. * * @throws IOException */ public void testReadMethods() throws IOException { byte[] bytes = new byte[]{ 'a' }; ByteArrayInputStream bais1 = new ByteArrayInputStream(bytes); Base64FilterInputStream is1 = new Base64FilterInputStream(bais1); ByteArrayInputStream bais2 = new ByteArrayInputStream(bytes); Base64FilterInputStream is2 = new Base64FilterInputStream(bais2); int val; byte[] resultBytes = new byte[4]; val = is1.read(resultBytes, 0, 4); Assert.assertEquals(4, val); int index = 0; while (-1 != (val = is2.read())) { Assert.assertTrue(resultBytes[index] == (byte) val); index++; } } /** * ByteArrayInputStream that returns a single byte at a time even if you * request more. */ private static class SingleByteArrayInputStream extends ByteArrayInputStream { public SingleByteArrayInputStream(byte[] bytes) { super(bytes); } @Override public int read(byte[] b, int off, int len) { int byteValue = read(); if (-1 == byteValue) { return -1; } else { b[off] = (byte) byteValue; return 1; } } } /** * Test that this stream works even if the underlying stream does not return * bytes in multiples of 3. */ public void testBug243976() throws IOException { byte[] bytes = new byte[]{ 'a', 'b', 'c'}; SingleByteArrayInputStream bais = new SingleByteArrayInputStream(bytes); Base64FilterInputStream is = new Base64FilterInputStream(bais); int val; byte[] expectedBytes = new byte[]{ 'Y', 'W', 'J', 'j' }; byte[] resultBytes = new byte[expectedBytes.length]; int index = 0; while (-1 != (val = is.read())) { resultBytes[index] = (byte) val; index++; } Assert.assertTrue(Arrays.equals(expectedBytes, resultBytes)); } /** * Tests that the <code>JcrConnector</code> when used with a Stream value * maintains the original encoding of the binary content. */ public void testBug1721179() throws Exception { // Encode the raw file. File rawFile = new File("testdata/mocktestdata/test.doc"); InputStream rawIs = new FileInputStream(rawFile); InputStream rawEis = new Base64FilterInputStream(rawIs); // Encode the content from the JcrConnector. This creates a JcrConnector // like the Test Connector would and then extracts the document and the // content stream property as it is done during traversal. MockRepositoryEventList eventList = new MockRepositoryEventList( "MockRepositoryEventLogBinaryFile.txt"); MockRepository mockRepo = new MockRepository(eventList); MockJcrRepository mockJcrRepo = new MockJcrRepository(mockRepo); JcrConnector jcrConn = new JcrConnector(mockJcrRepo); TraversalManager travMgr = jcrConn.login().getTraversalManager(); Document document = travMgr.startTraversal().nextDocument(); assertEquals("worddoc", Value.getSingleValueString(document, SpiConstants.PROPNAME_DOCID)); Value v = Value.getSingleValue(document, SpiConstants.PROPNAME_CONTENT); InputStream contentStream = ((BinaryValue) v).getInputStream(); InputStream encodedContentStream = new Base64FilterInputStream(contentStream); // Compare the bytes on each of the streams. int rawByte; while ((rawByte = rawEis.read()) != -1) { assertEquals(rawByte, encodedContentStream.read()); } assertEquals(-1, encodedContentStream.read()); // Clean up. rawEis.close(); encodedContentStream.close(); } static final String input = " Google's indices consist of information that has been" + " identified, indexed and compiled through an automated" + " process with no advance review by human beings. Given" + " the enormous volume of web site information added," + " deleted, and changed on a frequent basis, Google cannot" + " and does not screen anything made available through its" + " indices. For each web site reflected in Google's" + " indices, if either (i) a site owner restricts access to" + " his or her web site or (ii) a site is taken down from" + " the web, then, upon receipt of a request by the site" + " owner or a third party in the second instance, Google" + " would consider on a case-by-case basis requests to" + " remove the link to that site from its indices. However," + " if the operator of the site does not take steps to" + " prevent it, the automatic facilities used to create" + " the indices are likely to find that site and index it" + " again in a relatively short amount of time."; static final String expect = "IEdvb2dsZSdzIGluZGljZXMgY29uc2lzdCBvZiBpbmZvcm1hdGlvbi" + "B0aGF0IGhhcyBiZWVuIGlkZW50aWZpZWQsIGluZGV4ZWQgYW5kIGNv" + "bXBpbGVkIHRocm91Z2ggYW4gYXV0b21hdGVkIHByb2Nlc3Mgd2l0aC" + "BubyBhZHZhbmNlIHJldmlldyBieSBodW1hbiBiZWluZ3MuIEdpdmVu" + "IHRoZSBlbm9ybW91cyB2b2x1bWUgb2Ygd2ViIHNpdGUgaW5mb3JtYX" + "Rpb24gYWRkZWQsIGRlbGV0ZWQsIGFuZCBjaGFuZ2VkIG9uIGEgZnJl" + "cXVlbnQgYmFzaXMsIEdvb2dsZSBjYW5ub3QgYW5kIGRvZXMgbm90IH" + "NjcmVlbiBhbnl0aGluZyBtYWRlIGF2YWlsYWJsZSB0aHJvdWdoIGl0" + "cyBpbmRpY2VzLiBGb3IgZWFjaCB3ZWIgc2l0ZSByZWZsZWN0ZWQgaW" + "4gR29vZ2xlJ3MgaW5kaWNlcywgaWYgZWl0aGVyIChpKSBhIHNpdGUg" + "b3duZXIgcmVzdHJpY3RzIGFjY2VzcyB0byBoaXMgb3IgaGVyIHdlYi" + "BzaXRlIG9yIChpaSkgYSBzaXRlIGlzIHRha2VuIGRvd24gZnJvbSB0" + "aGUgd2ViLCB0aGVuLCB1cG9uIHJlY2VpcHQgb2YgYSByZXF1ZXN0IG" + "J5IHRoZSBzaXRlIG93bmVyIG9yIGEgdGhpcmQgcGFydHkgaW4gdGhl" + "IHNlY29uZCBpbnN0YW5jZSwgR29vZ2xlIHdvdWxkIGNvbnNpZGVyIG" + "9uIGEgY2FzZS1ieS1jYXNlIGJhc2lzIHJlcXVlc3RzIHRvIHJlbW92" + "ZSB0aGUgbGluayB0byB0aGF0IHNpdGUgZnJvbSBpdHMgaW5kaWNlcy" + "4gSG93ZXZlciwgaWYgdGhlIG9wZXJhdG9yIG9mIHRoZSBzaXRlIGRv" + "ZXMgbm90IHRha2Ugc3RlcHMgdG8gcHJldmVudCBpdCwgdGhlIGF1dG" + "9tYXRpYyBmYWNpbGl0aWVzIHVzZWQgdG8gY3JlYXRlIHRoZSBpbmRp" + "Y2VzIGFyZSBsaWtlbHkgdG8gZmluZCB0aGF0IHNpdGUgYW5kIGluZG" + "V4IGl0IGFnYWluIGluIGEgcmVsYXRpdmVseSBzaG9ydCBhbW91bnQg" + "b2YgdGltZS4="; static final String expectNL = "IEdvb2dsZSdzIGluZGljZXMgY29uc2lzdCBvZiBpbmZvcm1hdGlvbiB0aGF0IGhhcyBiZWVuIGlk\n" + "ZW50aWZpZWQsIGluZGV4ZWQgYW5kIGNvbXBpbGVkIHRocm91Z2ggYW4gYXV0b21hdGVkIHByb2Nl\n" + "c3Mgd2l0aCBubyBhZHZhbmNlIHJldmlldyBieSBodW1hbiBiZWluZ3MuIEdpdmVuIHRoZSBlbm9y\n" + "bW91cyB2b2x1bWUgb2Ygd2ViIHNpdGUgaW5mb3JtYXRpb24gYWRkZWQsIGRlbGV0ZWQsIGFuZCBj\n" + "aGFuZ2VkIG9uIGEgZnJlcXVlbnQgYmFzaXMsIEdvb2dsZSBjYW5ub3QgYW5kIGRvZXMgbm90IHNj\n" + "cmVlbiBhbnl0aGluZyBtYWRlIGF2YWlsYWJsZSB0aHJvdWdoIGl0cyBpbmRpY2VzLiBGb3IgZWFj\n" + "aCB3ZWIgc2l0ZSByZWZsZWN0ZWQgaW4gR29vZ2xlJ3MgaW5kaWNlcywgaWYgZWl0aGVyIChpKSBh\n" + "IHNpdGUgb3duZXIgcmVzdHJpY3RzIGFjY2VzcyB0byBoaXMgb3IgaGVyIHdlYiBzaXRlIG9yIChp\n" + "aSkgYSBzaXRlIGlzIHRha2VuIGRvd24gZnJvbSB0aGUgd2ViLCB0aGVuLCB1cG9uIHJlY2VpcHQg\n" + "b2YgYSByZXF1ZXN0IGJ5IHRoZSBzaXRlIG93bmVyIG9yIGEgdGhpcmQgcGFydHkgaW4gdGhlIHNl\n" + "Y29uZCBpbnN0YW5jZSwgR29vZ2xlIHdvdWxkIGNvbnNpZGVyIG9uIGEgY2FzZS1ieS1jYXNlIGJh\n" + "c2lzIHJlcXVlc3RzIHRvIHJlbW92ZSB0aGUgbGluayB0byB0aGF0IHNpdGUgZnJvbSBpdHMgaW5k\n" + "aWNlcy4gSG93ZXZlciwgaWYgdGhlIG9wZXJhdG9yIG9mIHRoZSBzaXRlIGRvZXMgbm90IHRha2Ug\n" + "c3RlcHMgdG8gcHJldmVudCBpdCwgdGhlIGF1dG9tYXRpYyBmYWNpbGl0aWVzIHVzZWQgdG8gY3Jl\n" + "YXRlIHRoZSBpbmRpY2VzIGFyZSBsaWtlbHkgdG8gZmluZCB0aGF0IHNpdGUgYW5kIGluZGV4IGl0\n" + "IGFnYWluIGluIGEgcmVsYXRpdmVseSBzaG9ydCBhbW91bnQgb2YgdGltZS4="; /* Test read() interface. */ public void testRead1() throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] resultBytes = new byte[expect.length()]; int val; int index = 0; while (-1 != (val = is.read())) { resultBytes[index] = (byte) val; index++; } Assert.assertTrue(expect.equals(new String(resultBytes, "UTF-8"))); } /* Test read(byte[]) interface. */ public void testReadByteArray() throws Exception { byteArrayRead(1); byteArrayRead(2); byteArrayRead(3); byteArrayRead(4); byteArrayRead(5); byteArrayRead(6); byteArrayRead(7); byteArrayRead(8); byteArrayRead(16); byteArrayRead(23); byteArrayRead(64); byteArrayRead(expect.length()); byteArrayRead(((expect.length() + 3)/4)*4); byteArrayRead(expect.length() - 1); byteArrayRead(2048); } /* Test read(byte[], off, len) interface. */ public void testReadByteArrayWithOffLen() throws Exception { byteArrayRead2(1); byteArrayRead2(2); byteArrayRead2(3); byteArrayRead2(4); byteArrayRead2(5); byteArrayRead2(6); byteArrayRead2(7); byteArrayRead2(8); byteArrayRead2(16); byteArrayRead2(23); byteArrayRead2(64); byteArrayRead2(expect.length()); byteArrayRead2(((expect.length() + 3)/4)*4); byteArrayRead2(expect.length() - 1); byteArrayRead2(2048); } /* Test read(byte[], off, len) interface where off != 0. */ public void testReadByteArrayWithOffset() throws Exception { byteArrayRead3(1); byteArrayRead3(2); byteArrayRead3(3); byteArrayRead3(4); byteArrayRead3(5); byteArrayRead3(6); byteArrayRead3(7); byteArrayRead3(8); byteArrayRead3(16); byteArrayRead3(23); byteArrayRead3(64); byteArrayRead3(expect.length()); byteArrayRead3(((expect.length() + 3)/4)*4); byteArrayRead3(expect.length() - 1); byteArrayRead3(2048); } /* Test use of mixed read() and read(byte[], off, len) interface. */ public void testReadWithReadByteArray() throws Exception { byteArrayRead4(1, 1); byteArrayRead4(2, 1); byteArrayRead4(3, 1); byteArrayRead4(4, 1); byteArrayRead4(5, 1); byteArrayRead4(6, 1); byteArrayRead4(7, 1); byteArrayRead4(8, 1); byteArrayRead4(16, 1); byteArrayRead4(23, 1); byteArrayRead4(64, 1); byteArrayRead4(expect.length(), 1); byteArrayRead4(((expect.length() + 3)/4)*4, 1); byteArrayRead4(expect.length() - 1, 1); byteArrayRead4(2048, 1); byteArrayRead4(1, 2); byteArrayRead4(2, 2); byteArrayRead4(3, 2); byteArrayRead4(4, 2); byteArrayRead4(5, 2); byteArrayRead4(6, 2); byteArrayRead4(7, 2); byteArrayRead4(8, 2); byteArrayRead4(16, 2); byteArrayRead4(23, 2); byteArrayRead4(64, 2); byteArrayRead4(expect.length(), 2); byteArrayRead4(((expect.length() + 3)/4)*4, 2); byteArrayRead4(expect.length() - 1, 2); byteArrayRead4(2048, 2); byteArrayRead4(1, 3); byteArrayRead4(2, 3); byteArrayRead4(3, 3); byteArrayRead4(4, 3); byteArrayRead4(5, 3); byteArrayRead4(6, 3); byteArrayRead4(7, 3); byteArrayRead4(8, 3); byteArrayRead4(16, 3); byteArrayRead4(23, 3); byteArrayRead4(64, 3); byteArrayRead4(expect.length(), 3); byteArrayRead4(((expect.length() + 3)/4)*4, 3); byteArrayRead4(expect.length() - 1, 3); byteArrayRead4(2048, 3); byteArrayRead4(1, 4); byteArrayRead4(2, 4); byteArrayRead4(3, 4); byteArrayRead4(4, 4); byteArrayRead4(5, 4); byteArrayRead4(6, 4); byteArrayRead4(7, 4); byteArrayRead4(8, 4); byteArrayRead4(16, 4); byteArrayRead4(23, 4); byteArrayRead4(64, 4); byteArrayRead4(expect.length(), 4); byteArrayRead4(((expect.length() + 3)/4)*4, 4); byteArrayRead4(expect.length() - 1, 4); byteArrayRead4(2048, 4); } /* Test read(byte[], off, len) interface with newlines in output. */ public void testReadByteArrayWithNewLines() throws Exception { byteArrayRead5(77); byteArrayRead5(80); byteArrayRead5(190); byteArrayRead5(expectNL.length()); byteArrayRead5(expectNL.length() + 1); byteArrayRead5(2048); } /* Test read(byte[], off, len) when < less than BASE64_LINE_LENGTH * doesn't produce newlines, even when asked. */ public void testReadByteArrayWithoutNewLines() throws Exception { byteArrayRead6(38); byteArrayRead6(76); } /* Test read(byte[]) interface. */ public void byteArrayRead(int buffsize) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] resultBytes = new byte[buffsize]; StringBuffer resultBuffer = new StringBuffer(expect.length()); int val; while (-1 != (val = is.read(resultBytes))) { resultBuffer.append(new String(resultBytes, 0, val, "UTF-8")); } Assert.assertTrue(expect.equals(resultBuffer.toString())); } /* Test read(byte[], off, len) interface. */ public void byteArrayRead2(int buffsize) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] resultBytes = new byte[buffsize]; StringBuffer resultBuffer = new StringBuffer(expect.length()); int val; while (-1 != (val = is.read(resultBytes, 0, buffsize))) { resultBuffer.append(new String(resultBytes, 0, val, "UTF-8")); } Assert.assertTrue(expect.equals(resultBuffer.toString())); } /* Test read(byte[], off, len) interface, where off != 0. */ public void byteArrayRead3(int buffsize) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] resultBytes = new byte[buffsize + 3]; StringBuffer resultBuffer = new StringBuffer(expect.length()); int val; while (-1 != (val = is.read(resultBytes, 3, buffsize))) { resultBuffer.append(new String(resultBytes, 3, val, "UTF-8")); } Assert.assertTrue(expect.equals(resultBuffer.toString())); } /* Test use of mixed read() and read(byte[], off, len) interface. */ public void byteArrayRead4(int buffsize, int readsize) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais); byte[] resultBytes = new byte[buffsize]; StringBuffer resultBuffer = new StringBuffer(expect.length()); int val; while ((readsize-- > 0) && (-1 != (val = is.read()))) { resultBuffer.append((char) val); } while (-1 != (val = is.read(resultBytes, 0, buffsize))) { resultBuffer.append(new String(resultBytes, 0, val, "UTF-8")); } Assert.assertTrue(expect.equals(resultBuffer.toString())); } /* Test read(byte[], off, len) interface, where off != 0, * and newlines in output. */ public void byteArrayRead5(int buffsize) throws Exception { Assert.assertTrue((buffsize > 76)); ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais, true); byte[] resultBytes = new byte[buffsize + 3]; StringBuffer resultBuffer = new StringBuffer(expectNL.length()); int val; while (-1 != (val = is.read(resultBytes, 3, buffsize))) { resultBuffer.append(new String(resultBytes, 3, val, "UTF-8")); } Assert.assertTrue(expectNL.equals(resultBuffer.toString())); } /* Test read(byte[], off, len) interface, where len <= BASE64_LINE_LENGTH * and newlines are requested. No newlines should actually be produced. */ public void byteArrayRead6(int buffsize) throws Exception { Assert.assertTrue((buffsize <= 76)); ByteArrayInputStream bais = new ByteArrayInputStream(input.getBytes()); Base64FilterInputStream is = new Base64FilterInputStream(bais, true); byte[] resultBytes = new byte[buffsize]; StringBuffer resultBuffer = new StringBuffer(expect.length()); int val; while (-1 != (val = is.read(resultBytes, 0, buffsize))) { resultBuffer.append(new String(resultBytes, 0, val, "UTF-8")); } Assert.assertTrue(expect.equals(resultBuffer.toString())); } }