Home | History | Annotate | Download | only in io
      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