Extract string resource intention action for android (KT-11715)
#KT-11715 Fixed
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
<orderEntry type="module" module-name="idea" />
|
||||
<orderEntry type="module" module-name="ide-common" />
|
||||
<orderEntry type="module" module-name="idea-analysis" />
|
||||
<orderEntry type="module" module-name="idea-test-framework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
<orderEntry type="module" module-name="frontend.java" />
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.intentions
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
|
||||
|
||||
val CREATE_XML_RESOURCE_PARAMETERS_NAME_KEY = Key<String>("CREATE_XML_RESOURCE_PARAMETERS_NAME_KEY")
|
||||
|
||||
class CreateXmlResourceParameters(val name: String,
|
||||
val value: String,
|
||||
val fileName: String,
|
||||
val directoryNames: List<String>)
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.intentions
|
||||
|
||||
import com.android.resources.ResourceType
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.codeInsight.template.*
|
||||
import com.intellij.codeInsight.template.impl.*
|
||||
import com.intellij.codeInsight.template.macro.VariableOfTypeMacro
|
||||
import com.intellij.openapi.application.Application
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.undo.UndoUtil
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.android.actions.CreateXmlResourceDialog
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import org.jetbrains.android.util.AndroidBundle
|
||||
import org.jetbrains.android.util.AndroidResourceUtil
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingIntention
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
|
||||
class KotlinAndroidAddStringResource : SelfTargetingIntention<KtLiteralStringTemplateEntry>(KtLiteralStringTemplateEntry::class.java,
|
||||
"Extract string resource") {
|
||||
private val GET_STRING_METHOD = "getString"
|
||||
private val EXTRACT_RESOURCE_DIALOG_TITLE = "Extract Resource"
|
||||
private val PACKAGE_NOT_FOUND_ERROR = "package.not.found.error"
|
||||
|
||||
override fun isApplicableTo(element: KtLiteralStringTemplateEntry, caretOffset: Int): Boolean {
|
||||
if (AndroidFacet.getInstance(element.containingFile) == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
return element.parent.children.size == 1
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtLiteralStringTemplateEntry, editor: Editor?) {
|
||||
val facet = AndroidFacet.getInstance(element.containingFile)
|
||||
if (editor == null) {
|
||||
throw IllegalArgumentException("This intention requires an editor.")
|
||||
}
|
||||
|
||||
if (facet == null) {
|
||||
throw IllegalStateException("This intention requires android facet.")
|
||||
}
|
||||
|
||||
val file = element.containingFile
|
||||
val project = file.project
|
||||
|
||||
val manifestPackage = getManifestPackage(facet)
|
||||
if (manifestPackage == null) {
|
||||
Messages.showErrorDialog(project, AndroidBundle.message(PACKAGE_NOT_FOUND_ERROR), CommonBundle.getErrorTitle())
|
||||
return
|
||||
}
|
||||
|
||||
val parameters = getCreateXmlResourceParameters(facet.module, element) ?:
|
||||
return
|
||||
|
||||
if (!AndroidResourceUtil.createValueResource(facet.module, parameters.name, ResourceType.STRING,
|
||||
parameters.fileName, parameters.directoryNames, parameters.value)) {
|
||||
return
|
||||
}
|
||||
|
||||
createResourceReference(facet.module, editor, file, element, manifestPackage, parameters.name, ResourceType.STRING)
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
UndoUtil.markPsiFileForUndo(file)
|
||||
}
|
||||
|
||||
private fun getCreateXmlResourceParameters(module: Module, element: KtLiteralStringTemplateEntry): CreateXmlResourceParameters? {
|
||||
|
||||
val stringValue = element.text
|
||||
|
||||
val showDialog = !ApplicationManager.getApplication().isUnitTestMode
|
||||
val resourceName = element.getUserData(CREATE_XML_RESOURCE_PARAMETERS_NAME_KEY)
|
||||
|
||||
val dialog = CreateXmlResourceDialog(module, ResourceType.STRING, resourceName, stringValue, true)
|
||||
dialog.title = EXTRACT_RESOURCE_DIALOG_TITLE
|
||||
if (showDialog && !dialog.showAndGet()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return CreateXmlResourceParameters(dialog.resourceName,
|
||||
dialog.value,
|
||||
dialog.fileName,
|
||||
dialog.dirNames)
|
||||
}
|
||||
|
||||
private fun createResourceReference(module: Module, editor: Editor, file: PsiFile, element: PsiElement, aPackage: String,
|
||||
resName: String, resType: ResourceType) {
|
||||
val rFieldName = AndroidResourceUtil.getRJavaFieldName(resName)
|
||||
val fieldName = "$aPackage.R.$resType.$rFieldName"
|
||||
|
||||
val template: TemplateImpl
|
||||
if (!needContextReceiver(element)) {
|
||||
template = TemplateImpl("", "$GET_STRING_METHOD($fieldName)", "")
|
||||
}
|
||||
else {
|
||||
template = TemplateImpl("", "\$context\$.$GET_STRING_METHOD($fieldName)", "")
|
||||
val marker = MacroCallNode(VariableOfTypeMacro())
|
||||
marker.addParameter(ConstantNode("android.content.Context"))
|
||||
template.addVariable("context", marker, ConstantNode("context"), true)
|
||||
}
|
||||
|
||||
val containingLiteralExpression = element.parent
|
||||
editor.caretModel.moveToOffset(containingLiteralExpression.textOffset)
|
||||
editor.document.deleteString(containingLiteralExpression.textRange.startOffset, containingLiteralExpression.textRange.endOffset)
|
||||
val marker = editor.document.createRangeMarker(containingLiteralExpression.textOffset, containingLiteralExpression.textOffset)
|
||||
marker.isGreedyToLeft = true
|
||||
marker.isGreedyToRight = true
|
||||
|
||||
TemplateManager.getInstance(module.project).startTemplate(editor, template, false, null, object : TemplateEditingAdapter() {
|
||||
override fun waitingForInput(template: Template?) {
|
||||
JavaCodeStyleManager.getInstance(module.project).shortenClassReferences(file, marker.startOffset, marker.endOffset)
|
||||
}
|
||||
|
||||
override fun beforeTemplateFinished(state: TemplateState?, template: Template?) {
|
||||
JavaCodeStyleManager.getInstance(module.project).shortenClassReferences(file, marker.startOffset, marker.endOffset)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun needContextReceiver(element: PsiElement): Boolean {
|
||||
val classesWithGetSting = listOf("android.content.Context", "android.app.Fragment", "android.support.v4.app.Fragment")
|
||||
val viewClass = listOf("android.view.View")
|
||||
var parent = PsiTreeUtil.findFirstParent(element, true) { it is KtClassOrObject || it is KtFunction || it is KtLambdaExpression }
|
||||
|
||||
while (parent != null) {
|
||||
|
||||
if (parent.isSubclassOrSubclassExtension(classesWithGetSting)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (parent.isSubclassOrSubclassExtension(viewClass) ||
|
||||
(parent is KtClassOrObject && !parent.isInnerClass() && !parent.isObjectLiteral())) {
|
||||
return true
|
||||
}
|
||||
|
||||
parent = PsiTreeUtil.findFirstParent(parent, true) { it is KtClassOrObject || it is KtFunction || it is KtLambdaExpression }
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getManifestPackage(facet: AndroidFacet) = facet.manifest?.`package`?.value
|
||||
|
||||
private fun PsiElement.isSubclassOrSubclassExtension(baseClasses: Collection<String>) =
|
||||
(this as? KtClassOrObject)?.isSubclassOfAny(baseClasses) ?:
|
||||
this.isSubclassExtensionOfAny(baseClasses)
|
||||
|
||||
private fun PsiElement.isSubclassExtensionOfAny(baseClasses: Collection<String>) =
|
||||
(this as? KtLambdaExpression)?.isSubclassExtensionOfAny(baseClasses) ?:
|
||||
(this as? KtFunction)?.isSubclassExtensionOfAny(baseClasses) ?:
|
||||
false
|
||||
|
||||
private fun KtClassOrObject.isObjectLiteral() = (this as? KtObjectDeclaration)?.isObjectLiteral() ?: false
|
||||
|
||||
private fun KtClassOrObject.isInnerClass() = (this as? KtClass)?.isInner() ?: false
|
||||
|
||||
private fun KtFunction.isSubclassExtensionOfAny(baseClasses: Collection<String>): Boolean {
|
||||
val descriptor = resolveToDescriptor() as FunctionDescriptor
|
||||
val extendedTypeDescriptor = descriptor.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
return extendedTypeDescriptor != null && baseClasses.any { extendedTypeDescriptor.isSubclassOf(it) }
|
||||
}
|
||||
|
||||
private fun KtLambdaExpression.isSubclassExtensionOfAny(baseClasses: Collection<String>): Boolean {
|
||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext.getType(this)
|
||||
|
||||
if (type == null || !type.isExtensionFunctionType) {
|
||||
return false
|
||||
}
|
||||
|
||||
val extendedTypeDescriptor = type.arguments.first().type.constructor.declarationDescriptor
|
||||
if (extendedTypeDescriptor is ClassDescriptor) {
|
||||
return baseClasses.any { extendedTypeDescriptor.isSubclassOf(it) }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KtClassOrObject.isSubclassOfAny(baseClasses: Collection<String>): Boolean {
|
||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||
val declarationDescriptor = bindingContext.get(BindingContext.CLASS, this)
|
||||
return baseClasses.any { declarationDescriptor?.isSubclassOf(it) ?: false }
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.isSubclassOf(className: String): Boolean {
|
||||
return fqNameSafe.asString() == className || defaultType.constructor.supertypes.any {
|
||||
(it.constructor.declarationDescriptor as? ClassDescriptor)?.isSubclassOf(className) ?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android;
|
||||
|
||||
import com.android.SdkConstants;
|
||||
import com.android.ide.common.rendering.RenderSecurityManager;
|
||||
import com.android.tools.idea.rendering.PsiProjectListener;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.facet.ModifiableFacetModel;
|
||||
import com.intellij.ide.startup.impl.StartupManagerImpl;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
|
||||
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
|
||||
import com.intellij.testFramework.fixtures.JavaTestFixtureFactory;
|
||||
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.facet.AndroidRootUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
|
||||
public abstract class KotlinAndroidTestCase extends KotlinAndroidTestCaseBase {
|
||||
protected Module myModule;
|
||||
protected List<Module> myAdditionalModules;
|
||||
|
||||
private final boolean myCreateManifest;
|
||||
protected AndroidFacet myFacet;
|
||||
|
||||
private boolean kotlinInternalModeOriginalValue;
|
||||
|
||||
public KotlinAndroidTestCase(boolean createManifest) {
|
||||
this.myCreateManifest = createManifest;
|
||||
}
|
||||
|
||||
public KotlinAndroidTestCase() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
protected File[] getResourceDirs(String path) {
|
||||
return new File(path).listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(@NotNull File file) {
|
||||
return file.getName().startsWith("res") && file.isDirectory();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
// sdk path workaround, set real android sdk path and platform for android plugin to work
|
||||
System.setProperty(KotlinAndroidTestCaseBase.SDK_PATH_PROPERTY, PathManager.getHomePath() + "/../dependencies/androidSDK");
|
||||
System.setProperty(KotlinAndroidTestCaseBase.PLATFORM_DIR_PROPERTY, "android-23");
|
||||
|
||||
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
|
||||
super.setUp();
|
||||
|
||||
// this will throw an exception if we don't have a full Android SDK, so we need to do this first thing before any other setup
|
||||
String sdkPath = getTestSdkPath();
|
||||
|
||||
final TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder =
|
||||
IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName());
|
||||
myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture());
|
||||
final JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
|
||||
final String dirPath = myFixture.getTempDirPath() + getContentRootPath();
|
||||
final File dir = new File(dirPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
assertTrue(dir.mkdirs());
|
||||
}
|
||||
tuneModule(moduleFixtureBuilder, dirPath);
|
||||
|
||||
final List<MyAdditionalModuleData> modules = new ArrayList<MyAdditionalModuleData>();
|
||||
configureAdditionalModules(projectBuilder, modules);
|
||||
|
||||
myFixture.setUp();
|
||||
myFixture.setTestDataPath(getTestDataPath());
|
||||
myModule = moduleFixtureBuilder.getFixture().getModule();
|
||||
|
||||
// Must be done before addAndroidFacet, and must always be done, even if !myCreateManifest.
|
||||
// We will delete it at the end of setUp; this is needed when unit tests want to rewrite
|
||||
// the manifest on their own.
|
||||
createManifest();
|
||||
|
||||
androidSdk = createAndroidSdk(getTestSdkPath(), getPlatformDir());
|
||||
myFacet = addAndroidFacet(myModule, sdkPath, getPlatformDir(), isToAddSdk());
|
||||
for (File resDir : getResourceDirs(dirPath)) {
|
||||
if (resDir.exists()) {
|
||||
myFixture.copyDirectoryToProject(resDir.getName(), resDir.getName());
|
||||
} else {
|
||||
Logger.getInstance(this.getClass()).info("No res directory found in test");
|
||||
}
|
||||
}
|
||||
myAdditionalModules = new ArrayList<Module>();
|
||||
|
||||
for (MyAdditionalModuleData data : modules) {
|
||||
final Module additionalModule = data.myModuleFixtureBuilder.getFixture().getModule();
|
||||
myAdditionalModules.add(additionalModule);
|
||||
final AndroidFacet facet = addAndroidFacet(additionalModule, sdkPath, getPlatformDir());
|
||||
facet.setLibraryProject(data.myLibrary);
|
||||
final String rootPath = getContentRootPath(data.myDirName);
|
||||
myFixture.copyDirectoryToProject("res", rootPath + "/res");
|
||||
myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML,
|
||||
rootPath + '/' + SdkConstants.FN_ANDROID_MANIFEST_XML);
|
||||
ModuleRootModificationUtil.addDependency(myModule, additionalModule);
|
||||
}
|
||||
|
||||
if (!myCreateManifest) {
|
||||
deleteManifest();
|
||||
}
|
||||
|
||||
if (RenderSecurityManager.RESTRICT_READS) {
|
||||
// Unit test class loader includes disk directories which security manager does not allow access to
|
||||
RenderSecurityManager.sEnabled = false;
|
||||
}
|
||||
|
||||
((StartupManagerImpl) StartupManager.getInstance(getProject())).runPostStartupActivities();
|
||||
|
||||
kotlinInternalModeOriginalValue = KotlinInternalMode.Instance.getEnabled();
|
||||
KotlinInternalMode.Instance.setEnabled(true);
|
||||
}
|
||||
|
||||
protected boolean isToAddSdk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String getContentRootPath() {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected void configureAdditionalModules(@NotNull TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder,
|
||||
@NotNull List<MyAdditionalModuleData> modules) {
|
||||
}
|
||||
|
||||
protected static String getContentRootPath(@NotNull String moduleName) {
|
||||
return "/additionalModules/" + moduleName;
|
||||
}
|
||||
|
||||
public static void tuneModule(JavaModuleFixtureBuilder moduleBuilder, String moduleDirPath) {
|
||||
moduleBuilder.addContentRoot(moduleDirPath);
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new File(moduleDirPath + "/src/").mkdir();
|
||||
moduleBuilder.addSourceRoot("src");
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new File(moduleDirPath + "/gen/").mkdir();
|
||||
moduleBuilder.addSourceRoot("gen");
|
||||
}
|
||||
|
||||
protected void createManifest() throws IOException {
|
||||
myFixture.copyFileToProject("plugins/android-extensions/android-extensions-idea/testData/android/AndroidManifest.xml",
|
||||
SdkConstants.FN_ANDROID_MANIFEST_XML);
|
||||
}
|
||||
|
||||
protected void deleteManifest() throws IOException {
|
||||
deleteManifest(myModule);
|
||||
}
|
||||
|
||||
protected void deleteManifest(final Module module) throws IOException {
|
||||
final AndroidFacet facet = AndroidFacet.getInstance(module);
|
||||
assertNotNull(facet);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String manifestRelativePath = facet.getProperties().MANIFEST_FILE_RELATIVE_PATH;
|
||||
VirtualFile manifest = AndroidRootUtil.getFileByRelativeModulePath(module, manifestRelativePath, true);
|
||||
if (manifest != null) {
|
||||
try {
|
||||
manifest.delete(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
fail("Could not delete default manifest");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
KotlinInternalMode.Instance.setEnabled(kotlinInternalModeOriginalValue);
|
||||
|
||||
Field listenersField = PsiProjectListener.class.getDeclaredField("myListeners");
|
||||
listenersField.setAccessible(true);
|
||||
Map listeners = (Map)listenersField.get(PsiProjectListener.getInstance(getProject()));
|
||||
listeners.clear();
|
||||
|
||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
|
||||
super.tearDown();
|
||||
|
||||
myModule = null;
|
||||
myAdditionalModules = null;
|
||||
myFixture.tearDown();
|
||||
myFixture = null;
|
||||
myFacet = null;
|
||||
|
||||
if (RenderSecurityManager.RESTRICT_READS) {
|
||||
RenderSecurityManager.sEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public AndroidFacet addAndroidFacet(Module module, String sdkPath, String platformDir) {
|
||||
return addAndroidFacet(module, sdkPath, platformDir, true);
|
||||
}
|
||||
|
||||
public AndroidFacet addAndroidFacet(Module module, String sdkPath, String platformDir, boolean addSdk) {
|
||||
FacetManager facetManager = FacetManager.getInstance(module);
|
||||
AndroidFacet facet = facetManager.createFacet(AndroidFacet.getFacetType(), "Android", null);
|
||||
|
||||
if (addSdk) {
|
||||
addAndroidSdk(module, sdkPath, platformDir);
|
||||
}
|
||||
final ModifiableFacetModel facetModel = facetManager.createModifiableModel();
|
||||
facetModel.addFacet(facet);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
facetModel.commit();
|
||||
}
|
||||
});
|
||||
return facet;
|
||||
}
|
||||
|
||||
protected static class MyAdditionalModuleData {
|
||||
final JavaModuleFixtureBuilder myModuleFixtureBuilder;
|
||||
final String myDirName;
|
||||
final boolean myLibrary;
|
||||
|
||||
private MyAdditionalModuleData(@NotNull JavaModuleFixtureBuilder moduleFixtureBuilder,
|
||||
@NotNull String dirName,
|
||||
boolean library) {
|
||||
myModuleFixtureBuilder = moduleFixtureBuilder;
|
||||
myDirName = dirName;
|
||||
myLibrary = library;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.kotlin.android;
|
||||
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.SdkModificator;
|
||||
import com.intellij.openapi.roots.JavadocOrderRootType;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.testFramework.IdeaTestCase;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
|
||||
import org.jetbrains.android.sdk.AndroidSdkAdditionalData;
|
||||
import org.jetbrains.android.sdk.AndroidSdkData;
|
||||
import org.jetbrains.android.sdk.AndroidSdkType;
|
||||
import org.jetbrains.kotlin.idea.test.RunnableWithException;
|
||||
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
|
||||
public abstract class KotlinAndroidTestCaseBase extends UsefulTestCase {
|
||||
/** Environment variable or system property containing the full path to an SDK install */
|
||||
public static final String SDK_PATH_PROPERTY = "ADT_TEST_SDK_PATH";
|
||||
|
||||
/** Environment variable or system property pointing to the directory name of the platform inside $sdk/platforms, e.g. "android-17" */
|
||||
public static final String PLATFORM_DIR_PROPERTY = "ADT_TEST_PLATFORM";
|
||||
|
||||
protected CodeInsightTestFixture myFixture;
|
||||
|
||||
protected Sdk androidSdk;
|
||||
protected VirtualFile androidJar;
|
||||
|
||||
private static final String TEST_DATA_PROJECT_RELATIVE = "/plugins/android-extensions/android-extensions-idea/testData/android";
|
||||
|
||||
protected KotlinAndroidTestCaseBase() {
|
||||
IdeaTestCase.initPlatformPrefix();
|
||||
}
|
||||
|
||||
public static String getPluginTestDataPathBase() {
|
||||
return KotlinTestUtils.getHomeDirectory() + TEST_DATA_PROJECT_RELATIVE;
|
||||
}
|
||||
|
||||
public String getTestDataPath() {
|
||||
return getPluginTestDataPathBase();
|
||||
}
|
||||
|
||||
public String getDefaultTestSdkPath() {
|
||||
return getTestDataPath() + "/sdk1.5";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
KotlinAndroidTestCaseBase.super.tearDown();
|
||||
androidJar = null;
|
||||
androidSdk = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getDefaultPlatformDir() {
|
||||
return "android-1.5";
|
||||
}
|
||||
|
||||
protected String getTestSdkPath() {
|
||||
if (requireRecentSdk()) {
|
||||
String override = System.getProperty(SDK_PATH_PROPERTY);
|
||||
if (override != null) {
|
||||
assertTrue("Must also define " + PLATFORM_DIR_PROPERTY, System.getProperty(PLATFORM_DIR_PROPERTY) != null);
|
||||
assertTrue(override, new File(override).exists());
|
||||
return override;
|
||||
}
|
||||
override = System.getenv(SDK_PATH_PROPERTY);
|
||||
if (override != null) {
|
||||
assertTrue("Must also define " + PLATFORM_DIR_PROPERTY, System.getenv(PLATFORM_DIR_PROPERTY) != null);
|
||||
return override;
|
||||
}
|
||||
fail("This unit test requires " + SDK_PATH_PROPERTY + " and " + PLATFORM_DIR_PROPERTY + " to be defined.");
|
||||
}
|
||||
|
||||
return getDefaultTestSdkPath();
|
||||
}
|
||||
|
||||
protected String getPlatformDir() {
|
||||
if (requireRecentSdk()) {
|
||||
String override = System.getProperty(PLATFORM_DIR_PROPERTY);
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
override = System.getenv(PLATFORM_DIR_PROPERTY);
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
fail("This unit test requires " + SDK_PATH_PROPERTY + " and " + PLATFORM_DIR_PROPERTY + " to be defined.");
|
||||
}
|
||||
return getDefaultPlatformDir();
|
||||
}
|
||||
|
||||
/** Is the bundled (incomplete) SDK install adequate or do we need to find a valid install? */
|
||||
protected boolean requireRecentSdk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void addAndroidSdk(Module module, String sdkPath, String platformDir) {
|
||||
assert androidSdk != null : "android sdk must be initialized";
|
||||
ModuleRootModificationUtil.setModuleSdk(module, androidSdk);
|
||||
}
|
||||
|
||||
public Sdk createAndroidSdk(String sdkPath, String platformDir) {
|
||||
Sdk sdk = ProjectJdkTable.getInstance().createSdk("android_test_sdk", AndroidSdkType.getInstance());
|
||||
SdkModificator sdkModificator = sdk.getSdkModificator();
|
||||
sdkModificator.setHomePath(sdkPath);
|
||||
|
||||
if (platformDir.equals(getDefaultPlatformDir())) {
|
||||
// Compatibility: the unit tests were using android.jar outside the sdk1.5 install;
|
||||
// we need to use that one, rather than the real one in sdk1.5, in order for the
|
||||
// tests to pass. Longer term, we should switch the unit tests over to all using
|
||||
// a valid SDK.
|
||||
String androidJarPath = sdkPath + "/../android.jar!/";
|
||||
androidJar = VirtualFileManager.getInstance().findFileByUrl("jar://" + androidJarPath);
|
||||
} else {
|
||||
androidJar = VirtualFileManager.getInstance().findFileByUrl("jar://" + sdkPath + "/platforms/" + platformDir + "/android.jar!/");
|
||||
}
|
||||
sdkModificator.addRoot(androidJar, OrderRootType.CLASSES);
|
||||
|
||||
VirtualFile resFolder = LocalFileSystem.getInstance().findFileByPath(sdkPath + "/platforms/" + platformDir + "/data/res");
|
||||
sdkModificator.addRoot(resFolder, OrderRootType.CLASSES);
|
||||
|
||||
VirtualFile docsFolder = LocalFileSystem.getInstance().findFileByPath(sdkPath + "/docs/reference");
|
||||
if (docsFolder != null) {
|
||||
sdkModificator.addRoot(docsFolder, JavadocOrderRootType.getInstance());
|
||||
}
|
||||
|
||||
AndroidSdkAdditionalData data = new AndroidSdkAdditionalData(sdk);
|
||||
AndroidSdkData sdkData = AndroidSdkData.getSdkData(sdkPath);
|
||||
assertNotNull(sdkData);
|
||||
IAndroidTarget target = sdkData.findTargetByName("Android 5.0"); // TODO: Get rid of this hardcoded version number
|
||||
if (target == null) {
|
||||
IAndroidTarget[] targets = sdkData.getTargets();
|
||||
for (IAndroidTarget t : targets) {
|
||||
if (t.getLocation().contains(platformDir)) {
|
||||
target = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target == null && targets.length > 0) {
|
||||
target = targets[targets.length - 1];
|
||||
}
|
||||
}
|
||||
assertNotNull(target);
|
||||
data.setBuildTarget(target);
|
||||
sdkModificator.setSdkAdditionalData(data);
|
||||
sdkModificator.commitChanges();
|
||||
return sdk;
|
||||
}
|
||||
|
||||
protected Project getProject() {
|
||||
return myFixture.getProject();
|
||||
}
|
||||
}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.intentions
|
||||
|
||||
import com.android.SdkConstants
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.android.KotlinAndroidTestCase
|
||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
|
||||
|
||||
abstract class AbstractAndroidResourceIntentionTest : KotlinAndroidTestCase() {
|
||||
|
||||
fun doTest(path: String) {
|
||||
val configFile = File(path)
|
||||
val testDataPath = configFile.parent
|
||||
|
||||
myFixture.testDataPath = testDataPath
|
||||
|
||||
val config = JsonParser().parse(FileUtil.loadFile(File(path), true)) as JsonObject
|
||||
|
||||
val intentionClass = config.getString("intentionClass")
|
||||
val isApplicableExpected = if (config.has("isApplicable")) config.get("isApplicable").asBoolean else true
|
||||
val rFile = if (config.has("rFile")) config.get("rFile").asString else null
|
||||
val resDirectory = if (config.has("resDirectory")) config.get("resDirectory").asString else null
|
||||
|
||||
if (rFile != null) {
|
||||
myFixture.copyFileToProject(rFile, "gen/" + PathUtil.getFileName(rFile))
|
||||
}
|
||||
else {
|
||||
if (File(testDataPath + "/R.java").isFile) {
|
||||
myFixture.copyFileToProject("R.java", "gen/R.java")
|
||||
}
|
||||
}
|
||||
|
||||
if (resDirectory != null) {
|
||||
myFixture.copyDirectoryToProject(resDirectory, "res")
|
||||
}
|
||||
else {
|
||||
if (File(testDataPath + "/res").isDirectory) {
|
||||
myFixture.copyDirectoryToProject("res", "res")
|
||||
}
|
||||
}
|
||||
|
||||
val sourceFile = myFixture.copyFileToProject("main.kt", "src/main.kt")
|
||||
myFixture.configureFromExistingVirtualFile(sourceFile)
|
||||
|
||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(myFixture.file as KtFile)
|
||||
|
||||
val intentionAction = Class.forName(intentionClass).newInstance() as IntentionAction
|
||||
|
||||
TestCase.assertEquals(isApplicableExpected, intentionAction.isAvailable(myFixture.project, myFixture.editor, myFixture.file))
|
||||
if (!isApplicableExpected) {
|
||||
return
|
||||
}
|
||||
|
||||
val element = getTargetElement()
|
||||
element?.putUserData(CREATE_XML_RESOURCE_PARAMETERS_NAME_KEY, "resource_id")
|
||||
|
||||
myFixture.launchAction(intentionAction)
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(myFixture.file as KtFile)
|
||||
|
||||
myFixture.checkResultByFile("/expected/main.kt")
|
||||
assertResourcesEqual(testDataPath + "/expected/res")
|
||||
}
|
||||
|
||||
fun assertResourcesEqual(expectedPath: String) {
|
||||
PlatformTestUtil.assertDirectoriesEqual(LocalFileSystem.getInstance().findFileByPath(expectedPath), getResourceDirectory())
|
||||
}
|
||||
|
||||
fun getResourceDirectory() = LocalFileSystem.getInstance().findFileByPath(myFixture.tempDirPath + "/res")
|
||||
|
||||
fun getTargetElement() = myFixture.file.findElementAt(myFixture.caretOffset)?.parent
|
||||
|
||||
override fun createManifest() {
|
||||
myFixture.copyFileToProject("idea/testData/android/AndroidManifest.xml", SdkConstants.FN_ANDROID_MANIFEST_XML)
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android.intentions;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("idea/testData/android/resourceIntentions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class AndroidResourceIntentionTestGenerated extends AbstractAndroidResourceIntentionTest {
|
||||
public void testAllFilesPresentInResourceIntentions() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/android/resourceIntentions"), Pattern.compile("^(.+)\\.test$"));
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/activityExtension/activityExtension.test")
|
||||
public void testKotlinAndroidAddStringResource_activityExtension_ActivityExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/activityExtension/activityExtension.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/activityMethod/activityMethod.test")
|
||||
public void testKotlinAndroidAddStringResource_activityMethod_ActivityMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/activityMethod/activityMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/classInActivity/classInActivity.test")
|
||||
public void testKotlinAndroidAddStringResource_classInActivity_ClassInActivity() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/classInActivity/classInActivity.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/extensionLambda/extensionLambda.test")
|
||||
public void testKotlinAndroidAddStringResource_extensionLambda_ExtensionLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/extensionLambda/extensionLambda.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/function/function.test")
|
||||
public void testKotlinAndroidAddStringResource_function_Function() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/function/function.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/innerClassInActivity/innerClassInActivity.test")
|
||||
public void testKotlinAndroidAddStringResource_innerClassInActivity_InnerClassInActivity() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/innerClassInActivity/innerClassInActivity.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/innerViewInActivity/innerViewInActivity.test")
|
||||
public void testKotlinAndroidAddStringResource_innerViewInActivity_InnerViewInActivity() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/innerViewInActivity/innerViewInActivity.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/objectInActivity/objectInActivity.test")
|
||||
public void testKotlinAndroidAddStringResource_objectInActivity_ObjectInActivity() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/objectInActivity/objectInActivity.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/objectInActivityMethod/objectInActivityMethod.test")
|
||||
public void testKotlinAndroidAddStringResource_objectInActivityMethod_ObjectInActivityMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/objectInActivityMethod/objectInActivityMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/objectInFunction/objectInFunction.test")
|
||||
public void testKotlinAndroidAddStringResource_objectInFunction_ObjectInFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/objectInFunction/objectInFunction.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/stringTemplate/stringTemplate.test")
|
||||
public void testKotlinAndroidAddStringResource_stringTemplate_StringTemplate() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/stringTemplate/stringTemplate.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/viewExtensionActivityMethod/viewExtensionActivityMethod.test")
|
||||
public void testKotlinAndroidAddStringResource_viewExtensionActivityMethod_ViewExtensionActivityMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/viewExtensionActivityMethod/viewExtensionActivityMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinAndroidAddStringResource/viewMethod/viewMethod.test")
|
||||
public void testKotlinAndroidAddStringResource_viewMethod_ViewMethod() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/android/resourceIntentions/kotlinAndroidAddStringResource/viewMethod/viewMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user