diff options
Diffstat (limited to 'generator')
8 files changed, 183 insertions, 202 deletions
diff --git a/generator/src/main/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDiviner.java b/generator/src/main/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDiviner.java index 636504d..d0c7a8b 100644 --- a/generator/src/main/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDiviner.java +++ b/generator/src/main/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDiviner.java @@ -14,10 +14,10 @@ package com.google.archivepatcher.generator; +import com.google.archivepatcher.shared.ByteArrayInputStreamFactory; import com.google.archivepatcher.shared.DefaultDeflateCompatibilityWindow; import com.google.archivepatcher.shared.JreDeflateParameters; import com.google.archivepatcher.shared.MultiViewInputStreamFactory; -import com.google.archivepatcher.shared.RandomAccessFileInputStream; import com.google.archivepatcher.shared.RandomAccessFileInputStreamFactory; import java.io.File; import java.io.IOException; @@ -41,15 +41,13 @@ import java.util.zip.ZipException; */ public class DefaultDeflateCompressionDiviner { - /** - * The levels to try for each strategy, in the order to attempt them. - */ - private final Map<Integer, List<Integer>> levelsByStrategy = getLevelsByStrategy(); + /** The levels to try for each strategy, in the order to attempt them. */ + private static final Map<Integer, List<Integer>> LEVELS_BY_STRATEGY = getLevelsByStrategy(); /** * A simple struct that contains a {@link MinimalZipEntry} describing a specific entry from a zip * archive along with an optional accompanying {@link JreDeflateParameters} describing the - * original compression settings that were used to generate the compressed data in that entry. + * original compression settings that were used to generate the compressed delivery in that entry. */ public static class DivinationResult { /** @@ -91,17 +89,30 @@ public class DefaultDeflateCompressionDiviner { * @see DivinationResult */ public List<DivinationResult> divineDeflateParameters(File archiveFile) throws IOException { - List<DivinationResult> results = new ArrayList<DivinationResult>(); + List<DivinationResult> results = new ArrayList<>(); for (MinimalZipEntry minimalZipEntry : MinimalZipArchive.listEntries(archiveFile)) { JreDeflateParameters divinedParameters = null; if (minimalZipEntry.isDeflateCompressed()) { - // TODO(andrewhayden): Reuse streams to avoid churning file descriptors - RandomAccessFileInputStreamFactory rafisFactory = + // TODO(pasc): Reuse streams to avoid churning file descriptors + MultiViewInputStreamFactory isFactory = new RandomAccessFileInputStreamFactory( archiveFile, minimalZipEntry.getFileOffsetOfCompressedData(), minimalZipEntry.getCompressedSize()); - divinedParameters = divineDeflateParameters(rafisFactory); + + // Keep small entries in memory to avoid unnecessary file I/O. + if (minimalZipEntry.getCompressedSize() < (100 * 1024)) { + try (InputStream is = isFactory.newStream()) { + byte[] compressedBytes = new byte[(int) minimalZipEntry.getCompressedSize()]; + is.read(compressedBytes); + divinedParameters = + divineDeflateParameters(new ByteArrayInputStreamFactory(compressedBytes)); + } catch (Exception ignore) { + divinedParameters = null; + } + } else { + divinedParameters = divineDeflateParameters(isFactory); + } } results.add(new DivinationResult(minimalZipEntry, divinedParameters)); } @@ -121,124 +132,103 @@ public class DefaultDeflateCompressionDiviner { * * @return such a mapping */ - protected Map<Integer, List<Integer>> getLevelsByStrategy() { - final Map<Integer, List<Integer>> levelsByStrategy = new HashMap<Integer, List<Integer>>(); + private static Map<Integer, List<Integer>> getLevelsByStrategy() { + final Map<Integer, List<Integer>> levelsByStrategy = new HashMap<>(); // The best order for the levels is simply the order of popularity in the world, which is // expected to be default (6), maximum compression (9), and fastest (1). // The rest of the levels are rarely encountered and their order is mostly irrelevant. levelsByStrategy.put(0, Collections.unmodifiableList(Arrays.asList(6, 9, 1, 4, 2, 3, 5, 7, 8))); levelsByStrategy.put(1, Collections.unmodifiableList(Arrays.asList(6, 9, 4, 5, 7, 8))); + // Strategy 2 does not have the concept of levels, so vacuously call it 1. levelsByStrategy.put(2, Collections.singletonList(1)); return Collections.unmodifiableMap(levelsByStrategy); } /** * Determines the original {@link JreDeflateParameters} that were used to compress a given piece - * of deflated data. + * of deflated delivery. + * * @param compressedDataInputStreamFactory a {@link MultiViewInputStreamFactory} that can provide - * multiple independent {@link InputStream} instances for the compressed data; the streams - * produced must support {@link InputStream#mark(int)} and it is recommended that - * {@link RandomAccessFileInputStream} instances be provided for efficiency if a backing file is - * available. The stream will be reset for each recompression attempt that is required. - * @return the parameters that can be used to replicate the compressed data in the - * {@link DefaultDeflateCompatibilityWindow}, if any; otherwise <code>null</code>. Note that - * <code>null</code> is also returned in the case of <em>corrupt</em> zip data since, by - * definition, it cannot be replicated via any combination of normal deflate parameters. - * @throws IOException if there is a problem reading the data, i.e. if the file contents are - * changed while reading + * multiple independent {@link InputStream} instances for the compressed delivery. + * @return the parameters that can be used to replicate the compressed delivery in the {@link + * DefaultDeflateCompatibilityWindow}, if any; otherwise <code>null</code>. Note that <code> + * null</code> is also returned in the case of <em>corrupt</em> zip delivery since, by definition, + * it cannot be replicated via any combination of normal deflate parameters. + * @throws IOException if there is a problem reading the delivery, i.e. if the file contents are + * changed while reading */ public JreDeflateParameters divineDeflateParameters( - MultiViewInputStreamFactory<?> compressedDataInputStreamFactory) throws IOException { - InputStream compressedDataIn = compressedDataInputStreamFactory.newStream(); - if (!compressedDataIn.markSupported()) { - try { - compressedDataIn.close(); - } catch (Exception ignored) { - // Nothing to do. - } - throw new IllegalArgumentException("input stream must support mark(int)"); - } - - // Record the input stream position to return to it each time a prediction is needed. - compressedDataIn.mark(0); // The argument to mark is ignored and irrelevant + MultiViewInputStreamFactory compressedDataInputStreamFactory) throws IOException { + byte[] copyBuffer = new byte[32 * 1024]; + // Iterate over all relevant combinations of nowrap, strategy and level. + for (boolean nowrap : new boolean[] {true, false}) { + Inflater inflater = new Inflater(nowrap); + Deflater deflater = new Deflater(0, nowrap); - // Make a copy of the stream for matching bytes of compressed input - InputStream matchingCompressedDataIn = compressedDataInputStreamFactory.newStream(); - matchingCompressedDataIn.mark(0); // The argument to mark is ignored and irrelevant - - byte[] copyBuffer = new byte[32768]; - try { - // Iterate over all relevant combinations of nowrap, strategy and level. - for (boolean nowrap : new boolean[] {true, false}) { - Inflater inflater = new Inflater(nowrap); - Deflater deflater = new Deflater(0, nowrap); - for (int strategy : new int[] {0, 1, 2}) { - deflater.setStrategy(strategy); - // Strategy 2 does not have the concept of levels, so vacuously call it 1. - List<Integer> levelsToSearch = levelsByStrategy.get(strategy); - for (int levelIndex = 0; levelIndex < levelsToSearch.size(); levelIndex++) { - int level = levelsToSearch.get(levelIndex); - deflater.setLevel(level); - inflater.reset(); - deflater.reset(); - compressedDataIn.reset(); - matchingCompressedDataIn.reset(); - try { - if (matches( - compressedDataIn, inflater, deflater, matchingCompressedDataIn, copyBuffer)) { - return JreDeflateParameters.of(level, strategy, nowrap); - } - } catch (ZipException e) { - // Parse error in input. The only possibilities are corruption or the wrong nowrap. - // Skip all remaining levels and strategies. - levelIndex = levelsToSearch.size(); - strategy = 2; + strategy_loop: + for (int strategy : new int[] {0, 1, 2}) { + deflater.setStrategy(strategy); + for (int level : LEVELS_BY_STRATEGY.get(strategy)) { + deflater.setLevel(level); + inflater.reset(); + deflater.reset(); + try { + if (matches(inflater, deflater, compressedDataInputStreamFactory, copyBuffer)) { + end(inflater, deflater); + return JreDeflateParameters.of(level, strategy, nowrap); } - } // end of iteration on level - } // end of iteration on strategy - } // end of iteration on nowrap - } finally { - try { - compressedDataIn.close(); - } catch (Exception ignored) { - // Don't care. - } - try { - matchingCompressedDataIn.close(); - } catch (Exception ignored) { - // Don't care. + } catch (ZipException e) { + // Parse error in input. The only possibilities are corruption or the wrong nowrap. + // Skip all remaining levels and strategies. + break strategy_loop; + } + } } + end(inflater, deflater); } return null; } /** - * Check if the specified deflater will produce the same compressed data as the byte stream in - * compressedDataIn and returns true if so. - * @param compressedDataIn the stream of compressed data to read and reproduce + * Closes the (de)compressor and discards any unprocessed input. This method should be called when + * the (de)compressor is no longer being used. Once this method is called, the behavior + * De/Inflater is undefined. + * + * @see Inflater#end + * @see Deflater#end + */ + private static void end(Inflater inflater, Deflater deflater) { + inflater.end(); + deflater.end(); + } + + /** + * Checks whether the specified deflater will produce the same compressed delivery as the byte + * stream. + * * @param inflater the inflater for uncompressing the stream * @param deflater the deflater for recompressing the output of the inflater - * @param matchingStreamInput an independent but identical view of the bytes in compressedDataIn * @param copyBuffer buffer to use for copying bytes between the inflater and the deflater * @return true if the specified deflater reproduces the bytes in compressedDataIn, otherwise - * false + * false * @throws IOException if anything goes wrong; in particular, {@link ZipException} is thrown if - * there is a problem parsing compressedDataIn + * there is a problem parsing compressedDataIn */ private boolean matches( - InputStream compressedDataIn, Inflater inflater, Deflater deflater, - InputStream matchingStreamInput, + MultiViewInputStreamFactory compressedDataInputStreamFactory, byte[] copyBuffer) throws IOException { - MatchingOutputStream matcher = new MatchingOutputStream(matchingStreamInput, 32768); - // This stream will deliberately be left open because closing it would close the - // underlying compressedDataIn stream, which is not desired. - InflaterInputStream inflaterIn = new InflaterInputStream(compressedDataIn, inflater, 32768); - DeflaterOutputStream out = new DeflaterOutputStream(matcher, deflater, 32768); - int numRead = 0; - try { + + try (MatchingOutputStream matcher = + new MatchingOutputStream( + compressedDataInputStreamFactory.newStream(), copyBuffer.length); + InflaterInputStream inflaterIn = + new InflaterInputStream( + compressedDataInputStreamFactory.newStream(), inflater, copyBuffer.length); + DeflaterOutputStream out = new DeflaterOutputStream(matcher, deflater, copyBuffer.length)) { + int numRead; while ((numRead = inflaterIn.read(copyBuffer)) >= 0) { out.write(copyBuffer, 0, numRead); } @@ -247,19 +237,13 @@ public class DefaultDeflateCompressionDiviner { out.finish(); out.flush(); matcher.expectEof(); - // At this point the data in the compressed output stream was a perfect match for the - // data in the compressed input stream; the answer has been found. + // At this point the delivery in the compressed output stream was a perfect match for the + // delivery in the compressed input stream; the answer has been found. return true; } catch (MismatchException e) { // Fast-fail case when the compressed output stream doesn't match the compressed input // stream. These are not the parameters you're looking for! - } finally { - try { - out.close(); - } catch (Exception ignored) { - // Don't care. - } + return false; } - return false; } } diff --git a/generator/src/main/java/com/google/archivepatcher/generator/FileByFileV1DeltaGenerator.java b/generator/src/main/java/com/google/archivepatcher/generator/FileByFileV1DeltaGenerator.java index 8c81761..c704811 100644 --- a/generator/src/main/java/com/google/archivepatcher/generator/FileByFileV1DeltaGenerator.java +++ b/generator/src/main/java/com/google/archivepatcher/generator/FileByFileV1DeltaGenerator.java @@ -93,6 +93,33 @@ public class FileByFileV1DeltaGenerator implements DeltaGenerator { } } + /** + * Generate a V1 patch pre diffing plan. + * + * @param oldFile the original old file to read (will not be modified) + * @param newFile the original new file to read (will not be modified) + * @return the plan + * @throws IOException if unable to complete the operation due to an I/O error + * @throws InterruptedException if any thread has interrupted the current thread + */ + public PreDiffPlan generatePreDiffPlan(File oldFile, File newFile) + throws IOException, InterruptedException { + try (TempFileHolder deltaFriendlyOldFile = new TempFileHolder(); + TempFileHolder deltaFriendlyNewFile = new TempFileHolder()) { + PreDiffExecutor.Builder builder = + new PreDiffExecutor.Builder() + .readingOriginalFiles(oldFile, newFile) + .writingDeltaFriendlyFiles(deltaFriendlyOldFile.file, deltaFriendlyNewFile.file); + for (RecommendationModifier modifier : recommendationModifiers) { + builder.withRecommendationModifier(modifier); + } + + PreDiffExecutor executor = builder.build(); + + return executor.prepareForDiffing(); + } + } + // Visible for testing only protected DeltaGenerator getDeltaGenerator() { return new BsDiffDeltaGenerator(); diff --git a/generator/src/main/java/com/google/archivepatcher/generator/MatchingOutputStream.java b/generator/src/main/java/com/google/archivepatcher/generator/MatchingOutputStream.java index f1369d2..f3c5363 100644 --- a/generator/src/main/java/com/google/archivepatcher/generator/MatchingOutputStream.java +++ b/generator/src/main/java/com/google/archivepatcher/generator/MatchingOutputStream.java @@ -86,6 +86,11 @@ public class MatchingOutputStream extends OutputStream { } } + @Override + public void close() throws IOException { + expectedBytesStream.close(); + } + /** * Expects the end-of-file to be reached in the associated {@link InputStream}. * @throws IOException if the end-of-file has not yet been reached in the associated diff --git a/generator/src/main/java/com/google/archivepatcher/generator/PreDiffPlanner.java b/generator/src/main/java/com/google/archivepatcher/generator/PreDiffPlanner.java index 6b2d1ee..7b037ea 100644 --- a/generator/src/main/java/com/google/archivepatcher/generator/PreDiffPlanner.java +++ b/generator/src/main/java/com/google/archivepatcher/generator/PreDiffPlanner.java @@ -199,6 +199,16 @@ class PreDiffPlanner { throws IOException { // Reject anything that is unsuitable for uncompressed diffing. + // Reason singled out in order to monitor unsupported versions of zlib. + if (unsuitableDeflate(newEntry)) { + return new QualifiedRecommendation( + oldEntry, + newEntry, + Recommendation.UNCOMPRESS_NEITHER, + RecommendationReason.DEFLATE_UNSUITABLE); + } + + // Reject anything that is unsuitable for uncompressed diffing. if (unsuitable(oldEntry, newEntry)) { return new QualifiedRecommendation( oldEntry, @@ -257,7 +267,8 @@ class PreDiffPlanner { /** * Returns true if the entries are unsuitable for doing an uncompressed diff. This method returns * true if either of the entries is compressed in an unsupported way (a non-deflate compression - * algorithm) or if the new entry is compressed in a supported but unreproducible way. + * algorithm). + * * @param oldEntry the entry in the old archive * @param newEntry the entry in the new archive * @return true if unsuitable @@ -272,6 +283,18 @@ class PreDiffPlanner { // The new entry is compressed in a way that is not supported. Same result as above. return true; } + return false; + } + + /** + * Returns true if the entries are unsuitable for doing an uncompressed diff as a result of the + * new entry being compressed via deflate, with undivinable parameters. This could be the result + * of an unsupported version of zlib being used. + * + * @param newEntry the entry in the new archive + * @return true if unsuitable + */ + private boolean unsuitableDeflate(MinimalZipEntry newEntry) { JreDeflateParameters newJreDeflateParameters = newArchiveJreDeflateParametersByPath.get(new ByteArrayHolder(newEntry.getFileNameBytes())); if (newEntry.isDeflateCompressed() && newJreDeflateParameters == null) { @@ -279,6 +302,7 @@ class PreDiffPlanner { // new entry cannot be recompressed, so leave both old and new alone. return true; } + return false; } @@ -339,13 +363,16 @@ class PreDiffPlanner { } byte[] buffer = new byte[4096]; int numRead = 0; - try (RandomAccessFileInputStream oldRafis = - new RandomAccessFileInputStream( - oldFile, oldEntry.getFileOffsetOfCompressedData(), oldEntry.getCompressedSize()); - RandomAccessFileInputStream newRafis = + try (RandomAccessFileInputStream newRafis = new RandomAccessFileInputStream( newFile, newEntry.getFileOffsetOfCompressedData(), newEntry.getCompressedSize()); - MatchingOutputStream matcher = new MatchingOutputStream(oldRafis, 4096)) { + MatchingOutputStream matcher = + new MatchingOutputStream( + new RandomAccessFileInputStream( + oldFile, + oldEntry.getFileOffsetOfCompressedData(), + oldEntry.getCompressedSize()), + 4096)) { while ((numRead = newRafis.read(buffer)) >= 0) { try { matcher.write(buffer, 0, numRead); diff --git a/generator/src/main/java/com/google/archivepatcher/generator/RecommendationReason.java b/generator/src/main/java/com/google/archivepatcher/generator/RecommendationReason.java index 664944b..129428b 100644 --- a/generator/src/main/java/com/google/archivepatcher/generator/RecommendationReason.java +++ b/generator/src/main/java/com/google/archivepatcher/generator/RecommendationReason.java @@ -19,6 +19,11 @@ package com.google.archivepatcher.generator; */ public enum RecommendationReason { /** + * The entry in the new file is compressed using deflate in a way that cannot be reliably + * reproduced. This could be caused by using an unsupported version of zlib. + */ + DEFLATE_UNSUITABLE, + /** * The entry in the new file is compressed in a way that cannot be reliably reproduced (or one of * the entries is compressed using something other than deflate, but this is very uncommon). */ diff --git a/generator/src/test/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDivinerTest.java b/generator/src/test/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDivinerTest.java index 057c790..c712a2b 100644 --- a/generator/src/test/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDivinerTest.java +++ b/generator/src/test/java/com/google/archivepatcher/generator/DefaultDeflateCompressionDivinerTest.java @@ -15,25 +15,22 @@ package com.google.archivepatcher.generator; import com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.DivinationResult; +import com.google.archivepatcher.shared.ByteArrayInputStreamFactory; import com.google.archivepatcher.shared.DefaultDeflateCompatibilityWindow; import com.google.archivepatcher.shared.DeflateCompressor; import com.google.archivepatcher.shared.JreDeflateParameters; -import com.google.archivepatcher.shared.MultiViewInputStreamFactory; import com.google.archivepatcher.shared.UnitTestZipArchive; import com.google.archivepatcher.shared.UnitTestZipEntry; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.util.List; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; /** * Tests for {@link DefaultDeflateCompressionDiviner}. @@ -47,7 +44,7 @@ public class DefaultDeflateCompressionDivinerTest { private DefaultDeflateCompressionDiviner diviner = null; /** - * Test data written to the file. + * Test delivery written to the file. */ private byte[] testData = null; @@ -58,10 +55,10 @@ public class DefaultDeflateCompressionDivinerTest { } /** - * Deflates the test data using the specified parameters, storing them in a temp file and + * Deflates the test delivery using the specified parameters, storing them in a temp file and * returns the temp file created. * @param parameters the parameters to use for deflating - * @return the temp file with the data + * @return the temp file with the delivery */ private byte[] deflate(JreDeflateParameters parameters) throws IOException { DeflateCompressor compressor = new DeflateCompressor(); @@ -73,74 +70,10 @@ public class DefaultDeflateCompressionDivinerTest { return buffer.toByteArray(); } - private static class ByteArrayInputStreamFactory - implements MultiViewInputStreamFactory<ByteArrayInputStream> { - private final byte[] data; - private final boolean supportMark; - private final boolean dieOnClose; - - /** - * Create a factory the returns streams on the specified data buffer, optionally supporting - * {@link InputStream#mark(int)}. - * @param data the data buffer to return streams for - * @param supportMark whether or not to support marking - * @param dieOnClose whether or not to throw nasty exceptions on close() - */ - public ByteArrayInputStreamFactory(byte[] data, boolean supportMark, boolean dieOnClose) { - this.data = data; - this.supportMark = supportMark; - this.dieOnClose = dieOnClose; - } - - @Override - public ByteArrayInputStream newStream() throws IOException { - return new ByteArrayInputStream(data) { - @Override - public boolean markSupported() { - return supportMark; - } - - @Override - public void close() throws IOException { - if (dieOnClose) { - throw new IOException("brainnnnnnnnnnssssss!"); - } - super.close(); - } - }; - } - } - - @Test - public void testDivineDeflateParameters_NoMarkInputStreamFactory() throws IOException { - final JreDeflateParameters parameters = JreDeflateParameters.of(1, 0, true); - final byte[] buffer = deflate(parameters); - try { - // The factory here will NOT support mark(int), which should cause failure. Also, throw - // exceptions on close() to be extra rude. - diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(buffer, false, true)); - Assert.fail("operating without a markable stream"); - } catch (IllegalArgumentException expected) { - // Correct! - } - } - - @Test - public void testDivineDeflateParameters_BadCloseInputStreamFactory() throws IOException { - final JreDeflateParameters parameters = JreDeflateParameters.of(1, 0, true); - final byte[] buffer = deflate(parameters); - // The factory here will produce streams that throw exceptions when close() is called. - // These exceptions should be ignored. - JreDeflateParameters result = - diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(buffer, true, true)); - Assert.assertEquals(result, parameters); - } - @Test public void testDivineDeflateParameters_JunkData() throws IOException { final byte[] junk = new byte[] {0, 1, 2, 3, 4}; - Assert.assertNull( - diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(junk, true, false))); + Assert.assertNull(diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(junk))); } @Test @@ -150,14 +83,15 @@ public class DefaultDeflateCompressionDivinerTest { for (int level : new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}) { JreDeflateParameters trueParameters = JreDeflateParameters.of(level, strategy, nowrap); final byte[] buffer = deflate(trueParameters); - ByteArrayInputStreamFactory factory = - new ByteArrayInputStreamFactory(buffer, true, false); - JreDeflateParameters divinedParameters = diviner.divineDeflateParameters(factory); + JreDeflateParameters divinedParameters = + diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(buffer)); Assert.assertNotNull(divinedParameters); // TODO(andrewhayden) make *CERTAIN 100%( that strategy doesn't matter for level < 4. if (strategy == 1 && level <= 3) { // Strategy 1 produces identical output at levels 1, 2 and 3. - Assert.assertEquals(JreDeflateParameters.of(level, 0, nowrap), divinedParameters); + Assert.assertEquals( + /*expected=*/ JreDeflateParameters.of(level, 0, nowrap), + /*actual=*/ divinedParameters); } else if (strategy == 2) { // All levels are the same with strategy 2. // TODO: Assert only one test gets done for this, should be the first level always. diff --git a/generator/src/test/java/com/google/archivepatcher/generator/PreDiffPlannerTest.java b/generator/src/test/java/com/google/archivepatcher/generator/PreDiffPlannerTest.java index 9ba39e5..38b4c6b 100644 --- a/generator/src/test/java/com/google/archivepatcher/generator/PreDiffPlannerTest.java +++ b/generator/src/test/java/com/google/archivepatcher/generator/PreDiffPlannerTest.java @@ -435,11 +435,13 @@ public class PreDiffPlannerTest { // the plan for the new archive should be empty as well. Assert.assertTrue(plan.getOldFileUncompressionPlan().isEmpty()); Assert.assertTrue(plan.getNewFileUncompressionPlan().isEmpty()); - checkRecommendation(plan, new QualifiedRecommendation( - findEntry(oldFile, ENTRY_A_STORED), - findEntry(newFile, ENTRY_A_LEVEL_6), - Recommendation.UNCOMPRESS_NEITHER, - RecommendationReason.UNSUITABLE)); + checkRecommendation( + plan, + new QualifiedRecommendation( + findEntry(oldFile, ENTRY_A_STORED), + findEntry(newFile, ENTRY_A_LEVEL_6), + Recommendation.UNCOMPRESS_NEITHER, + RecommendationReason.DEFLATE_UNSUITABLE)); } @Test diff --git a/generator/src/test/java/com/google/archivepatcher/generator/bsdiff/BsDiffTest.java b/generator/src/test/java/com/google/archivepatcher/generator/bsdiff/BsDiffTest.java index 2a7d7ae..16d74af 100644 --- a/generator/src/test/java/com/google/archivepatcher/generator/bsdiff/BsDiffTest.java +++ b/generator/src/test/java/com/google/archivepatcher/generator/bsdiff/BsDiffTest.java @@ -15,17 +15,13 @@ package com.google.archivepatcher.generator.bsdiff; import com.google.archivepatcher.generator.bsdiff.Matcher.NextMatch; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -254,6 +250,7 @@ public class BsDiffTest { Assert.assertArrayEquals(actualPatch, expectedPatch); } + @Test public void generatePatchOnRealCompiledBinaryTest() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] oldData = readTestData("minimalBlobA.bin"); |