mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
IJPL-217109: IAE: [WelcomeScreenNewFileDialog.doOKAction]
- Fix "java.lang.IllegalArgumentException: separators must be '/'" on Windows when creating a new file from the Welcome Screen GitOrigin-RevId: bf5872459ccb17f966f0189c9a3d0be8e102dd07
This commit is contained in:
committed by
intellij-monorepo-bot
parent
011d91dd1f
commit
606636ffce
@@ -364,6 +364,8 @@ jvm_library(
|
||||
"//plugins/jsonpath",
|
||||
"//plugins/jsonpath:jsonpath_test_lib",
|
||||
"//plugins/ui-designer/jps-plugin/tests:tests_test_lib",
|
||||
"//platform/non-modal-welcome-screen",
|
||||
"//platform/non-modal-welcome-screen:non-modal-welcome-screen_test_lib",
|
||||
"//platform/util/coroutines:coroutines-tests_test_lib",
|
||||
"//platform/util/progress:progress-tests_test_lib",
|
||||
"//platform/testFramework/junit5.jimfs",
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
<orderEntry type="module" module-name="intellij.java.guiForms.jps.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.newUiOnboarding" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.newUsersOnboarding" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.nonModalWelcomeScreen" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.kotlin.onboarding.promoter" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.execution.process.elevation" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.vcs.gitlab.yaml" scope="RUNTIME" />
|
||||
|
||||
@@ -36,4 +36,47 @@ jvm_library(
|
||||
],
|
||||
plugins = ["@lib//:compose-plugin"]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.ide.nonModalWelcomeScreen` end
|
||||
|
||||
jvm_library(
|
||||
name = "non-modal-welcome-screen_test_lib",
|
||||
visibility = ["//visibility:public"],
|
||||
srcs = glob(["testSrc/**/*.kt", "testSrc/**/*.java", "testSrc/**/*.form"], allow_empty = True),
|
||||
associates = [":non-modal-welcome-screen"],
|
||||
deps = [
|
||||
"//platform/analysis-api:analysis",
|
||||
"//platform/editor-ui-api:editor-ui",
|
||||
"//platform/compose",
|
||||
"//platform/compose:compose_test_lib",
|
||||
"//platform/core-api:core",
|
||||
"//jps/model-api:model",
|
||||
"//platform/lang-core",
|
||||
"//libraries/compose-runtime-desktop",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"//platform/util:util-ui",
|
||||
"//platform/platform-api:ide",
|
||||
"//platform/lang-impl",
|
||||
"//platform/core-ui",
|
||||
"//platform/ide-core-impl",
|
||||
"//platform/platform-impl:ide-impl",
|
||||
"@lib//:junit5",
|
||||
"//platform/statistics",
|
||||
"//platform/statistics:statistics_test_lib",
|
||||
"//libraries/kotlinx/serialization/core",
|
||||
"//platform/kernel/shared:kernel",
|
||||
"//platform/platform-impl/rpc",
|
||||
"//platform/project/shared:project",
|
||||
],
|
||||
plugins = ["@lib//:compose-plugin"]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.ide.nonModalWelcomeScreen` end
|
||||
|
||||
### auto-generated section `test intellij.platform.ide.nonModalWelcomeScreen` start
|
||||
load("@community//build:tests-options.bzl", "jps_test")
|
||||
|
||||
jps_test(
|
||||
name = "non-modal-welcome-screen_test",
|
||||
runtime_deps = [":non-modal-welcome-screen_test_lib"]
|
||||
)
|
||||
### auto-generated section `test intellij.platform.ide.nonModalWelcomeScreen` end
|
||||
@@ -30,6 +30,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
||||
@@ -22,10 +22,12 @@ import com.intellij.util.ui.FormBuilder
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.event.FocusAdapter
|
||||
import java.awt.event.FocusEvent
|
||||
import java.nio.file.InvalidPathException
|
||||
import java.nio.file.Path
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JList
|
||||
import javax.swing.event.DocumentEvent
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
|
||||
@ApiStatus.Internal
|
||||
class WelcomeScreenNewFileDialog private constructor(
|
||||
@@ -33,8 +35,24 @@ class WelcomeScreenNewFileDialog private constructor(
|
||||
private val builder: Builder,
|
||||
) : DialogWrapper(project, true) {
|
||||
|
||||
private companion object {
|
||||
internal companion object {
|
||||
private const val MAX_PATH_LENGTH = 70
|
||||
|
||||
/**
|
||||
* Normalizes a directory path for use with [DirectoryUtil.mkdirs].
|
||||
*
|
||||
* This method ensures the path:
|
||||
* - Uses forward slashes (/) as separators, which is required by [DirectoryUtil.mkdirs]
|
||||
* - Has redundant path elements (like `.` and `..`) resolved
|
||||
*
|
||||
* This is necessary because on Windows, [Path.toString] returns paths with backslashes,
|
||||
* but [DirectoryUtil.mkdirs] requires forward slashes.
|
||||
*
|
||||
* @see IJPL-217109
|
||||
*/
|
||||
fun normalizeDirectoryPath(path: String): String {
|
||||
return Path.of(path).normalize().invariantSeparatorsPathString
|
||||
}
|
||||
}
|
||||
|
||||
private val targetDirectoryField: ComponentWithBrowseButton<JBTextField> = ComponentWithBrowseButton(ExtendableTextField(), null)
|
||||
@@ -155,7 +173,7 @@ class WelcomeScreenNewFileDialog private constructor(
|
||||
|
||||
val targetDirectoryName = targetDirectoryField.childComponent.text
|
||||
|
||||
if (targetDirectoryName.isEmpty()) {
|
||||
if (targetDirectoryName.isNullOrEmpty()) {
|
||||
Messages.showErrorDialog(
|
||||
project,
|
||||
NonModalWelcomeScreenBundle.message("welcome.screen.create.file.dialog.no.target.directory.specified"),
|
||||
@@ -168,12 +186,14 @@ class WelcomeScreenNewFileDialog private constructor(
|
||||
ApplicationManager.getApplication().runWriteAction {
|
||||
try {
|
||||
targetDirectory = DirectoryUtil.mkdirs(
|
||||
PsiManager.getInstance(project),
|
||||
Path.of(targetDirectoryName).normalize().toString()
|
||||
PsiManager.getInstance(project),
|
||||
normalizeDirectoryPath(targetDirectoryName)
|
||||
)
|
||||
}
|
||||
catch (_: IncorrectOperationException) {
|
||||
}
|
||||
catch (_: InvalidPathException) {
|
||||
}
|
||||
}
|
||||
}, NonModalWelcomeScreenBundle.message("welcome.screen.create.file.dialog.create.directory"), null)
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.ide.nonModalWelcomeScreen.newFileDialog
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import java.nio.file.FileSystems
|
||||
|
||||
/**
|
||||
* Tests for [WelcomeScreenNewFileDialog.normalizeDirectoryPath].
|
||||
*
|
||||
* The method ensures paths use forward slashes, which is required by [DirectoryUtil.mkdirs].
|
||||
*
|
||||
* **Note:** Windows-specific tests use [@EnabledOnOs] and will be skipped on other platforms.
|
||||
* They will run on Windows agents in TeamCity.
|
||||
*
|
||||
* @see IJPL-217109
|
||||
*/
|
||||
class WelcomeScreenNewFileDialogTest {
|
||||
|
||||
/**
|
||||
* Regression test for IJPL-217109: [DirectoryUtil.mkdirs] requires forward slashes.
|
||||
* Simulates user input with platform-native separators (backslashes on Windows).
|
||||
*/
|
||||
@Test
|
||||
fun `normalizeDirectoryPath uses forward slashes`() {
|
||||
val separator = FileSystems.getDefault().separator
|
||||
val userInput = listOf("Users", "test", "NewProject").joinToString(separator)
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(userInput)
|
||||
|
||||
assertFalse(normalized.contains("\\"),
|
||||
"Path for DirectoryUtil must not contain backslashes: $normalized")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `normalizeDirectoryPath resolves parent directory references`() {
|
||||
val pathWithDots = "home/user/../user/project"
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(pathWithDots)
|
||||
|
||||
assertFalse(normalized.contains(".."), "Normalized path should not contain '..': $normalized")
|
||||
assertEquals("home/user/project", normalized)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `normalizeDirectoryPath resolves current directory references`() {
|
||||
val pathWithDot = "home/./user/./project"
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(pathWithDot)
|
||||
|
||||
assertEquals("home/user/project", normalized)
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test for IJPL-217109: Windows backslash paths must be converted to forward slashes.
|
||||
* This test runs ONLY on Windows agents in TeamCity.
|
||||
*/
|
||||
@Test
|
||||
@EnabledOnOs(OS.WINDOWS)
|
||||
fun `normalizeDirectoryPath converts Windows backslashes to forward slashes`() {
|
||||
val windowsPath = "C:\\Users\\test\\project"
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(windowsPath)
|
||||
|
||||
assertEquals("C:/Users/test/project", normalized)
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Windows paths with mixed separators (common when copy-pasting paths).
|
||||
* This test runs ONLY on Windows agents in TeamCity.
|
||||
*/
|
||||
@Test
|
||||
@EnabledOnOs(OS.WINDOWS)
|
||||
fun `normalizeDirectoryPath handles Windows mixed separators`() {
|
||||
val mixedPath = "C:/Users\\test/project\\src"
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(mixedPath)
|
||||
|
||||
assertEquals("C:/Users/test/project/src", normalized)
|
||||
assertFalse(normalized.contains("\\"), "Path should not contain backslashes")
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that trailing backslashes are handled correctly on Windows.
|
||||
* This test runs ONLY on Windows agents in TeamCity.
|
||||
*/
|
||||
@Test
|
||||
@EnabledOnOs(OS.WINDOWS)
|
||||
fun `normalizeDirectoryPath handles Windows trailing separators`() {
|
||||
val pathWithTrailing = "C:\\Users\\test\\"
|
||||
|
||||
val normalized = WelcomeScreenNewFileDialog.normalizeDirectoryPath(pathWithTrailing)
|
||||
|
||||
assertEquals("C:/Users/test", normalized)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user