1package org.brotli.wrapper.enc;
2
3import static org.junit.Assert.assertEquals;
4
5import org.brotli.integration.BundleHelper;
6import org.brotli.wrapper.dec.BrotliInputStream;
7import java.io.ByteArrayInputStream;
8import java.io.ByteArrayOutputStream;
9import java.io.FileInputStream;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.OutputStream;
13import java.util.List;
14import junit.framework.TestCase;
15import junit.framework.TestSuite;
16import org.junit.runner.RunWith;
17import org.junit.runners.AllTests;
18
19/** Tests for {@link org.brotli.wrapper.enc.BrotliOutputStream}. */
20@RunWith(AllTests.class)
21public class BrotliOutputStreamTest {
22
23  private enum TestMode {
24    WRITE_ALL,
25    WRITE_CHUNKS,
26    WRITE_BYTE
27  }
28
29  // TODO: remove when Bazel get JNI support.
30  static {
31    System.load(new java.io.File(new java.io.File(System.getProperty("java.library.path")),
32        "liblibjni.so").getAbsolutePath());
33  }
34
35  private static final int CHUNK_SIZE = 256;
36
37  static InputStream getBundle() throws IOException {
38    return new FileInputStream(System.getProperty("TEST_BUNDLE"));
39  }
40
41  /** Creates a test suite. */
42  public static TestSuite suite() throws IOException {
43    TestSuite suite = new TestSuite();
44    InputStream bundle = getBundle();
45    try {
46      List<String> entries = BundleHelper.listEntries(bundle);
47      for (String entry : entries) {
48        suite.addTest(new StreamTestCase(entry, TestMode.WRITE_ALL));
49        suite.addTest(new StreamTestCase(entry, TestMode.WRITE_CHUNKS));
50        suite.addTest(new StreamTestCase(entry, TestMode.WRITE_BYTE));
51      }
52    } finally {
53      bundle.close();
54    }
55    return suite;
56  }
57
58  /** Test case with a unique name. */
59  static class StreamTestCase extends TestCase {
60    final String entryName;
61    final TestMode mode;
62    StreamTestCase(String entryName, TestMode mode) {
63      super("BrotliOutputStreamTest." + entryName + "." + mode.name());
64      this.entryName = entryName;
65      this.mode = mode;
66    }
67
68    @Override
69    protected void runTest() throws Throwable {
70      BrotliOutputStreamTest.run(entryName, mode);
71    }
72  }
73
74  private static void run(String entryName, TestMode mode) throws Throwable {
75    InputStream bundle = getBundle();
76    byte[] original;
77    try {
78      original = BundleHelper.readEntry(bundle, entryName);
79    } finally {
80      bundle.close();
81    }
82    if (original == null) {
83      throw new RuntimeException("Can't read bundle entry: " + entryName);
84    }
85
86    if ((mode == TestMode.WRITE_CHUNKS) && (original.length <= CHUNK_SIZE)) {
87      return;
88    }
89
90    ByteArrayOutputStream dst = new ByteArrayOutputStream();
91    OutputStream encoder = new BrotliOutputStream(dst);
92    try {
93      switch (mode) {
94        case WRITE_ALL:
95          encoder.write(original);
96          break;
97
98        case WRITE_CHUNKS:
99          for (int offset = 0; offset < original.length; offset += CHUNK_SIZE) {
100            encoder.write(original, offset, Math.min(CHUNK_SIZE, original.length - offset));
101          }
102          break;
103
104        case WRITE_BYTE:
105          for (byte singleByte : original) {
106            encoder.write(singleByte);
107          }
108          break;
109      }
110    } finally {
111      encoder.close();
112    }
113
114    InputStream decoder = new BrotliInputStream(new ByteArrayInputStream(dst.toByteArray()));
115    try {
116      long originalCrc = BundleHelper.fingerprintStream(new ByteArrayInputStream(original));
117      long crc = BundleHelper.fingerprintStream(decoder);
118      assertEquals(originalCrc, crc);
119    } finally {
120      decoder.close();
121    }
122  }
123}
124