blob: 6bf49a01fe430ae074742db05e0440bd1fd51b94 [file] [log] [blame]
// Copyright (c) 2019, 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.desugaredlibrary;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.io.IOException;
import java.nio.file.Path;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntUnaryOperator;
import org.junit.Assume;
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 RetargetOverrideTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
private final boolean machineSpec;
@Parameters(name = "machine: {0}, {2}, shrink: {1}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
BooleanUtils.values(),
getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
}
public RetargetOverrideTest(
boolean machineSpec, boolean shrinkDesugaredLibrary, TestParameters parameters) {
this.machineSpec = machineSpec;
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
}
@Test
public void testRetargetOverrideCf() throws Exception {
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
Path desugaredTwice =
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
.addOptionsModification(this::setMachineSpec)
.addProgramFiles(
testForD8(Backend.CF)
.addLibraryFiles(getLibraryFile())
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
.compile()
.writeToZip())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
options -> options.desugarSpecificOptions().allowAllDesugaredInput = true)
.compile()
.writeToZip();
String stdout;
if (parameters.getRuntime().isDex()) {
// Convert to DEX without desugaring and run.
stdout =
testForD8(Backend.DEX)
.addProgramFiles(desugaredTwice)
.addOptionsModification(this::setMachineSpec)
.setMinApi(parameters.getApiLevel())
.disableDesugaring()
.compile()
.addDesugaredCoreLibraryRunClassPath(
this::buildDesugaredLibrary,
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
.run(
parameters.getRuntime(),
Executor.class,
Boolean.toString(parameters.getRuntime().isCf()))
.assertSuccess()
.getStdOut();
} else {
// Run on the JVM with desugared library on classpath.
stdout =
testForJvm()
.addProgramFiles(desugaredTwice)
.addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
.run(
parameters.getRuntime(),
Executor.class,
Boolean.toString(parameters.getRuntime().isCf()))
.assertSuccess()
.getStdOut();
}
assertLines2By2Correct(stdout);
}
private void setMachineSpec(InternalOptions opt) {
if (!machineSpec) {
return;
}
try {
HumanDesugaredLibrarySpecification human =
new LegacyToHumanSpecificationConverter()
.convert(opt.desugaredLibrarySpecification, getLibraryFile(), opt);
MachineDesugaredLibrarySpecification machine =
new HumanToMachineSpecificationConverter().convert(human, getLibraryFile(), opt);
opt.testing.machineDesugaredLibrarySpecification = machine;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
public void testRetargetOverrideD8() throws Exception {
Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
String stdout =
testForD8()
.addLibraryFiles(getLibraryFile())
.addOptionsModification(this::setMachineSpec)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
.compile()
.addDesugaredCoreLibraryRunClassPath(
this::buildDesugaredLibrary,
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
.run(
parameters.getRuntime(),
Executor.class,
Boolean.toString(parameters.getRuntime().isCf()))
.assertSuccess()
.getStdOut();
assertLines2By2Correct(stdout);
}
@Test
public void testRetargetOverrideR8() throws Exception {
Assume.assumeTrue(parameters.getRuntime().isDex());
KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
String stdout =
testForR8(Backend.DEX)
.addLibraryFiles(getLibraryFile())
.addOptionsModification(this::setMachineSpec)
.addKeepMainRule(Executor.class)
.addInnerClasses(RetargetOverrideTest.class)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.setMinApi(parameters.getApiLevel())
.compile()
.addDesugaredCoreLibraryRunClassPath(
this::buildDesugaredLibrary,
parameters.getApiLevel(),
keepRuleConsumer.get(),
shrinkDesugaredLibrary)
.run(
parameters.getRuntime(),
Executor.class,
Boolean.toString(parameters.getRuntime().isCf()))
.assertSuccess()
.getStdOut();
assertLines2By2Correct(stdout);
}
static class Executor {
public static void main(String[] args) {
boolean isJvm = Boolean.parseBoolean(args[0]);
directTypes(isJvm);
polyTypes(isJvm);
baseTypes(isJvm);
}
public static void directTypes(boolean isJvm) {
MyCalendarOverride myCal = new MyCalendarOverride(1990, 2, 22);
if (!isJvm) {
System.out.println(myCal.toZonedDateTime());
System.out.println("1990-11-22T00:00Z[GMT]");
System.out.println(myCal.toInstant());
System.out.println("1990-03-22T00:00:00Z");
}
MyCalendarNoOverride myCalN = new MyCalendarNoOverride(1990, 2, 22);
if (!isJvm) {
System.out.println(myCalN.toZonedDateTime());
System.out.println("1990-03-22T00:00Z[GMT]");
System.out.println(myCalN.superToZonedDateTime());
System.out.println("1990-03-22T00:00Z[GMT]");
System.out.println(myCalN.toInstant());
System.out.println("1990-03-22T00:00:00Z");
System.out.println(myCalN.superToInstant());
System.out.println("1990-03-22T00:00:00Z");
}
MyDateDoubleOverride myDateCast2 = new MyDateDoubleOverride(123456789);
System.out.println(myDateCast2.toInstant());
System.out.println("1970-01-02T10:17:48.789Z");
MyDateOverride myDate = new MyDateOverride(123456789);
System.out.println(myDate.toInstant());
System.out.println("1970-01-02T10:17:45.789Z");
MyDateNoOverride myDateN = new MyDateNoOverride(123456789);
System.out.println(myDateN.toInstant());
System.out.println("1970-01-02T10:17:36.789Z");
System.out.println(myDateN.superToInstant());
System.out.println("1970-01-02T10:17:36.789Z");
MyAtomicInteger myAtomicInteger = new MyAtomicInteger(42);
System.out.println(myAtomicInteger.getAndUpdate(x -> x + 1));
System.out.println("42");
System.out.println(myAtomicInteger.superGetAndUpdate(x -> x + 2));
System.out.println("43");
System.out.println(myAtomicInteger.updateAndGet(x -> x + 100));
System.out.println("145");
Date date1 = MyDateNoOverride.from(myCal.toInstant());
if (!isJvm) {
System.out.println(date1.toInstant());
System.out.println("1990-03-22T00:00:00Z");
Date date2 = MyDateOverride.from(myCal.toInstant());
System.out.println(date2.toInstant());
System.out.println("1990-03-22T00:00:00Z");
}
System.out.println(MyDateDoubleOverride.from(myCal.toInstant()).toInstant());
System.out.println("1970-01-02T10:17:36.788Z");
System.out.println(MyDateTrippleOverride.from(myCal.toInstant()).toInstant());
System.out.println("1970-01-02T10:17:36.788Z");
}
public static void polyTypes(boolean isJvm) {
Date myDateCast = new MyDateOverride(123456789);
System.out.println(myDateCast.toInstant());
System.out.println("1970-01-02T10:17:45.789Z");
Date myDateCast2 = new MyDateDoubleOverride(123456789);
System.out.println(myDateCast2.toInstant());
System.out.println("1970-01-02T10:17:48.789Z");
Date myDateN = new MyDateNoOverride(123456789);
System.out.println(myDateN.toInstant());
System.out.println("1970-01-02T10:17:36.789Z");
GregorianCalendar myCalCast = new MyCalendarOverride(1990, 2, 22);
if (!isJvm) {
System.out.println(myCalCast.toZonedDateTime());
System.out.println("1990-11-22T00:00Z[GMT]");
System.out.println(myCalCast.toInstant());
System.out.println("1990-03-22T00:00:00Z");
}
GregorianCalendar myCalN = new MyCalendarNoOverride(1990, 2, 22);
if (!isJvm) {
System.out.println(myCalN.toZonedDateTime());
System.out.println("1990-03-22T00:00Z[GMT]");
System.out.println(myCalN.toInstant());
System.out.println("1990-03-22T00:00:00Z");
}
}
public static void baseTypes(boolean isJvm) {
java.sql.Date date = new java.sql.Date(123456789);
if (!isJvm) {
// The following one is not working on JVMs, but works on Android...
System.out.println(date.toInstant());
System.out.println("1970-01-02T10:17:36.789Z");
}
GregorianCalendar gregCal = new GregorianCalendar(1990, 2, 22);
if (!isJvm) {
System.out.println(gregCal.toInstant());
System.out.println("1990-03-22T00:00:00Z");
}
}
}
static class MyCalendarOverride extends GregorianCalendar {
public MyCalendarOverride(int year, int month, int dayOfMonth) {
super(year, month, dayOfMonth);
}
// Cannot override toInstant (final).
@Override
public ZonedDateTime toZonedDateTime() {
return super.toZonedDateTime().withMonth(11);
}
}
static class MyCalendarNoOverride extends GregorianCalendar {
public MyCalendarNoOverride(int year, int month, int dayOfMonth) {
super(year, month, dayOfMonth);
}
public Instant superToInstant() {
return super.toInstant();
}
public ZonedDateTime superToZonedDateTime() {
return super.toZonedDateTime();
}
}
static class MyDateOverride extends Date {
public MyDateOverride(long date) {
super(date);
}
@Override
public Instant toInstant() {
return super.toInstant().plusSeconds(9);
}
}
static class MyDateDoubleOverride extends MyDateOverride {
public MyDateDoubleOverride(long date) {
super(date);
}
@Override
public Instant toInstant() {
return super.toInstant().plusSeconds(3);
}
public static Date from(Instant instant) {
return new Date(123456788);
}
}
static class MyDateTrippleOverride extends MyDateDoubleOverride {
public MyDateTrippleOverride(long date) {
super(date);
}
@Override
public Instant toInstant() {
return super.toInstant().plusSeconds(6);
}
}
static class MyDateNoOverride extends Date {
public MyDateNoOverride(long date) {
super(date);
}
public Instant superToInstant() {
return super.toInstant();
}
}
static class MyAtomicInteger extends AtomicInteger {
// No overrides, all final methods.
public MyAtomicInteger(int initialValue) {
super(initialValue);
}
public int superGetAndUpdate(IntUnaryOperator op) {
return super.getAndUpdate(op);
}
}
}