aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
blob: 8fdcfa58c6f66f075d225f2adc4e5ef073839ed9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.internal;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.CompilationException;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.Resource;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.OutputMode;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.Test;

public class R8GMSCoreDeterministicTest extends GMSCoreCompilationTestBase {

  public List<DexEncodedMethod> shuffle(List<DexEncodedMethod> methods) {
    Collections.shuffle(methods);
    return methods;
  }

  private AndroidApp doRun()
      throws IOException, ProguardRuleParserException, CompilationException, ExecutionException {
    R8Command command =
        R8Command.builder().addProgramFiles(Paths.get(GMSCORE_V7_DIR, GMSCORE_APK)).build();
    return ToolHelper.runR8(
        command, options -> {
          // For this test just do random shuffle.
          options.testing.irOrdering = this::shuffle;
          // Only use one thread to process to process in the order decided by the callback.
          options.numberOfThreads = 1;
          options.minApiLevel = Constants.ANDROID_L_API;
        });
  }

  @Test
  public void deterministic()
      throws ExecutionException, IOException, ProguardRuleParserException, InterruptedException,
          CompilationException {

    // Run two independent compilations.
    AndroidApp app1 = doRun();
    AndroidApp app2 = doRun();

    // Verify that the result of the two compilations was the same.
    try (Closer closer = Closer.create()) {
      List<Resource> files1 = app1.getDexProgramResources();
      List<Resource> files2 = app2.getDexProgramResources();
      assertEquals(files1.size(), files2.size());
      for (int index = 0; index < files1.size(); index++) {
        InputStream file1 = files1.get(index).getStream(closer);
        InputStream file2 = files2.get(index).getStream(closer);
        byte[] bytes1 = ByteStreams.toByteArray(file1);
        byte[] bytes2 = ByteStreams.toByteArray(file2);
        assertArrayEquals("File index " + index, bytes1, bytes2);
      }
    }

    // Check that the generated bytecode runs through the dex2oat verifier with no errors.
    Path combinedInput = temp.getRoot().toPath().resolve("all.jar");
    Path oatFile = temp.getRoot().toPath().resolve("all.oat");
    app1.writeToZip(combinedInput, OutputMode.Indexed);
    ToolHelper.runDex2Oat(combinedInput, oatFile);
  }
}