From cf1e01cc56bb17c98cc3d54ec983c4a9dc10fc42 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Thu, 10 Mar 2022 17:07:42 -0800 Subject: Add tests for UsageInfoTreeNode Test: N/A Bug: 220017221 Change-Id: I8417bd6552877e7f0b2fd2c22669af95a6a41eae --- .../modularize/UsageInfoTreeNodeTest.kt | 299 +++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 android/testSrc/com/android/tools/idea/refactoring/modularize/UsageInfoTreeNodeTest.kt (limited to 'android') diff --git a/android/testSrc/com/android/tools/idea/refactoring/modularize/UsageInfoTreeNodeTest.kt b/android/testSrc/com/android/tools/idea/refactoring/modularize/UsageInfoTreeNodeTest.kt new file mode 100644 index 00000000000..a4b4708e119 --- /dev/null +++ b/android/testSrc/com/android/tools/idea/refactoring/modularize/UsageInfoTreeNodeTest.kt @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2022 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 com.android.tools.idea.refactoring.modularize + +import com.android.ide.common.resources.configuration.FolderConfiguration +import com.android.testutils.MockitoKt.any +import com.android.testutils.MockitoKt.argThat +import com.android.testutils.MockitoKt.eq +import com.android.testutils.MockitoKt.getTypedArgument +import com.android.testutils.MockitoKt.mock +import com.android.testutils.MockitoKt.mockStatic +import com.android.tools.idea.res.getFolderConfiguration +import com.google.common.truth.Truth.assertThat +import com.intellij.openapi.application.Application +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.util.Computable +import com.intellij.openapi.util.Iconable +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.xml.XmlTag +import com.intellij.ui.ColoredTreeCellRenderer +import com.intellij.ui.SimpleTextAttributes +import com.intellij.usageView.UsageInfo +import org.junit.Test +import org.mockito.Mockito +import org.mockito.Mockito.never +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import java.awt.Color +import javax.swing.Icon +import kotlin.random.Random +import kotlin.test.assertFailsWith +import org.mockito.Mockito.`when` as given + +class UsageInfoTreeNodeTest { + + @Test + fun `constructor populates PsiElement from UsageInfo`() { + val usageInfo = mock() + val element = mock() + given(usageInfo.element).thenReturn(element) + + val node = UsageInfoTreeNode(usageInfo, Random.nextInt()) + + assertThat(node.psiElement).isEqualTo(element) + } + + @Test + fun `constructor can populate PsiElement with null missing form UsageInfo`() { + val node = UsageInfoTreeNode(mock(), Random.nextInt()) + + assertThat(node.psiElement).isNull() + } + + @Test + fun `render throws a NPE if the PsiElement is missing`() { + val app = mock() + given(app.runReadAction(any>())).thenAnswer { + it.getTypedArgument>(0).compute() + } + + val node = UsageInfoTreeNode(mock(), Random.nextInt()) + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(app) + + assertFailsWith { node.render(mock()) } + } + } + + @Test + fun `render sets the icon from the PsiElement`() { + val icon = mock() + val element = mock() + given(element.getIcon(Iconable.ICON_FLAG_VISIBILITY or Iconable.ICON_FLAG_READ_STATUS)).thenReturn(icon) + val usageInfo = mock() + given(usageInfo.element).thenReturn(element) + + val app = mock() + given(app.runReadAction(any>())).thenAnswer { + it.getTypedArgument>(0).compute() + } + + val renderer = mock() + + val node = UsageInfoTreeNode(usageInfo, Random.nextInt()) + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(app) + + assertThat( + assertFailsWith { node.render(renderer) }) + .hasMessageThat().isEqualTo("Unknown psiElement $element") + verify(renderer).icon = icon + } + } + + @Test + fun `render appends XmlTag's text with attributes`() { + val text = "" + val xmlTag = mock() + given(xmlTag.text).thenReturn(text) + val usageInfo = mock() + given(usageInfo.element).thenReturn(xmlTag) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + Mockito.doReturn(attributes).`when`(node).textAttributes + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + node.render(renderer) + + verify(renderer).append(eq(text), eq(attributes)) + } + } + + @Test + fun `render handles PsiClass with name`() { + val name = "" + val psiClass = mock() + given(psiClass.name).thenReturn(name) + val usageInfo = mock() + given(usageInfo.element).thenReturn(psiClass) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + Mockito.doReturn(attributes).`when`(node).textAttributes + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + node.render(renderer) + + verify(renderer).append(eq(name), eq(attributes)) + verify(node).renderReferenceCount(eq(renderer), eq(attributes)) + } + } + + @Test + fun `render handles PsiClass without name`() { + val psiClass = mock() + given(psiClass.name).thenReturn(null) + val usageInfo = mock() + given(usageInfo.element).thenReturn(psiClass) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + Mockito.doReturn(attributes).`when`(node).textAttributes + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + node.render(renderer) + + verify(renderer).append(eq(""), eq(attributes)) + verify(node).renderReferenceCount(eq(renderer), eq(attributes)) + } + } + + @Test + fun `render handles PsiFile with nontrivial folder config`() { + val name = "" + val psiFile = mock() + given(psiFile.name).thenReturn(name) + val usageInfo = mock() + given(usageInfo.element).thenReturn(psiFile) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + val color = mock() + given(attributes.fgColor).thenReturn(color) + Mockito.doReturn(attributes).`when`(node).textAttributes + + val qualifierString = "" + val folderConfiguration = mock() + given(folderConfiguration.qualifierString).thenReturn(qualifierString) + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + val `JVM class containing getFolderConfiguration` = Class.forName("com.android.tools.idea.res.IdeResourcesUtil") + Mockito.mockStatic(`JVM class containing getFolderConfiguration`).use { + given(getFolderConfiguration(psiFile)).thenReturn(folderConfiguration) + + mockStatic().use { + given(StringUtil.isEmptyOrSpaces(qualifierString)).thenReturn(false) + + node.render(renderer) + + verify(renderer).append(eq(name), eq(attributes)) + verify(renderer).append(eq(" ($qualifierString)"), argThat { + it.style == attributes.style or SimpleTextAttributes.STYLE_SMALLER && + it.fgColor == attributes.fgColor + }) + verify(node).renderReferenceCount(eq(renderer), eq(attributes)) + } + } + } + } + + @Test + fun `render handles PsiFile with trivial folder config`() { + val name = "" + val psiFile = mock() + given(psiFile.name).thenReturn(name) + val usageInfo = mock() + given(usageInfo.element).thenReturn(psiFile) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + val color = mock() + given(attributes.fgColor).thenReturn(color) + Mockito.doReturn(attributes).`when`(node).textAttributes + + val qualifierString = "" + val folderConfiguration = mock() + given(folderConfiguration.qualifierString).thenReturn(qualifierString) + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + val `JVM class containing getFolderConfiruation` = Class.forName("com.android.tools.idea.res.IdeResourcesUtil") + Mockito.mockStatic(`JVM class containing getFolderConfiruation`).use { + given(getFolderConfiguration(psiFile)).thenReturn(folderConfiguration) + + mockStatic().use { + given(StringUtil.isEmptyOrSpaces(qualifierString)).thenReturn(true) + + node.render(renderer) + + verify(renderer).append(eq(name), eq(attributes)) + verify(renderer, never()).append(eq(" ($qualifierString)"), argThat { + it.style == attributes.style or SimpleTextAttributes.STYLE_SMALLER && + it.fgColor == attributes.fgColor + }) + verify(node).renderReferenceCount(eq(renderer), eq(attributes)) + } + } + } + } + + @Test + fun `render raises NPE on PsiFile without folder config`() { + val name = "" + val psiFile = mock() + given(psiFile.name).thenReturn(name) + val usageInfo = mock() + given(usageInfo.element).thenReturn(psiFile) + + val renderer = mock() + + val node = spy(UsageInfoTreeNode(usageInfo, Random.nextInt())) + val attributes = mock() + val color = mock() + given(attributes.fgColor).thenReturn(color) + Mockito.doReturn(attributes).`when`(node).textAttributes + + mockStatic().use { + given(ApplicationManager.getApplication()).thenReturn(mock()) + + val `JVM class containing getFolderConfiguration` = Class.forName("com.android.tools.idea.res.IdeResourcesUtil") + Mockito.mockStatic(`JVM class containing getFolderConfiguration`).use { + given(getFolderConfiguration(psiFile)).thenReturn(null) + + assertFailsWith { node.render(renderer) } + + verify(renderer).append(eq(name), eq(attributes)) + verify(node, never()).renderReferenceCount(eq(renderer), eq(attributes)) + } + } + } +} \ No newline at end of file -- cgit v1.2.3