summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Vaage <vaage@google.com>2022-07-20 12:04:38 -0700
committerAaron Vaage <vaage@google.com>2022-08-10 14:48:47 +0000
commitdebbd4706b60cfe5380a7c54475ba057b5ae4655 (patch)
treec58735c4bd13b8e7074cfc53fe697de1ca553479
parent81668564896d9ccb63fceb8cc6014108e568c2bb (diff)
downloadidea-debbd4706b60cfe5380a7c54475ba057b5ae4655.tar.gz
Added tests for TraceSignatureConverter
Added tests for TraceSignatureConverter. This did require making some changes to TraceSignatureConverter in order to make it easier to test (changing a method signature). Since this code works with PSI types, which are hard to initialize, the tests do rely heavily on mocks. Change-Id: Iee2aeac51dcf110f58738c6f489f2d1a4e95d83b
-rw-r--r--codenavigation/BUILD1
-rw-r--r--codenavigation/codenavigation.iml1
-rw-r--r--codenavigation/src/com/android/tools/idea/codenavigation/PsiNavSource.kt10
-rw-r--r--codenavigation/src/com/android/tools/idea/codenavigation/TraceSignatureConverter.java33
-rw-r--r--codenavigation/testSrc/TraceSignatureConverterTest.kt121
5 files changed, 147 insertions, 19 deletions
diff --git a/codenavigation/BUILD b/codenavigation/BUILD
index 74bd2dbad80..9c83dbf8f4f 100644
--- a/codenavigation/BUILD
+++ b/codenavigation/BUILD
@@ -13,5 +13,6 @@ iml_module(
"//tools/adt/idea/.idea/libraries:truth[test]",
"//tools/adt/idea/native-symbolizer[module]",
"//tools/adt/idea/android:intellij.android.core[module]",
+ "//tools/adt/idea/.idea/libraries:mockito[test]",
],
)
diff --git a/codenavigation/codenavigation.iml b/codenavigation/codenavigation.iml
index 2044b7850a4..21d293ed98c 100644
--- a/codenavigation/codenavigation.iml
+++ b/codenavigation/codenavigation.iml
@@ -12,5 +12,6 @@
<orderEntry type="library" scope="TEST" name="truth" level="project" />
<orderEntry type="module" module-name="native-symbolizer" />
<orderEntry type="module" module-name="intellij.android.core" />
+ <orderEntry type="library" scope="TEST" name="mockito" level="project" />
</component>
</module> \ No newline at end of file
diff --git a/codenavigation/src/com/android/tools/idea/codenavigation/PsiNavSource.kt b/codenavigation/src/com/android/tools/idea/codenavigation/PsiNavSource.kt
index d846b775529..5e3835021ff 100644
--- a/codenavigation/src/com/android/tools/idea/codenavigation/PsiNavSource.kt
+++ b/codenavigation/src/com/android/tools/idea/codenavigation/PsiNavSource.kt
@@ -21,6 +21,7 @@ import com.intellij.pom.Navigatable
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.util.ClassUtil
/**
@@ -85,7 +86,12 @@ class PsiNavSource(private val project: Project): NavSource {
return null
}
- val methods = psiClass.findMethodsByName(location.methodName, true)
- return methods.firstOrNull{ location.signature == TraceSignatureConverter.getTraceSignature(it) }
+ return psiClass.findMethodsByName(location.methodName, true).firstOrNull{
+ val signature = TraceSignatureConverter.getTraceSignature(
+ it.returnType,
+ it.getSignature(PsiSubstitutor.EMPTY).parameterTypes)
+
+ return@firstOrNull location.signature == signature
+ }
}
} \ No newline at end of file
diff --git a/codenavigation/src/com/android/tools/idea/codenavigation/TraceSignatureConverter.java b/codenavigation/src/com/android/tools/idea/codenavigation/TraceSignatureConverter.java
index 586be96180e..e606c6332a1 100644
--- a/codenavigation/src/com/android/tools/idea/codenavigation/TraceSignatureConverter.java
+++ b/codenavigation/src/com/android/tools/idea/codenavigation/TraceSignatureConverter.java
@@ -18,16 +18,15 @@ package com.android.tools.idea.codenavigation;
import com.google.common.collect.ImmutableMap;
import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClassType;
-import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPrimitiveType;
-import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.TypeConversionUtil;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.VisibleForTesting;
-final class TraceSignatureConverter {
+public final class TraceSignatureConverter {
/**
* Mapping from java primitive type encoding to PsiPrimitiveType
* More about java primitive type encoding: https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName()
@@ -54,15 +53,18 @@ final class TraceSignatureConverter {
* void => "V"
*/
@Nullable
- private static String convertToString(@NotNull PsiType psiType) {
- if (psiType instanceof PsiArrayType) {
- return '[' + convertToString(((PsiArrayType)psiType).getComponentType());
+ @VisibleForTesting
+ public static String convertToString(@NotNull PsiType psiType) {
+ PsiType sanitizedType = TypeConversionUtil.erasure(psiType);
+
+ if (sanitizedType instanceof PsiArrayType) {
+ return '[' + convertToString(((PsiArrayType)sanitizedType).getComponentType());
}
- else if (psiType instanceof PsiPrimitiveType) {
- return String.valueOf(PRIMITIVE_TYPES.get(psiType));
+ else if (sanitizedType instanceof PsiPrimitiveType) {
+ return String.valueOf(PRIMITIVE_TYPES.get(sanitizedType));
}
- else if (psiType instanceof PsiClassType) {
- return "L" + psiType.getCanonicalText().replace('.', '/') + ";";
+ else if (sanitizedType instanceof PsiClassType) {
+ return "L" + sanitizedType.getCanonicalText().replace('.', '/') + ";";
}
return null;
}
@@ -75,18 +77,15 @@ final class TraceSignatureConverter {
* returns (Ljava/util/List;Ljava/util/ArrayList;Z[[Ljava/lang/Integer;)I
*/
@NotNull
- public static String getTraceSignature(@NotNull PsiMethod method) {
+ public static String getTraceSignature(@Nullable PsiType returnType, @NotNull PsiType[] parameterTypes) {
StringBuilder signature = new StringBuilder("(");
- for (PsiType type : method.getSignature(PsiSubstitutor.EMPTY).getParameterTypes()) {
- String converted = convertToString(TypeConversionUtil.erasure(type));
- signature.append(converted);
+ for (PsiType type : parameterTypes) {
+ signature.append(convertToString(type));
}
signature.append(")");
- PsiType returnType = method.getReturnType();
if (returnType != null) {
- String converted = convertToString(TypeConversionUtil.erasure(returnType));
- signature.append(converted);
+ signature.append(convertToString(returnType));
}
return signature.toString();
}
diff --git a/codenavigation/testSrc/TraceSignatureConverterTest.kt b/codenavigation/testSrc/TraceSignatureConverterTest.kt
new file mode 100644
index 00000000000..607bff4cb04
--- /dev/null
+++ b/codenavigation/testSrc/TraceSignatureConverterTest.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+import com.android.tools.idea.codenavigation.TraceSignatureConverter
+import com.google.common.truth.Truth.assertThat
+import com.intellij.psi.PsiArrayType
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiType
+import com.intellij.psi.PsiTypeVisitor
+import org.junit.Test
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+
+class TraceSignatureConverterTest {
+ // Testing with PSI types is challenging since they are not trivial to create. To work around
+ // this we mock the PsiClassType which allows us to test our logic. The hardest part of mocking
+ // them comes from the "accept visitor" functionality which is used to resolve generics. This is
+ // why we needed to mock "accept", "resolve", and "rawTypes".
+ companion object {
+ fun createPsiTypeFor(className: String): PsiType {
+ val type = mock(PsiClassType::class.java)
+ `when`(type.canonicalText).thenReturn(className)
+ `when`(type.accept(any<PsiTypeVisitor<*>>())).thenCallRealMethod()
+ `when`(type.resolve()).thenReturn(null)
+ `when`(type.rawType()).thenReturn(type) // We are our own raw type.
+
+ return type
+ }
+
+ fun createPsiTypeForGeneric(className: String, rawName: String): PsiType {
+ val rawType = mock(PsiClassType::class.java)
+ `when`(rawType.canonicalText).thenReturn(rawName)
+ `when`(rawType.accept(any<PsiTypeVisitor<*>>())).thenCallRealMethod()
+ `when`(rawType.resolve()).thenReturn(null)
+ `when`(rawType.rawType()).thenReturn(rawType) // We are our own raw type.
+
+ val genericType = mock(PsiClassType::class.java)
+ `when`(genericType.canonicalText).thenReturn(className)
+ `when`(genericType.accept(any<PsiTypeVisitor<*>>())).thenCallRealMethod()
+ `when`(genericType.resolve()).thenReturn(null)
+ `when`(genericType.rawType()).thenReturn(rawType)
+
+ return genericType
+ }
+ }
+
+ @Test
+ fun convertsPrimitiveToString() {
+ val str = TraceSignatureConverter.convertToString(PsiType.BYTE)
+ assertThat(str).isEqualTo("B")
+ }
+
+ @Test
+ fun convertsArrayToString() {
+ val type = createPsiTypeFor("java.lang.String")
+ val array = PsiArrayType(PsiArrayType(PsiArrayType(type)))
+
+ val str = TraceSignatureConverter.convertToString(array)
+ assertThat(str).isEqualTo("[[[Ljava/lang/String;")
+ }
+
+ @Test
+ fun convertClassToString() {
+ val type = createPsiTypeFor("java.util.ArrayList")
+
+ val str = TraceSignatureConverter.convertToString(type)
+ assertThat(str).isEqualTo("Ljava/util/ArrayList;")
+ }
+
+ @Test
+ fun convertGenericClassToString() {
+ val type = createPsiTypeForGeneric("java.util.ArrayList<T>", "java.util.ArrayList")
+
+ val str = TraceSignatureConverter.convertToString(type)
+ assertThat(str).isEqualTo("Ljava/util/ArrayList;")
+ }
+
+ @Test
+ fun convertsVoidToString() {
+ val str = TraceSignatureConverter.convertToString(PsiType.VOID)
+ assertThat(str).isEqualTo("V")
+ }
+
+ @Test
+ fun convertsEmptyMethodToString() {
+ val str = TraceSignatureConverter.getTraceSignature(PsiType.INT, emptyArray())
+ assertThat(str).isEqualTo("()I")
+ }
+
+ @Test
+ fun convertsMethodToString() {
+ val str = TraceSignatureConverter.getTraceSignature(PsiType.INT, arrayOf(
+ createPsiTypeForGeneric("java.util.List<String>", "java.util.List"),
+ createPsiTypeForGeneric("java.util.ArrayList<T>", "java.util.ArrayList"),
+ PsiType.BOOLEAN,
+ PsiArrayType(PsiArrayType(createPsiTypeFor("java.lang.Integer")))
+ ))
+
+ assertThat(str).isEqualTo("(Ljava/util/List;Ljava/util/ArrayList;Z[[Ljava/lang/Integer;)I")
+ }
+
+ @Test
+ fun convertsMethodWithNoReturnValueToString() {
+ val str = TraceSignatureConverter.getTraceSignature(null, arrayOf(PsiType.BOOLEAN))
+ assertThat(str).isEqualTo("(Z)")
+ }
+} \ No newline at end of file