blob: 67652ae66a191035d0f2fb57c498b624a74ee34c [file] [log] [blame]
// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.archivepatcher.generator;
import com.google.archivepatcher.shared.JreDeflateParameters;
import com.google.archivepatcher.shared.PatchConstants;
import com.google.archivepatcher.shared.TypedRange;
import org.junit.After;
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.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* Tests for {@link PatchWriter}.
*/
@RunWith(JUnit4.class)
@SuppressWarnings("javadoc")
public class PatchWriterTest {
// This is Integer.MAX_VALUE + 1.
private static final long BIG = 2048L * 1024L * 1024L;
private static final JreDeflateParameters DEFLATE_PARAMS = JreDeflateParameters.of(6, 0, true);
private static final TypedRange<Void> OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE =
new TypedRange<Void>(BIG, 17L, null);
private static final TypedRange<JreDeflateParameters> NEW_DELTA_FRIENDLY_UNCOMPRESS_RANGE =
new TypedRange<JreDeflateParameters>(BIG - 100L, BIG, DEFLATE_PARAMS);
private static final TypedRange<JreDeflateParameters> NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE =
new TypedRange<JreDeflateParameters>(BIG, BIG, DEFLATE_PARAMS);
private static final List<TypedRange<Void>> OLD_DELTA_FRIENDLY_UNCOMPRESS_PLAN =
Collections.singletonList(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE);
private static final List<TypedRange<JreDeflateParameters>> NEW_DELTA_FRIENDLY_UNCOMPRESS_PLAN =
Collections.singletonList(NEW_DELTA_FRIENDLY_UNCOMPRESS_RANGE);
private static final List<TypedRange<JreDeflateParameters>> NEW_DELTA_FRIENDLY_RECOMPRESS_PLAN =
Collections.singletonList(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE);
private static final long DELTA_FRIENDLY_OLD_FILE_SIZE = BIG - 75L;
private static final long DELTA_FRIENDLY_NEW_FILE_SIZE = BIG + 75L;
private static final PreDiffPlan PLAN =
new PreDiffPlan(
Collections.<QualifiedRecommendation>emptyList(),
OLD_DELTA_FRIENDLY_UNCOMPRESS_PLAN,
NEW_DELTA_FRIENDLY_UNCOMPRESS_PLAN,
NEW_DELTA_FRIENDLY_RECOMPRESS_PLAN);
private static final String DELTA_CONTENT = "this is a really cool delta, woo";
private File deltaFile = null;
private ByteArrayOutputStream buffer = null;
@Before
public void setup() throws IOException {
buffer = new ByteArrayOutputStream();
deltaFile = File.createTempFile("patchwritertest", "delta");
deltaFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(deltaFile)) {
out.write(DELTA_CONTENT.getBytes());
out.flush();
}
}
@After
public void tearDown() {
deltaFile.delete();
}
@Test
public void testWriteV1Patch() throws IOException {
// ---------------------------------------------------------------------------------------------
// CAUTION - DO NOT CHANGE THIS FUNCTION WITHOUT DUE CONSIDERATION FOR BREAKING THE PATCH FORMAT
// ---------------------------------------------------------------------------------------------
// This test writes a simple patch with all the static data listed above and verifies it.
// This code MUST be INDEPENDENT of the real patch parser code, even if it is partially
// redundant; this guards against accidental changes to the patch writer that could alter the
// format and otherwise escape detection.
PatchWriter writer =
new PatchWriter(
PLAN, DELTA_FRIENDLY_OLD_FILE_SIZE, DELTA_FRIENDLY_NEW_FILE_SIZE, deltaFile);
writer.writeV1Patch(buffer);
DataInputStream patchIn = new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()));
byte[] eightBytes = new byte[8];
// Start by reading the signature and flags
patchIn.readFully(eightBytes);
Assert.assertArrayEquals(PatchConstants.IDENTIFIER.getBytes("US-ASCII"), eightBytes);
Assert.assertEquals(0, patchIn.readInt()); // Flags, all reserved in v1
Assert.assertEquals(DELTA_FRIENDLY_OLD_FILE_SIZE, patchIn.readLong());
// Read the uncompression instructions
Assert.assertEquals(1, patchIn.readInt()); // Number of old archive uncompression instructions
Assert.assertEquals(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE.getOffset(), patchIn.readLong());
Assert.assertEquals(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE.getLength(), patchIn.readLong());
// Read the recompression instructions
Assert.assertEquals(1, patchIn.readInt()); // Number of new archive recompression instructions
Assert.assertEquals(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE.getOffset(), patchIn.readLong());
Assert.assertEquals(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE.getLength(), patchIn.readLong());
// Now the JreDeflateParameters for the record
Assert.assertEquals(
PatchConstants.CompatibilityWindowId.DEFAULT_DEFLATE.patchValue, patchIn.read());
Assert.assertEquals(DEFLATE_PARAMS.level, patchIn.read());
Assert.assertEquals(DEFLATE_PARAMS.strategy, patchIn.read());
Assert.assertEquals(DEFLATE_PARAMS.nowrap ? 1 : 0, patchIn.read());
// Delta section. V1 patches have exactly one delta entry and it is always mapped to the entire
// file contents of the delta-friendly archives
Assert.assertEquals(1, patchIn.readInt()); // Number of difference records
Assert.assertEquals(PatchConstants.DeltaFormat.BSDIFF.patchValue, patchIn.read());
Assert.assertEquals(0, patchIn.readLong()); // Old delta-friendly range start
Assert.assertEquals(DELTA_FRIENDLY_OLD_FILE_SIZE, patchIn.readLong()); // old range length
Assert.assertEquals(0, patchIn.readLong()); // New delta-friendly range start
Assert.assertEquals(DELTA_FRIENDLY_NEW_FILE_SIZE, patchIn.readLong()); // new range length
byte[] expectedDeltaContent = DELTA_CONTENT.getBytes("US-ASCII");
Assert.assertEquals(expectedDeltaContent.length, patchIn.readLong());
byte[] actualDeltaContent = new byte[expectedDeltaContent.length];
patchIn.readFully(actualDeltaContent);
Assert.assertArrayEquals(expectedDeltaContent, actualDeltaContent);
}
}