From 1a6f412fac912fda4f0c340c0f290da8010dc5ed Mon Sep 17 00:00:00 2001 From: Ilia Zakoulov Date: Fri, 22 Aug 2025 19:53:13 +0200 Subject: [PATCH] PY-83395: Test add source root quick fix GitOrigin-RevId: df736f6a7d5fb838d5947e2e43ee6a4c96626858 --- .../PyUnresolvedReferencesVisitor.java | 2 +- .../mysrc/foo/abc.py | 1 + .../mysrc/foo/abc_after.py | 1 + .../mysrc/foo/abc_no_src.py | 1 + .../mysrc/foo/abc_no_src_after.py | 1 + .../mysrc/qwerty/qwe.py | 5 ++ ...PyMarkDirectoryAsSourceRootQuickFixTest.kt | 49 +++++++++++++++++++ 7 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc.py create mode 100644 python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_after.py create mode 100644 python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src.py create mode 100644 python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src_after.py create mode 100644 python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/qwerty/qwe.py create mode 100644 python/testSrc/com/jetbrains/python/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest.kt diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesVisitor.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesVisitor.java index d0b7e75f4068..4df3304a1c02 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesVisitor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesVisitor.java @@ -365,7 +365,7 @@ public abstract class PyUnresolvedReferencesVisitor extends PyInspectionVisitor isAddedToInstallAllFix = true; } - ContainerUtil.addAll(fixes, getAddSourceRootQuickFix(node)); + ContainerUtil.addIfNotNull(fixes, getAddSourceRootQuickFix(node)); if (reference instanceof PySubstitutionChunkReference) { return; diff --git a/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc.py b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc.py new file mode 100644 index 000000000000..017367c3abf0 --- /dev/null +++ b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc.py @@ -0,0 +1 @@ +from qwerty.qwe import a_function \ No newline at end of file diff --git a/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_after.py b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_after.py new file mode 100644 index 000000000000..435222297827 --- /dev/null +++ b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_after.py @@ -0,0 +1 @@ +from qwerty.qwe import a_function \ No newline at end of file diff --git a/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src.py b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src.py new file mode 100644 index 000000000000..45b77864201c --- /dev/null +++ b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src.py @@ -0,0 +1 @@ +from qwejfknqweklfnjqlkjwnef.qwe import a_function \ No newline at end of file diff --git a/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src_after.py b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src_after.py new file mode 100644 index 000000000000..45b77864201c --- /dev/null +++ b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/foo/abc_no_src_after.py @@ -0,0 +1 @@ +from qwejfknqweklfnjqlkjwnef.qwe import a_function \ No newline at end of file diff --git a/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/qwerty/qwe.py b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/qwerty/qwe.py new file mode 100644 index 000000000000..09c086952171 --- /dev/null +++ b/python/testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest/mysrc/qwerty/qwe.py @@ -0,0 +1,5 @@ +def a_function(): + pass + +def abc(): + pass \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest.kt b/python/testSrc/com/jetbrains/python/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest.kt new file mode 100644 index 000000000000..0e6d0d898938 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest.kt @@ -0,0 +1,49 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.quickFixes + +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.testFramework.TestDataPath +import com.jetbrains.python.PyQuickFixTestCase +import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection + +@TestDataPath("\$CONTENT_ROOT/../testData/quickFixes/PyMarkDirectoryAsSourceRootQuickFixTest") +class PyMarkDirectoryAsSourceRootQuickFixTest: PyQuickFixTestCase() { + @Throws(Exception::class) + override fun setUp() { + super.setUp() + myFixture.copyDirectoryToProject("", "") + } + + fun testUpdatesSourceRoots() = doSourceRootTest(pyFilePath = "mysrc/foo/abc.py", expectedSourceRootPath = "mysrc") + + fun testNoQuickFixBecauseSourceRootNotFound() = doSourceRootTest(pyFilePath = "mysrc/foo/abc_no_src.py", expectedSourceRootPath = null) + + private fun doSourceRootTest( + pyFilePath: String, + expectedSourceRootPath: String? + ) { + myFixture.enableInspections(PyUnresolvedReferencesInspection::class.java) + myFixture.configureByFile(pyFilePath) + myFixture.checkHighlighting(true, false, false) + val intentionAction = myFixture.filterAvailableIntentions(QUICK_FIX_NAME_BEGINNING) + if (expectedSourceRootPath == null) { + assertEmpty(intentionAction) + return + } + assertSize(1, intentionAction) + myFixture.launchAction(intentionAction[0]) + myFixture.checkResultByFile(pyFilePath.removeSuffix(".py") + "_after.py", true) + + val moduleRootManager = ModuleRootManager.getInstance(myFixture.module) + val sourceRoot = moduleRootManager.sourceRoots.firstOrNull { + it.path == TEST_PROJECT_ROOT_PATH + expectedSourceRootPath + } + assertNotNull("Source root '${expectedSourceRootPath}' not found.", sourceRoot) + } + + companion object { + private const val TEST_PROJECT_ROOT_PATH = "/src/" + // QFIX.add.source.root.for.unresolved.import.name + private const val QUICK_FIX_NAME_BEGINNING = "Mark '" + } +}