| // 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.jasmin; | |
| import static org.junit.Assert.assertEquals; | |
| import static org.junit.Assert.assertTrue; | |
| import static org.junit.Assert.fail; | |
| import com.android.tools.r8.CompilationFailedException; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.utils.AndroidApiLevel; | |
| import com.android.tools.r8.utils.StringUtils; | |
| import java.nio.file.InvalidPathException; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| class NameTestBase extends JasminTestBase { | |
| // TestString is a String with modified toString() which prints \\uXXXX for | |
| // characters outside 0x20..0x7e. | |
| static class TestString { | |
| private final String value; | |
| TestString(String value) { | |
| this.value = value; | |
| } | |
| String getValue() { | |
| return value; | |
| } | |
| @Override | |
| public String toString() { | |
| return StringUtils.toASCIIString(value); | |
| } | |
| } | |
| // The return value is a collection of rows with the following fields: | |
| // - Name (String) to test (can be class name, field name, method name). | |
| // - boolean, whether it runs on the JVM. | |
| // - boolean, whether it runs on the ART. | |
| static Collection<Object[]> getCommonNameTestData(boolean classNames) { | |
| boolean windowsSensitive = classNames && ToolHelper.isWindows(); | |
| boolean supportSpaces = ToolHelper.getMinApiLevelForDexVm().getLevel() | |
| >= AndroidApiLevel.R.getLevel(); | |
| boolean java9 = ToolHelper.isJava9Runtime(); | |
| return Arrays.asList( | |
| new Object[][] { | |
| {new TestString("azAZ09$_"), true, true}, | |
| {new TestString("_"), !java9, true}, | |
| {new TestString("a-b"), !java9, true}, | |
| {new TestString("\u00a0"), !java9, supportSpaces}, | |
| {new TestString("\u00a1"), !java9, true}, | |
| {new TestString("\u1fff"), !java9, true}, | |
| {new TestString("\u2000"), !windowsSensitive && !java9, supportSpaces}, | |
| {new TestString("\u200f"), !windowsSensitive && !java9, false}, | |
| {new TestString("\u2010"), !windowsSensitive && !java9, true}, | |
| {new TestString("\u2027"), !windowsSensitive && !java9, true}, | |
| {new TestString("\u2028"), !windowsSensitive && !java9, false}, | |
| {new TestString("\u202f"), !windowsSensitive && !java9, supportSpaces}, | |
| {new TestString("\u2030"), !windowsSensitive && !java9, true}, | |
| {new TestString("\ud7ff"), !windowsSensitive && !java9, true}, | |
| {new TestString("\ue000"), !windowsSensitive && !java9, true}, | |
| {new TestString("\uffef"), !windowsSensitive && !java9, true}, | |
| {new TestString("\ufff0"), !windowsSensitive && !java9, false}, | |
| {new TestString("\uffff"), !windowsSensitive && !java9, false}, | |
| // Standalone high and low surrogates. | |
| {new TestString("\ud800"), !classNames && !java9, false}, | |
| {new TestString("\udbff"), !classNames && !java9, false}, | |
| {new TestString("\udc00"), !classNames && !java9, false}, | |
| {new TestString("\udfff"), !classNames && !java9, false}, | |
| // Single and double code points above 0x10000. | |
| {new TestString("\ud800\udc00"), true, true}, | |
| {new TestString("\ud800\udcfa"), true, true}, | |
| {new TestString("\ud800\udcfb"), !windowsSensitive && !java9, true}, | |
| {new TestString("\udbff\udfff"), !windowsSensitive && !java9, true}, | |
| {new TestString("\ud800\udc00\ud800\udcfa"), true, true}, | |
| { | |
| new TestString("\ud800\udc00\udbff\udfff"), | |
| !windowsSensitive && !java9, | |
| true | |
| } | |
| }); | |
| } | |
| void runNameTesting( | |
| boolean validForJVM, | |
| JasminBuilder jasminBuilder, | |
| String mainClassName, | |
| String expectedResult, | |
| boolean validForArt, | |
| String expectedNameInFailingD8Message) | |
| throws Exception { | |
| if (validForJVM) { | |
| String javaResult = runOnJava(jasminBuilder, mainClassName); | |
| assertEquals(expectedResult, javaResult); | |
| } else { | |
| try { | |
| runOnJava(jasminBuilder, mainClassName); | |
| fail("Should have failed on JVM."); | |
| } catch (AssertionError | InvalidPathException e) { | |
| // Silent on expected failure. | |
| } | |
| } | |
| if (validForArt) { | |
| String artResult = runOnArtD8(jasminBuilder, mainClassName); | |
| assertEquals(expectedResult, artResult); | |
| } else { | |
| // Make sure the compiler fails. | |
| try { | |
| runOnArtD8(jasminBuilder, mainClassName); | |
| fail("D8 should have rejected this case."); | |
| } catch (CompilationFailedException t) { | |
| assertTrue(t.getCause().getMessage().contains(expectedNameInFailingD8Message)); | |
| } | |
| // Make sure ART also fail, if D8 rejects it. | |
| try { | |
| runOnArtD8( | |
| jasminBuilder, | |
| mainClassName, | |
| options -> { | |
| options.itemFactory.setSkipNameValidationForTesting(true); | |
| }); | |
| fail("Art should have failed."); | |
| } catch (AssertionError e) { | |
| // Silent on expected failure. | |
| } | |
| } | |
| } | |
| } |