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