| // Copyright (c) 2018, 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.debuginfo; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.debuginfo.InliningWithoutPositionsTestSourceDump.Location; |
| import com.android.tools.r8.naming.retrace.StackTrace; |
| import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine; |
| import com.android.tools.r8.utils.AndroidApiLevel; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import org.hamcrest.CoreMatchers; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| @RunWith(Parameterized.class) |
| public class InliningWithoutPositionsTestRunner extends TestBase { |
| |
| private static final String TEST_SIMPLE_NAME = "InliningWithoutPositionsTestSource"; |
| private static final String TEST_PACKAGE = "com.android.tools.r8.debuginfo"; |
| private static final String TEST_FILE = TEST_SIMPLE_NAME + ".java"; |
| private static final String TEST_CLASS = TEST_PACKAGE + "." + TEST_SIMPLE_NAME; |
| |
| private final TestParameters parameters; |
| private final boolean mainPos; |
| private final boolean foo1Pos; |
| private final boolean barPos; |
| private final boolean foo2Pos; |
| private final Location throwLocation; |
| |
| @Parameters(name = "{0}: main/foo1/bar/foo2 positions: {1}/{2}/{3}/{4}, throwLocation: {5}") |
| public static Collection<Object[]> data() { |
| List<Object[]> testCases = new ArrayList<>(); |
| for (TestParameters parameters : |
| TestParameters.builder().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build()) { |
| for (int i = 0; i < 16; ++i) { |
| for (Location throwLocation : Location.values()) { |
| if (throwLocation != Location.MAIN) { |
| testCases.add( |
| new Object[] { |
| parameters, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0, (i & 8) != 0, throwLocation |
| }); |
| } |
| } |
| } |
| } |
| return testCases; |
| } |
| |
| public InliningWithoutPositionsTestRunner( |
| TestParameters parameters, |
| boolean mainPos, |
| boolean foo1Pos, |
| boolean barPos, |
| boolean foo2Pos, |
| Location throwLocation) { |
| this.parameters = parameters; |
| this.mainPos = mainPos; |
| this.foo1Pos = foo1Pos; |
| this.barPos = barPos; |
| this.foo2Pos = foo2Pos; |
| this.throwLocation = throwLocation; |
| } |
| |
| @Test |
| public void testStackTrace() throws Exception { |
| testForR8(parameters.getBackend()) |
| .setMinApi(parameters.getApiLevel()) |
| .addProgramClassFileData( |
| InliningWithoutPositionsTestSourceDump.dump( |
| mainPos, foo1Pos, barPos, foo2Pos, throwLocation)) |
| .addKeepMainRule(TEST_CLASS) |
| .addKeepAttributeSourceFile() |
| .addKeepAttributeLineNumberTable() |
| .addOptionsModification( |
| options -> options.inlinerOptions().simpleInliningInstructionLimit = 40) |
| .run(parameters.getRuntime(), TEST_CLASS) |
| .assertFailure() |
| .inspectOriginalStackTrace( |
| rawStackTrace -> { |
| assertThat( |
| rawStackTrace.getExceptionLine(), |
| CoreMatchers.containsString("<" + throwLocation + "-exception>")); |
| assertTrue(rawStackTrace.size() > 1); |
| StackTraceLine line = rawStackTrace.get(0); |
| assertEquals(TEST_CLASS, line.className); |
| assertEquals("main", line.methodName); |
| // Expected line number could be PC based or increments. |
| // The test need not check what it is, just that all methods have been fully inlined. |
| assertEquals(2, rawStackTrace.size()); |
| }) |
| .inspectStackTrace( |
| retracedStackTrace -> { |
| assertThat( |
| retracedStackTrace.getExceptionLine(), |
| CoreMatchers.containsString("<" + throwLocation + "-exception>")); |
| switch (throwLocation) { |
| case FOO1: |
| assertThat( |
| retracedStackTrace, |
| StackTrace.isSame( |
| StackTrace.builder() |
| .add(line("foo", Location.FOO1, foo1Pos)) |
| .add(line("main", Location.MAIN, mainPos)) |
| .build())); |
| break; |
| case BAR: |
| assertThat( |
| retracedStackTrace, |
| StackTrace.isSame( |
| StackTrace.builder() |
| .add(line("bar", Location.BAR, barPos)) |
| .add(line("foo", Location.FOO1, foo1Pos)) |
| .add(line("main", Location.MAIN, mainPos)) |
| .build())); |
| break; |
| case FOO2: |
| assertThat( |
| retracedStackTrace, |
| StackTrace.isSame( |
| StackTrace.builder() |
| .add( |
| line( |
| "foo", |
| foo2Pos ? Location.FOO2 : Location.FOO1, |
| foo2Pos || foo1Pos)) |
| .add(line("main", Location.MAIN, mainPos)) |
| .build())); |
| break; |
| default: |
| fail(); |
| } |
| }); |
| } |
| |
| private StackTraceLine line(String methodName, Location location, boolean hasPosition) { |
| return StackTraceLine.builder() |
| .setClassName(TEST_CLASS) |
| .setFileName(TEST_FILE) |
| .setMethodName(methodName) |
| .setLineNumber(hasPosition ? location.line : 0) |
| .build(); |
| } |
| } |