@Test public void testNonObfuscatedBuild() throws IOException { Path proguardConfigFile = Paths.get("the/configuration.txt"); Path proguardMappingFile = Paths.get("the/mapping.txt"); SplitZipStep splitZipStep = new SplitZipStep( /* inputPathsToSplit */ ImmutableSet.<Path>of(), /* secondaryJarMetaPath */ Paths.get(""), /* primaryJarPath */ Paths.get(""), /* secondaryJarDir */ Paths.get(""), /* secondaryJarPattern */ "", /* proguardFullConfigFile */ Optional.of(proguardConfigFile), /* proguardMappingFile */ Optional.of(proguardMappingFile), /* primaryDexPatterns */ ImmutableSet.<String>of("primary"), /* primaryDexClassesFile */ Optional.<Path>absent(), ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR, /* pathToReportDir */ Paths.get(""), /* useLinearAllocSplitDex */ true, /* linearAllocHardLimit */ 4 * 1024 * 1024); ProjectFilesystem projectFilesystem = EasyMock.createMock(ProjectFilesystem.class); EasyMock.expect(projectFilesystem.readLines(proguardConfigFile)) .andReturn(ImmutableList.<String>of("-dontobfuscate")); ExecutionContext context = EasyMock.createMock(ExecutionContext.class); EasyMock.expect(context.getProjectFilesystem()).andReturn(projectFilesystem).anyTimes(); EasyMock.replay(projectFilesystem, context); Predicate<String> requiredInPrimaryZipPredicate = splitZipStep.createRequiredInPrimaryZipPredicate(context); assertTrue( "Primary class should be in primary.", requiredInPrimaryZipPredicate.apply("primary.class")); assertFalse( "Secondary class should be in secondary.", requiredInPrimaryZipPredicate.apply("secondary.class")); EasyMock.verify(projectFilesystem, context); }
@Test public void testMetaList() throws IOException { File outJar = tempDir.newFile("test.jar"); ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outJar))); Map<String, String> fileToClassName = ImmutableMap.of( "com/facebook/foo.class", "com.facebook.foo", "bar.class", "bar"); try { for (String entry : fileToClassName.keySet()) { zipOut.putNextEntry(new ZipEntry(entry)); zipOut.write(new byte[] {0}); } } finally { zipOut.close(); } StringWriter stringWriter = new StringWriter(); BufferedWriter writer = new BufferedWriter(stringWriter); try { SplitZipStep.writeMetaList(writer, ImmutableList.of(outJar), DexStore.JAR); } finally { writer.close(); } List<String> lines = CharStreams.readLines(new StringReader(stringWriter.toString())); assertEquals(1, lines.size()); String line = Iterables.getFirst(lines, null); String[] data = line.split(" "); assertEquals(3, data.length); // Note that we cannot test data[1] (the hash) because zip files change their hash each // time they are written due to timestamps written into the file. assertEquals("test.dex.jar", data[0]); assertTrue( String.format("Unexpected class: %s", data[2]), fileToClassName.values().contains(data[2])); }
@Test public void testRequiredInPrimaryZipPredicate() throws IOException { Path primaryDexClassesFile = Paths.get("the/manifest.txt"); SplitZipStep splitZipStep = new SplitZipStep( /* inputPathsToSplit */ ImmutableSet.<Path>of(), /* secondaryJarMetaPath */ Paths.get(""), /* primaryJarPath */ Paths.get(""), /* secondaryJarDir */ Paths.get(""), /* secondaryJarPattern */ "", /* proguardFullConfigFile */ Optional.<Path>absent(), /* proguardMappingFile */ Optional.<Path>absent(), /* primaryDexPatterns */ ImmutableSet.of("List"), Optional.of(primaryDexClassesFile), ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR, /* pathToReportDir */ Paths.get(""), /* useLinearAllocSplitDex */ true, /* linearAllocHardLimit */ 4 * 1024 * 1024); List<String> linesInManifestFile = ImmutableList.of( "com/google/common/collect/ImmutableSortedSet", " com/google/common/collect/ImmutableSet", "# com/google/common/collect/ImmutableMap"); ProjectFilesystem projectFilesystem = EasyMock.createMock(ProjectFilesystem.class); EasyMock.expect(projectFilesystem.readLines(primaryDexClassesFile)) .andReturn(linesInManifestFile); ExecutionContext context = EasyMock.createMock(ExecutionContext.class); EasyMock.expect(context.getProjectFilesystem()).andReturn(projectFilesystem); EasyMock.replay(projectFilesystem, context); Predicate<String> requiredInPrimaryZipPredicate = splitZipStep.createRequiredInPrimaryZipPredicate(context); assertTrue( "All non-.class files should be accepted.", requiredInPrimaryZipPredicate.apply("apples.txt")); assertTrue( "com/google/common/collect/ImmutableSortedSet.class is listed in the manifest verbatim.", requiredInPrimaryZipPredicate.apply("com/google/common/collect/ImmutableSortedSet.class")); assertTrue( "com/google/common/collect/ImmutableSet.class is in the manifest with whitespace.", requiredInPrimaryZipPredicate.apply("com/google/common/collect/ImmutableSet.class")); assertFalse( "com/google/common/collect/ImmutableSet.class cannot have whitespace as param.", requiredInPrimaryZipPredicate.apply(" com/google/common/collect/ImmutableSet.class")); assertFalse( "com/google/common/collect/ImmutableMap.class is commented out.", requiredInPrimaryZipPredicate.apply("com/google/common/collect/ImmutableMap.class")); assertFalse( "com/google/common/collect/Iterables.class is not even mentioned.", requiredInPrimaryZipPredicate.apply("com/google/common/collect/Iterables.class")); assertTrue( "java/awt/List.class matches the substring 'List'.", requiredInPrimaryZipPredicate.apply("java/awt/List.class")); assertFalse( "Substring matching is case-sensitive.", requiredInPrimaryZipPredicate.apply("shiny/Glistener.class")); EasyMock.verify(projectFilesystem, context); }
@Test public void testRequiredInPrimaryZipPredicateWithProguard() throws IOException { Path proguardConfigFile = Paths.get("the/configuration.txt"); Path proguardMappingFile = Paths.get("the/mapping.txt"); Path primaryDexClassesFile = Paths.get("the/manifest.txt"); SplitZipStep splitZipStep = new SplitZipStep( /* inputPathsToSplit */ ImmutableSet.<Path>of(), /* secondaryJarMetaPath */ Paths.get(""), /* primaryJarPath */ Paths.get(""), /* secondaryJarDir */ Paths.get(""), /* secondaryJarPattern */ "", /* proguardFullConfigFile */ Optional.of(proguardConfigFile), /* proguardMappingFile */ Optional.of(proguardMappingFile), /* primaryDexPatterns */ ImmutableSet.of("/primary/", "x/"), Optional.of(primaryDexClassesFile), ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR, /* pathToReportDir */ Paths.get(""), /* useLinearAllocSplitDex */ true, /* linearAllocHardLimit */ 4 * 1024 * 1024); List<String> linesInMappingFile = ImmutableList.of( "foo.bar.MappedPrimary -> foo.bar.a:", "foo.bar.MappedSecondary -> foo.bar.b:", "foo.bar.UnmappedPrimary -> foo.bar.UnmappedPrimary:", "foo.bar.UnmappedSecondary -> foo.bar.UnmappedSecondary:", "foo.primary.MappedPackage -> x.a:", "foo.secondary.MappedPackage -> x.b:", "foo.primary.UnmappedPackage -> foo.primary.UnmappedPackage:"); List<String> linesInManifestFile = ImmutableList.of( // Actual primary dex classes. "foo/bar/MappedPrimary", "foo/bar/UnmappedPrimary", // Red herrings! "foo/bar/b", "x/b"); ProjectFilesystem projectFilesystem = EasyMock.createMock(ProjectFilesystem.class); EasyMock.expect(projectFilesystem.readLines(primaryDexClassesFile)) .andReturn(linesInManifestFile); EasyMock.expect(projectFilesystem.readLines(proguardConfigFile)) .andReturn(ImmutableList.<String>of()); EasyMock.expect(projectFilesystem.readLines(proguardMappingFile)).andReturn(linesInMappingFile); ExecutionContext context = EasyMock.createMock(ExecutionContext.class); EasyMock.expect(context.getProjectFilesystem()).andReturn(projectFilesystem).anyTimes(); EasyMock.replay(projectFilesystem, context); Predicate<String> requiredInPrimaryZipPredicate = splitZipStep.createRequiredInPrimaryZipPredicate(context); assertTrue( "Mapped class from primary list should be in primary.", requiredInPrimaryZipPredicate.apply("foo/bar/a.class")); assertTrue( "Unmapped class from primary list should be in primary.", requiredInPrimaryZipPredicate.apply("foo/bar/UnmappedPrimary.class")); assertTrue( "Mapped class from substring should be in primary.", requiredInPrimaryZipPredicate.apply("x/a.class")); assertTrue( "Unmapped class from substring should be in primary.", requiredInPrimaryZipPredicate.apply("foo/primary/UnmappedPackage.class")); assertFalse( "Mapped class with obfuscated name match should not be in primary.", requiredInPrimaryZipPredicate.apply("foo/bar/b.class")); assertFalse( "Unmapped class name should not randomly be in primary.", requiredInPrimaryZipPredicate.apply("foo/bar/UnmappedSecondary.class")); assertFalse( "Map class with obfuscated name substring should not be in primary.", requiredInPrimaryZipPredicate.apply("x/b.class")); EasyMock.verify(projectFilesystem, context); }