• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.google.archivepatcher.applier;
16 
17 import com.google.archivepatcher.shared.JreDeflateParameters;
18 import com.google.archivepatcher.shared.TypedRange;
19 import com.google.archivepatcher.shared.UnitTestZipArchive;
20 import com.google.archivepatcher.shared.UnitTestZipEntry;
21 
22 import org.junit.Assert;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.junit.runners.JUnit4;
27 
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.util.Arrays;
31 import java.util.Collections;
32 
33 /**
34  * Tests for {@link PartiallyCompressingOutputStream}.
35  */
36 @RunWith(JUnit4.class)
37 @SuppressWarnings("javadoc")
38 public class PartiallyCompressingOutputStreamTest {
39   private ByteArrayOutputStream outBuffer;
40   private PartiallyCompressingOutputStream stream;
41 
42   // The preamble comes before any compressed bytes in the stream
43   private static byte[] PREAMBLE_BYTES = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
44 
45   // First range for compression
46   private static JreDeflateParameters PARAMS1 = JreDeflateParameters.of(1, 0, true);
47   private static UnitTestZipEntry ENTRY1 =
48       UnitTestZipArchive.makeUnitTestZipEntry(
49           "/foo", PARAMS1.level, PARAMS1.nowrap, "foo-level1", null);
50   private static long OFFSET1 = PREAMBLE_BYTES.length;
51   private static long LENGTH1 = ENTRY1.getUncompressedBinaryContent().length;
52   private static TypedRange<JreDeflateParameters> COMPRESS_RANGE_1 =
53       new TypedRange<JreDeflateParameters>(OFFSET1, LENGTH1, PARAMS1);
54 
55   private static byte[] GAP1_BYTES = new byte[] {37};
56 
57   // Second range for compression, with a gap in between. Note this changes nowrap and level
58   private static JreDeflateParameters PARAMS2 = JreDeflateParameters.of(6, 0, false);
59   private static UnitTestZipEntry ENTRY2 =
60       UnitTestZipArchive.makeUnitTestZipEntry(
61           "/bar", PARAMS2.level, PARAMS2.nowrap, "bar-level6", null);
62   private static long OFFSET2 = OFFSET1 + LENGTH1 + GAP1_BYTES.length;
63   private static long LENGTH2 = ENTRY2.getUncompressedBinaryContent().length;
64   private static TypedRange<JreDeflateParameters> COMPRESS_RANGE_2 =
65       new TypedRange<JreDeflateParameters>(OFFSET2, LENGTH2, PARAMS2);
66 
fuse(byte[]... arrays)67   private byte[] fuse(byte[]... arrays) throws IOException {
68     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
69     for (byte[] array : arrays) {
70       buffer.write(array);
71     }
72     return buffer.toByteArray();
73   }
74 
75   @Before
setup()76   public void setup() {
77     outBuffer = new ByteArrayOutputStream();
78   }
79 
80   @Test
testWrite_Nothing()81   public void testWrite_Nothing() throws IOException {
82     // Test the case where there are no compression ranges at all and nothing is written.
83     stream =
84         new PartiallyCompressingOutputStream(
85             Collections.<TypedRange<JreDeflateParameters>>emptyList(), outBuffer, 32768);
86     byte[] input = new byte[] {};
87     stream.write(input);
88     stream.flush();
89     stream.close();
90     Assert.assertArrayEquals(input, outBuffer.toByteArray());
91   }
92 
93   @Test
testWrite_NoneCompressed()94   public void testWrite_NoneCompressed() throws IOException {
95     // Test the case where there are no compression ranges at all.
96     stream =
97         new PartiallyCompressingOutputStream(
98             Collections.<TypedRange<JreDeflateParameters>>emptyList(), outBuffer, 32768);
99     byte[] input = new byte[] {1, 77, 66, 44, 22, 11};
100     byte[] expected = input.clone();
101     stream.write(input);
102     stream.flush();
103     Assert.assertArrayEquals(expected, outBuffer.toByteArray());
104   }
105 
106   @Test
testWrite_AllCompressed()107   public void testWrite_AllCompressed() throws IOException {
108     // Test the case where a single compression range covers the entire input
109     TypedRange<JreDeflateParameters> range =
110         new TypedRange<JreDeflateParameters>(
111             0, ENTRY1.getUncompressedBinaryContent().length, PARAMS1);
112     stream =
113         new PartiallyCompressingOutputStream(Collections.singletonList(range), outBuffer, 32768);
114     stream.write(ENTRY1.getUncompressedBinaryContent());
115     stream.flush();
116     Assert.assertArrayEquals(ENTRY1.getCompressedBinaryContent(), outBuffer.toByteArray());
117   }
118 
119   @Test
testWrite_GapAndCompression()120   public void testWrite_GapAndCompression() throws IOException {
121     // Write uncompressed data followed by compressed data
122     stream =
123         new PartiallyCompressingOutputStream(
124             Collections.singletonList(COMPRESS_RANGE_1), outBuffer, 32768);
125     byte[] input = fuse(PREAMBLE_BYTES, ENTRY1.getUncompressedBinaryContent());
126     byte[] expected = fuse(PREAMBLE_BYTES, ENTRY1.getCompressedBinaryContent());
127     stream.write(input);
128     stream.flush();
129     Assert.assertArrayEquals(expected, outBuffer.toByteArray());
130   }
131 
132   @Test
testWrite_GapAndCompressionAndGap()133   public void testWrite_GapAndCompressionAndGap() throws IOException {
134     // Write uncompressed data followed by compressed data and another bit of uncompressed data
135     stream =
136         new PartiallyCompressingOutputStream(
137             Collections.singletonList(COMPRESS_RANGE_1), outBuffer, 32768);
138     byte[] input = fuse(PREAMBLE_BYTES, ENTRY1.getUncompressedBinaryContent(), GAP1_BYTES);
139     byte[] expected = fuse(PREAMBLE_BYTES, ENTRY1.getCompressedBinaryContent(), GAP1_BYTES);
140     stream.write(input);
141     stream.flush();
142     Assert.assertArrayEquals(expected, outBuffer.toByteArray());
143   }
144 
145   @Test
testWrite_MixedSequence_Thrash()146   public void testWrite_MixedSequence_Thrash() throws IOException {
147     // Write uncompressed data, compressed data, uncompressed data, compressed data (new params)
148     // Thrash by writing one byte at a time to pound on edge-casey code
149     stream =
150         new PartiallyCompressingOutputStream(
151             Arrays.asList(COMPRESS_RANGE_1, COMPRESS_RANGE_2), outBuffer, 32768);
152     byte[] input =
153         fuse(
154             PREAMBLE_BYTES,
155             ENTRY1.getUncompressedBinaryContent(),
156             GAP1_BYTES,
157             ENTRY2.getUncompressedBinaryContent());
158     byte[] expected =
159         fuse(
160             PREAMBLE_BYTES,
161             ENTRY1.getCompressedBinaryContent(),
162             GAP1_BYTES,
163             ENTRY2.getCompressedBinaryContent());
164     for (int x = 0; x < input.length; x++) {
165       stream.write(input[x] & 0xff);
166       stream.flush();
167     }
168     stream.close();
169     Assert.assertArrayEquals(expected, outBuffer.toByteArray());
170   }
171 }
172