blob: 05bb3c1f946629f0e74f929b66265040bcecd0b6 [file] [log] [blame]
/*
* Copyright (C) 2019 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.compose
import com.android.SdkConstants
import com.android.tools.idea.flags.StudioFlags
import com.android.tools.idea.project.DefaultModuleSystem
import com.android.tools.idea.projectsystem.getModuleSystem
import com.android.tools.idea.testing.AndroidProjectRule
import com.android.tools.idea.testing.loadNewFile
import com.android.tools.idea.testing.moveCaret
import com.android.tools.idea.ui.resourcemanager.rendering.MultipleColorIcon
import com.google.common.truth.Truth.assertThat
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl
import com.intellij.lang.annotation.AnnotationSession
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import com.intellij.testFramework.EdtRule
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.RunsInEdt
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
import com.intellij.testFramework.runInEdtAndWait
import org.jetbrains.android.AndroidAnnotatorUtil
import org.jetbrains.android.compose.stubComposableAnnotation
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import java.awt.Color
/**
* Tests for [ComposeColorAnnotator]
*/
class ComposeColorAnnotatorTest {
@get:Rule
val projectRule = AndroidProjectRule.onDisk()
private val myFixture: JavaCodeInsightTestFixture by lazy { projectRule.fixture as JavaCodeInsightTestFixture }
@Before
fun setUp() {
StudioFlags.COMPOSE_EDITOR_SUPPORT.override(true)
(myFixture.module.getModuleSystem() as DefaultModuleSystem).usesCompose = true
myFixture.addClass(
//language=kotlin
"""
package androidx.compose.ui.graphics
class ColorSpace
""")
myFixture.addFileToProject(
"src/com/androidx/compose/ui/graphics/Color.kt",
//language=kotlin
"""
package androidx.compose.ui.graphics
fun Color(color: Int): Long = 1L
fun Color(color: Long): Long = 1L
fun Color(
red: Int,
green: Int,
blue: Int,
alpha: Int = 0xFF
): Long = 1L
fun Color(
red: Float,
green: Float,
blue: Float,
alpha: Float = 1f,
colorSpace: ColorSpace? = null
): Long = 1L
""".trimIndent())
}
@Test
fun testColorLong() {
val psiFile = myFixture.addFileToProject(
"src/com/android/test/A.kt",
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(0xFFC20029)
fun () {
val primary = Color(0xFF4A8A7B)
val primaryVariant = Color(color = 0xFF57AD28)
}
}
""".trimIndent())
myFixture.configureFromExistingVirtualFile(psiFile.virtualFile)
checkGutterIconInfos(
listOf(
Color(194, 0, 41),
Color(74, 138, 123),
Color(87, 173, 40)
),
includeClickAction = true
)
setNewColor("Co|lor(0xFF4A8A7B)", Color(0xFFAABBCC.toInt()))
assertThat(myFixture.editor.document.text).isEqualTo(
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(0xFFC20029)
fun () {
val primary = Color(0xFFAABBCC)
val primaryVariant = Color(color = 0xFF57AD28)
}
}
""".trimIndent()
)
}
@Test
fun testColorInt() {
val psiFile = myFixture.addFileToProject(
"src/com/android/test/A.kt",
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(0xC20029)
fun () {
val primary = Color(0x4A8A7B)
val primaryVariant = Color(color = 0x57AD28)
}
}
""".trimIndent())
myFixture.configureFromExistingVirtualFile(psiFile.virtualFile)
checkGutterIconInfos(
listOf(
Color(194, 0, 41, 0),
Color(74, 138, 123, 0),
Color(87, 173, 40, 0)),
includeClickAction = true
)
setNewColor("Co|lor(0x4A8A7B)", Color(0xFFAABBCC.toInt()))
assertThat(myFixture.editor.document.text).isEqualTo(
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(0xC20029)
fun () {
val primary = Color(0xFFAABBCC)
val primaryVariant = Color(color = 0x57AD28)
}
}
""".trimIndent())
}
private fun setNewColor(window: String, newColor: Color) {
runInEdtAndWait {
val element = myFixture.moveCaret(window)
val annotationHolder = AnnotationHolderImpl(AnnotationSession(myFixture.file))
annotationHolder.runAnnotatorWithContext(element.parentOfType<KtCallExpression>()!! as PsiElement, ComposeColorAnnotator())
val iconRenderer = annotationHolder[0].gutterIconRenderer as ColorIconRenderer
iconRenderer.setColorToAttribute(newColor)
PlatformTestUtil.dispatchAllInvocationEventsInIdeEventQueue()
}
}
@Test
fun testColorIntx3x4() {
val psiFile = myFixture.addFileToProject(
"src/com/android/test/A.kt",
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(0.194f, 0f, 0.41f)
fun () {
val primary = Color(0.74f, 0.138f, 0.3f, 0.845f)
val primaryVariant = Color(red = 0.87f, green = 0.173f, blue = 0.4f)
}
}
""".trimIndent())
myFixture.configureFromExistingVirtualFile(psiFile.virtualFile)
checkGutterIconInfos(
listOf(
Color(49, 0, 105),
Color(189, 35, 77, 215),
Color(222, 44, 102)),
includeClickAction = false
)
}
@Test
fun testFloatIntx3x4() {
val psiFile = myFixture.addFileToProject(
"src/com/android/test/A.kt",
//language=kotlin
"""
package com.android.test
import androidx.compose.ui.graphics.Color
class A {
val other = Color(194, 0, 41)
fun () {
val primary = Color(74, 138, 123, 145)
val primaryVariant = Color(red = 87, green = 173, blue = 40)
}
}
""".trimIndent())
myFixture.configureFromExistingVirtualFile(psiFile.virtualFile)
checkGutterIconInfos(
listOf(
Color(194, 0, 41),
Color(74, 138, 123, 145),
Color(87, 173, 40)),
includeClickAction = false
)
}
private fun checkGutterIconInfos(expectedColorIcons: List<Color>, includeClickAction: Boolean) {
val iconList = myFixture.doHighlighting().filter { it.gutterIconRenderer is ColorIconRenderer }.sortedBy { it.startOffset }
assertThat(iconList).hasSize(3)
iconList.forEach {
assertThat(it.gutterIconRenderer.icon).isNotNull()
if (includeClickAction) {
val action = runReadAction { (it.gutterIconRenderer as ColorIconRenderer).clickAction }
assertThat(action).isNotNull()
}
else {
val action = runReadAction { (it.gutterIconRenderer as ColorIconRenderer).clickAction }
assertThat(action).isNull()
}
}
assertThat(iconList.map { (it.gutterIconRenderer as ColorIconRenderer).color }).containsExactlyElementsIn(expectedColorIcons)
}
}
/**
* Tests for [AndroidKotlinResourceExternalAnnotator]
*/
class ComposeColorReferenceAnnotatorTest {
private val projectRule = AndroidProjectRule.onDisk()
@get:Rule
val ruleChain: RuleChain = RuleChain.outerRule(projectRule).around(EdtRule())
private val myFixture: JavaCodeInsightTestFixture by lazy { projectRule.fixture as JavaCodeInsightTestFixture }
@Before
fun setUp() {
(myFixture.module.getModuleSystem() as DefaultModuleSystem).usesCompose = true
myFixture.stubComposableAnnotation(ComposeFqNames.root)
myFixture.testDataPath = getComposePluginTestDataPath()
myFixture.copyFileToProject("annotator/colors.xml", "res/values/colors.xml")
myFixture.copyFileToProject("annotator/AndroidManifest.xml", SdkConstants.FN_ANDROID_MANIFEST_XML)
}
// Regression test for https://issuetracker.google.com/144560843
@RunsInEdt
@Test
fun testColorReferenceNoLayout() {
myFixture.loadNewFile(
"src/com/example/MyViews.kt",
// language=kotlin
"""
package p1.p2
import androidx.compose.runtime.Composable
@Composable
fun Foobar(required: Int) {
val drawable = R.drawable.ic_tick
val color = R.color.color1
}
""".trimIndent()
)
val icons = myFixture.findAllGutters()
val colorGutterIconRenderer = icons.firstIsInstance<AndroidAnnotatorUtil.ColorRenderer>()
assertThat((colorGutterIconRenderer.icon as MultipleColorIcon).colors).containsExactlyElementsIn(arrayOf(Color(63, 81, 181)))
}
}