blob: 27636134058472d5934b28fc11876616eea715a1 [file] [log] [blame]
/*
* Copyright 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.
*/
@file:Suppress("UnstableApiUsage")
package androidx.fragment.lint
import androidx.fragment.lint.stubs.FRAGMENT_TRANSACTION_STUBS
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestLintResult
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
class AttachAndDetachInSameTransactionDetectorTest : LintDetectorTest() {
override fun getDetector(): Detector = AttachAndDetachInSameTransactionDetector()
override fun getIssues(): MutableList<Issue> =
mutableListOf(AttachAndDetachInSameTransactionDetector.DETACH_ATTACH_OPERATIONS_ISSUE)
private fun check(vararg files: TestFile): TestLintResult {
return lint().files(*files, *FRAGMENT_TRANSACTION_STUBS)
.run()
}
@Test
fun pass() {
check(
kotlin(
"""
package com.example
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.example.test.Foo
class Test {
private fun testPassingToAnotherClass() {
val ft = FragmentManager().beginTransaction()
val foo = Foo().commitTransaction(ft)
}
private fun testTwoDifferentFragments() {
val fragment1 = Fragment()
val fragment2 = Fragment()
val ft = FragmentManager().beginTransaction()
ft.attach(fragment1)
ft.detach(fragment2)
ft.commit()
}
// If the variable is reassigned even though it is the same instance we won't warn
private fun testReassign() {
val fragment3 = Fragment()
val fragment4 = fragment3
val ft = FragmentManager().beginTransaction()
ft.attach(fragment3)
ft.detach(fragment4)
ft.commit()
}
// If the fragment is passed through to another function we won't warn
private fun testPassingToAnother() {
val fragment = Fragment()
val ft = FragmentManager().beginTransaction()
ft.attach(fragment)
helper(ft, fragment)
}
private fun helper(ft: FragmentTransaction, fragment: Fragment) {
ft.detach(fragment)
ft.commit()
}
}
"""
),
kotlin(
"""
package com.example.test
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
class Foo {
fun commitTransaction(fragmentTransaction: FragmentTransaction, fragment: Fragment) {
val fragment1 = Fragment()
val fragment2 = Fragment()
fragmentTransaction.attach(fragment1)
fragmentTransaction.detach(fragment2)
fragmentTransaction.commit()
}
}
"""
)
)
.expectClean()
}
@Test
fun inMethodFails() {
check(
kotlin(
"""
package com.example
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
class Test {
private fun testInternal() {
val fragment = Fragment()
val ft = FragmentManager().beginTransaction()
ft.attach(fragment)
ft.detach(fragment)
ft.commit()
}
}
"""
)
)
.expect(
"""
src/com/example/Test.kt:11: Warning: Calling detach() and attach() in the same FragmentTransaction is a no-op, meaning it does not recreate the Fragment's view. If you would like the view to be recreated, separate these operations into separate transactions. [DetachAndAttachSameFragment]
val ft = FragmentManager().beginTransaction()
~~~~~~~~~~~~~~~~
0 errors, 1 warnings
"""
)
}
@Test
fun helperMethodFails() {
check(
kotlin(
"""
package com.example
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
class Test {
private fun test() {
val fragment = Fragment()
helper(fragment)
}
private fun helper(fragment: Fragment) {
val ft = FragmentManager().beginTransaction()
ft.detach(fragment)
ft.attach(fragment)
ft.commit()
}
}
"""
)
)
.expect(
"""
src/com/example/Test.kt:15: Warning: Calling detach() and attach() in the same FragmentTransaction is a no-op, meaning it does not recreate the Fragment's view. If you would like the view to be recreated, separate these operations into separate transactions. [DetachAndAttachSameFragment]
val ft = FragmentManager().beginTransaction()
~~~~~~~~~~~~~~~~
0 errors, 1 warnings
"""
)
}
}