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