blob: 08a2f267745b357589c052bbed7d45208673103f [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* 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.android.tools.deployer;
import static org.junit.Assert.*;
import com.android.tools.deployer.model.Apk;
import com.android.tools.deployer.model.ApkEntry;
import com.android.tools.deployer.model.DexClass;
import com.android.tools.deployer.model.FileDiff;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import org.junit.Test;
public class DexComparatorTest {
@Test
public void testNoDiff() throws DeployerException {
DexComparator comparator = new DexComparator();
List<FileDiff> diffs = new ArrayList<>();
DexComparator.ChangedClasses classes = comparator.compare(diffs, new FakeDexSplitter());
assertTrue(classes.newClasses.isEmpty());
assertTrue(classes.modifiedClasses.isEmpty());
}
@Test
public void testNoChanges() throws DeployerException {
DexComparator comparator = new DexComparator();
List<FileDiff> diffs = new ArrayList<>();
Apk oldApk = makeApk("abcd");
ApkEntry oldFile = new ApkEntry("a.dex", 1, oldApk);
// A similar apk that contains a dex with different checksum
// but actually the same classes (different order for example)
Apk newApk = makeApk("efgh");
ApkEntry newFile = new ApkEntry("a.dex", 2, newApk);
diffs.add(new FileDiff(oldFile, newFile, FileDiff.Status.MODIFIED));
DexComparator.ChangedClasses classes = comparator.compare(diffs, new FakeDexSplitter());
assertTrue(classes.newClasses.isEmpty());
assertTrue(classes.modifiedClasses.isEmpty());
}
@Test
public void testOneClassChange() throws DeployerException {
DexComparator comparator = new DexComparator();
List<FileDiff> diffs = new ArrayList<>();
Apk oldApk = makeApk("abcd");
ApkEntry oldFile = new ApkEntry("a.dex", 1, oldApk);
Apk newApk = makeApk("efgh");
ApkEntry newFile = new ApkEntry("a.dex", 3, newApk);
diffs.add(new FileDiff(oldFile, newFile, FileDiff.Status.MODIFIED));
DexComparator.ChangedClasses classes = comparator.compare(diffs, new FakeDexSplitter());
assertTrue(classes.newClasses.isEmpty());
assertEquals(1, classes.modifiedClasses.size());
assertEquals(0x0012, classes.modifiedClasses.get(0).checksum);
assertEquals("A", classes.modifiedClasses.get(0).name);
}
@Test
public void testOneClassAdded() throws DeployerException {
DexComparator comparator = new DexComparator();
List<FileDiff> diffs = new ArrayList<>();
Apk oldApk = makeApk("abcd");
ApkEntry oldFile = new ApkEntry("a.dex", 1, oldApk);
Apk newApk = makeApk("efgh");
ApkEntry newFile = new ApkEntry("a.dex", 4, newApk);
diffs.add(new FileDiff(oldFile, newFile, FileDiff.Status.MODIFIED));
DexComparator.ChangedClasses classes = comparator.compare(diffs, new FakeDexSplitter());
assertEquals(1, classes.newClasses.size());
}
@Test
public void testOneClassChangeWithMultipleCopies() throws DeployerException {
DexComparator comparator = new DexComparator();
List<FileDiff> diffs = new ArrayList<>();
Apk oldApk = makeApk("abcd");
ApkEntry oldFile = new ApkEntry("a.dex", 1, oldApk);
Apk newApk = makeApk("efgh");
ApkEntry newFile = new ApkEntry("a.dex", 1, newApk);
diffs.add(new FileDiff(oldFile, newFile, FileDiff.Status.MODIFIED));
DexComparator.ChangedClasses classes =
comparator.compare(
diffs,
new FakeDexSplitter() {
@Override
public List<DexClass> split(
ApkEntry dex, Predicate<DexClass> keepCode) {
List result = Lists.newArrayList(super.split(dex, keepCode));
result.add(new DexClass("A", 0x9999, new byte[0], dex));
return result;
}
});
assertTrue(classes.newClasses.isEmpty());
assertEquals(0, classes.modifiedClasses.size());
}
static class FakeDexSplitter implements DexSplitter {
@Override
public List<DexClass> split(ApkEntry dex, Predicate<DexClass> keepCode) {
ArrayList<DexClass> classes = new ArrayList<>();
if (dex.getChecksum() == 1) {
classes.add(new DexClass("A", 0x0011, new byte[0], dex));
} else if (dex.getChecksum() == 2) {
classes.add(new DexClass("A", 0x0011, new byte[0], dex));
} else if (dex.getChecksum() == 3) {
classes.add(new DexClass("A", 0x0012, new byte[0], dex));
} else if (dex.getChecksum() == 4) {
classes.add(new DexClass("A", 0x0011, new byte[0], dex));
classes.add(new DexClass("B", 0x0013, new byte[0], dex));
}
for (int i = 0; i < classes.size(); i++) {
DexClass cls = classes.get(i);
if (keepCode == null || !keepCode.test(cls)) {
classes.set(i, new DexClass(cls.name, cls.checksum, null, cls.dex));
}
}
return classes;
}
}
private static Apk makeApk(String checksum) {
return Apk.builder().setName("base.apk").setChecksum(checksum).build();
}
}