blob: 640796d5ca1560ee3cc8c9681de60dcdc50d1034 [file] [log] [blame]
// Copyright (c) 2021, 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.desugar.lambdas;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class LambdaInStacktraceTest extends TestBase {
static final String fileName = "LambdaInStacktraceTest.java";
static final String EXPECTED_JAVAC =
StringUtils.lines(
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$0(" + fileName + ")",
"main(" + fileName + ")",
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$1(" + fileName + ")",
"main(" + fileName + ")");
// TODO(b/187491007): The "call" frame should have a file name.
static final String EXPECTED_D8 =
StringUtils.lines(
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$0(" + fileName + ")",
"call(D8$$SyntheticClass)",
"main(" + fileName + ")",
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$1(" + fileName + ")",
"call(D8$$SyntheticClass)",
"main(" + fileName + ")");
static final String EXPECTED_D8_ANDROID_O =
StringUtils.lines(
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$0(" + fileName + ")",
"call(NULL)",
"main(" + fileName + ")",
"getStacktraceWithFileNames(" + fileName + ")",
"lambda$main$1(" + fileName + ")",
"call(NULL)",
"main(" + fileName + ")");
private final TestParameters parameters;
private final boolean isAndroidOOrLater;
private final boolean isDalvik;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
public LambdaInStacktraceTest(TestParameters parameters) {
this.parameters = parameters;
isDalvik = parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik();
isAndroidOOrLater =
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V8_1_0);
}
@Test
public void testJvm() throws Exception {
assumeTrue("Only run JVM reference on CF runtimes", parameters.isCfRuntime());
testForJvm()
.addInnerClasses(LambdaInStacktraceTest.class)
.run(parameters.getRuntime(), TestRunner.class, Boolean.toString(false))
.assertSuccess()
.assertSuccessWithOutput(EXPECTED_JAVAC);
}
@Test
public void testD8() throws Exception {
testForD8(parameters.getBackend())
.addInnerClasses(LambdaInStacktraceTest.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
.assertSuccessWithOutput(isAndroidOOrLater ? EXPECTED_D8_ANDROID_O : EXPECTED_D8);
}
@Test
public void testR8() throws Exception {
assumeTrue(parameters.getRuntime().isDex());
String stdout =
testForR8(parameters.getBackend())
.addInnerClasses(LambdaInStacktraceTest.class)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(TestRunner.class)
.addKeepAttributeSourceFile()
.addKeepRules("-renamesourcefileattribute SourceFile")
.noTreeShaking()
.run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
.assertSuccess()
.getStdOut();
assertTrue(
StringUtils.splitLines(stdout).stream()
.allMatch(s -> s.contains(isAndroidOOrLater ? "NULL" : "SourceFile")));
}
static class TestRunner {
public static List<String> getStacktraceWithFileNames(boolean isDalvik) {
Throwable stackTrace = new RuntimeException().fillInStackTrace();
// Dalvik has an additional "main(NativeStart.java)" bottom frame.
List<String> frames = new ArrayList<>();
for (int i = 0; i < stackTrace.getStackTrace().length - (isDalvik ? 1 : 0); i++) {
StackTraceElement stackTraceElement = stackTrace.getStackTrace()[i];
String fileName = stackTraceElement.getFileName();
frames.add(
stackTraceElement.getMethodName() + "(" + (fileName != null ? fileName : "NULL") + ")");
}
return frames;
}
public static void main(String[] args) throws Exception {
boolean isDalvik = Boolean.parseBoolean(args[0]);
Callable<List<String>> callable = () -> getStacktraceWithFileNames(isDalvik);
System.out.println(String.join(System.lineSeparator(), callable.call()));
Callable<Callable<List<String>>> callableNested =
() -> () -> getStacktraceWithFileNames(isDalvik);
System.out.println(String.join(System.lineSeparator(), callableNested.call().call()));
}
}
}