1 /* 2 * Copyright (C) 2012 The Guava Authors 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 com.google.common.io; 18 19 import static com.google.common.io.SourceSinkFactory.ByteSourceFactory; 20 import static com.google.common.io.SourceSinkFactory.CharSourceFactory; 21 import static org.junit.Assert.assertArrayEquals; 22 23 import com.google.common.base.Charsets; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.hash.HashCode; 26 import com.google.common.hash.Hashing; 27 28 import junit.framework.TestSuite; 29 30 import java.io.ByteArrayInputStream; 31 import java.io.ByteArrayOutputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.OutputStream; 35 import java.lang.reflect.Method; 36 import java.util.Map; 37 import java.util.Random; 38 39 /** 40 * A generator of {@code TestSuite} instances for testing {@code ByteSource} implementations. 41 * Generates tests of a all methods on a {@code ByteSource} given various inputs the source is 42 * expected to contain as well as as sub-suites for testing the {@code CharSource} view and 43 * {@code slice()} views in the same way. 44 * 45 * @author Colin Decker 46 */ 47 public class ByteSourceTester extends SourceSinkTester<ByteSource, byte[], ByteSourceFactory> { 48 49 private static final ImmutableList<Method> testMethods 50 = getTestMethods(ByteSourceTester.class); 51 52 static TestSuite tests(String name, ByteSourceFactory factory, boolean testAsCharSource) { 53 TestSuite suite = new TestSuite(name); 54 for (Map.Entry<String, String> entry : TEST_STRINGS.entrySet()) { 55 if (testAsCharSource) { 56 suite.addTest(suiteForString(factory, entry.getValue(), name, entry.getKey())); 57 } else { 58 suite.addTest(suiteForBytes( 59 factory, entry.getValue().getBytes(Charsets.UTF_8), name, entry.getKey(), true)); 60 } 61 } 62 return suite; 63 } 64 65 private static TestSuite suiteForString(ByteSourceFactory factory, String string, 66 String name, String desc) { 67 TestSuite suite = suiteForBytes(factory, string.getBytes(Charsets.UTF_8), name, desc, true); 68 CharSourceFactory charSourceFactory = SourceSinkFactories.asCharSourceFactory(factory); 69 suite.addTest(CharSourceTester.suiteForString(charSourceFactory, string, 70 name + ".asCharSource[Charset]", desc)); 71 return suite; 72 } 73 74 private static TestSuite suiteForBytes(ByteSourceFactory factory, byte[] bytes, 75 String name, String desc, boolean slice) { 76 TestSuite suite = new TestSuite(name + " [" + desc + "]"); 77 for (Method method : testMethods) { 78 suite.addTest(new ByteSourceTester(factory, bytes, name, desc, method)); 79 } 80 81 if (slice && bytes.length > 0) { 82 // test a random slice() of the ByteSource 83 Random random = new Random(); 84 byte[] expected = factory.getExpected(bytes); 85 // if expected.length == 0, off has to be 0 but length doesn't matter--result will be empty 86 int off = expected.length == 0 ? 0 : random.nextInt(expected.length); 87 int len = expected.length == 0 ? 4 : random.nextInt(expected.length - off); 88 ByteSourceFactory sliced = SourceSinkFactories.asSlicedByteSourceFactory(factory, off, len); 89 suite.addTest(suiteForBytes(sliced, bytes, name + ".slice[int, int]", 90 desc, false)); 91 } 92 93 return suite; 94 } 95 96 private ByteSource source; 97 98 public ByteSourceTester(ByteSourceFactory factory, byte[] bytes, 99 String suiteName, String caseDesc, Method method) { 100 super(factory, bytes, suiteName, caseDesc, method); 101 } 102 103 @Override 104 public void setUp() throws IOException { 105 source = factory.createSource(data); 106 } 107 108 public void testOpenStream() throws IOException { 109 InputStream in = source.openStream(); 110 try { 111 byte[] readBytes = ByteStreams.toByteArray(in); 112 assertExpectedBytes(readBytes); 113 } finally { 114 in.close(); 115 } 116 } 117 118 public void testOpenBufferedStream() throws IOException { 119 InputStream in = source.openBufferedStream(); 120 try { 121 byte[] readBytes = ByteStreams.toByteArray(in); 122 assertExpectedBytes(readBytes); 123 } finally { 124 in.close(); 125 } 126 } 127 128 public void testRead() throws IOException { 129 byte[] readBytes = source.read(); 130 assertExpectedBytes(readBytes); 131 } 132 133 public void testCopyTo_outputStream() throws IOException { 134 ByteArrayOutputStream out = new ByteArrayOutputStream(); 135 source.copyTo(out); 136 assertExpectedBytes(out.toByteArray()); 137 } 138 139 public void testCopyTo_byteSink() throws IOException { 140 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 141 // HERESY! but it's ok just for this I guess 142 source.copyTo(new ByteSink() { 143 @Override 144 public OutputStream openStream() throws IOException { 145 return out; 146 } 147 }); 148 assertExpectedBytes(out.toByteArray()); 149 } 150 151 public void testIsEmpty() throws IOException { 152 assertEquals(expected.length == 0, source.isEmpty()); 153 } 154 155 public void testSize() throws IOException { 156 assertEquals(expected.length, source.size()); 157 } 158 159 public void testContentEquals() throws IOException { 160 assertTrue(source.contentEquals(new ByteSource() { 161 @Override 162 public InputStream openStream() throws IOException { 163 return new RandomAmountInputStream( 164 new ByteArrayInputStream(expected), new Random()); 165 } 166 })); 167 } 168 169 public void testRead_usingByteProcessor() throws IOException { 170 byte[] readBytes = source.read(new ByteProcessor<byte[]>() { 171 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 172 173 @Override 174 public boolean processBytes(byte[] buf, int off, int len) throws IOException { 175 out.write(buf, off, len); 176 return true; 177 } 178 179 @Override 180 public byte[] getResult() { 181 return out.toByteArray(); 182 } 183 }); 184 185 assertExpectedBytes(readBytes); 186 } 187 188 public void testHash() throws IOException { 189 HashCode expectedHash = Hashing.md5().hashBytes(expected); 190 assertEquals(expectedHash, source.hash(Hashing.md5())); 191 } 192 193 public void testSlice_illegalArguments() { 194 try { 195 source.slice(-1, 0); 196 fail("expected IllegalArgumentException for call to slice with offset -1: " + source); 197 } catch (IllegalArgumentException expected) { 198 } 199 200 try { 201 source.slice(0, -1); 202 fail("expected IllegalArgumentException for call to slice with length -1: " + source); 203 } catch (IllegalArgumentException expected) { 204 } 205 } 206 207 private void assertExpectedBytes(byte[] readBytes) { 208 assertArrayEquals(expected, readBytes); 209 } 210 } 211