CompatDxTests.java revision 418d1ca139ea11316113beafbb3b3dd3fd5587a
1418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// for details. All rights reserved. Use of this source code is governed by a
3418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager// BSD-style license that can be found in the LICENSE file.
4418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpackage com.android.tools.r8.compatdx;
5418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
6418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static org.junit.Assert.assertEquals;
7418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static org.junit.Assert.assertNotEquals;
8418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport static org.junit.Assert.assertTrue;
9418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
10418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.ToolHelper;
11418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.errors.CompilationError;
12418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.maindexlist.MainDexListTests;
13418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.FileUtils;
14418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.StringUtils;
15418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport com.android.tools.r8.utils.StringUtils.BraceType;
16418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.io.IOException;
17418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Files;
18418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Path;
19418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.nio.file.Paths;
20418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.ArrayList;
21418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Collections;
22418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.List;
23418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.Set;
24418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.stream.Collectors;
25418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.zip.ZipEntry;
26418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport java.util.zip.ZipFile;
27418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.Rule;
28418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.Test;
29418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.rules.ExpectedException;
30418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerimport org.junit.rules.TemporaryFolder;
31418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
32418d1ca139ea11316113beafbb3b3dd3fd5587aMads Agerpublic class CompatDxTests {
33418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String EXAMPLE_JAR_FILE1 = "build/test/examples/arithmetic.jar";
34418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String EXAMPLE_JAR_FILE2 = "build/test/examples/barray.jar";
35418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
36418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String NO_LOCALS = "--no-locals";
37418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String NO_POSITIONS = "--positions=none";
38418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String MULTIDEX = "--multi-dex";
39418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private static final String NUM_THREADS_5 = "--num-threads=5";
40418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
41418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Rule
42418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public ExpectedException thrown = ExpectedException.none();
43418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
44418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Rule
45418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
46418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
47418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
48418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void noFilesTest() throws IOException {
49418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer("--no-files");
50418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
51418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
52418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
53418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void noOutputTest() throws IOException {
54418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexerWithoutOutput(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
55418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
56418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
57418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
58418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void singleJarInputFile() throws IOException {
59418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
60418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
61418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
62418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
63418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void multipleJarInputFiles() throws IOException {
64418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1, EXAMPLE_JAR_FILE2);
65418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
66418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
67418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
68418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void outputZipFile() throws IOException {
69418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexerWithOutput("foo.dex.zip", NO_POSITIONS, NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
70418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
71418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
72418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
73418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void useMultipleThreads() throws IOException {
74418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NUM_THREADS_5, NO_POSITIONS, NO_LOCALS, EXAMPLE_JAR_FILE1);
75418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
76418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
77418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
78418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void withPositions() throws IOException {
79418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NO_LOCALS, MULTIDEX, EXAMPLE_JAR_FILE1);
80418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
81418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
82418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
83418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void withLocals() throws IOException {
84418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NO_POSITIONS, MULTIDEX, EXAMPLE_JAR_FILE1);
85418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
86418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
87418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
88418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void withoutMultidex() throws IOException {
89418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(NO_POSITIONS, NO_LOCALS, EXAMPLE_JAR_FILE1);
90418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
91418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
92418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
93418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void writeToNamedDexFile() throws IOException {
94418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexerWithOutput("named-output.dex", EXAMPLE_JAR_FILE1);
95418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
96418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
97418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  @Test
98418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  public void singleDexProgramIsTooLarge() throws IOException {
99418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    thrown.expect(CompilationError.class);
100418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexer(MainDexListTests.getTwoLargeClassesAppPath().toString());
101418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
102418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
103418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private void runDexer(String... args) throws IOException {
104418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexerWithOutput("", args);
105418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
106418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
107418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private void runDexerWithoutOutput(String... args) throws IOException {
108418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    runDexerWithOutput(null, args);
109418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
110418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
111418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private void runDexerWithOutput(String out, String... args) throws IOException {
112418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Path d8Out = null;
113418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Path dxOut = null;
114418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (out != null) {
115418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      d8Out = temp.newFolder("d8-out").toPath().resolve(out);
116418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      dxOut = temp.newFolder("dx-out").toPath().resolve(out);
117418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      assertNotEquals(d8Out, dxOut);
118418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
119418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
120418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<String> d8Args = new ArrayList<>(args.length + 2);
121418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    d8Args.add("--dex");
122418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (d8Out != null) {
123418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      d8Args.add("--output=" + d8Out);
124418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
125418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Collections.addAll(d8Args, args);
126418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    System.out.println("running: d8 " + StringUtils.join(d8Args, " "));
127418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    CompatDx.main(d8Args.toArray(new String[d8Args.size()]));
128418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
129418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<String> dxArgs = new ArrayList<>(args.length + 2);
130418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (dxOut != null) {
131418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      dxArgs.add("--output=" + dxOut);
132418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
133418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Collections.addAll(dxArgs, args);
134418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    System.out.println("running: dx " + StringUtils.join(dxArgs, " "));
135418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ToolHelper.runDX(dxArgs.toArray(new String[dxArgs.size()]));
136418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
137418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    if (out == null) {
138418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      // Can't check output if explicitly not writing any.
139418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      return;
140418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
141418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
142418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<Path> d8Files = Files.list(Files.isDirectory(d8Out) ? d8Out : d8Out.getParent())
143418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        .sorted().collect(Collectors.toList());
144418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    List<Path> dxFiles = Files.list(Files.isDirectory(dxOut) ? dxOut : dxOut.getParent())
145418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        .sorted().collect(Collectors.toList());
146418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    assertEquals("Out file names differ",
147418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        StringUtils.join(dxFiles, "\n", BraceType.NONE, (file) ->
148418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            file.getFileName().toString()),
149418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        StringUtils.join(d8Files, "\n", BraceType.NONE, (file) ->
150418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager            file.getFileName().toString()));
151418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
152418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (int i = 0; i < d8Files.size(); i++) {
153418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (FileUtils.isArchive(d8Files.get(i))) {
154418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        compareArchiveFiles(d8Files.get(i), dxFiles.get(i));
155418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
156418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
157418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
158418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager
159418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  private void compareArchiveFiles(Path d8File, Path dxFile) throws IOException {
160418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ZipFile d8Zip = new ZipFile(d8File.toFile());
161418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    ZipFile dxZip = new ZipFile(dxFile.toFile());
162418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    // TODO(zerny): This should test resource containment too once supported.
163418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Set<String> d8Content = d8Zip.stream().map(ZipEntry::getName).collect(Collectors.toSet());
164418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    Set<String> dxContent = dxZip.stream().map(ZipEntry::getName).collect(Collectors.toSet());
165418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (String entry : d8Content) {
166418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      assertTrue("Expected dx output to contain " + entry, dxContent.contains(entry));
167418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
168418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    for (String entry : dxContent) {
169418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      if (FileUtils.isDexFile(Paths.get(entry))) {
170418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager        assertTrue("Expected d8 output to contain " + entry, d8Content.contains(entry));
171418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager      }
172418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager    }
173418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager  }
174418d1ca139ea11316113beafbb3b3dd3fd5587aMads Ager}
175