diff --git a/CHANGELOG.md b/CHANGELOG.md index 6489113b7..b5bbc45ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to the Zowe IntelliJ Plugin will be documented in this file. +## `1.1.2 (2024-01-22)` + +* Bugfix: Sync action does not work after file download ([bfb125d7](https://github.com/zowe/zowe-explorer-intellij/commit/bfb125d7)) +* Bugifx: "Skip This Files" doesn't work when uploading local file to PDS ([749b2d4b](https://github.com/zowe/zowe-explorer-intellij/commit/749b2d4b)) +* Bugifx: "Use new name" doesn't work for copying partitioned dataset to USS folder ([26d865be](https://github.com/zowe/zowe-explorer-intellij/commit/26d865be)) +* Bugifx: "Use new name" doesn't work for copying sequential dataset to partitioned dataset ([349c02e9](https://github.com/zowe/zowe-explorer-intellij/commit/349c02e9)) +* Bugfix: "Use new name" doesn't work when uploading local file to PDS ([26d865be](https://github.com/zowe/zowe-explorer-intellij/commit/26d865be)) +* Bugfix: Editing two members with the same name does not update the content for one of the members ([25606368](https://github.com/zowe/zowe-explorer-intellij/commit/25606368)) +* Bugfix: Topics handling ([25606368](https://github.com/zowe/zowe-explorer-intellij/commit/25606368)) +* Bugfix: Zowe config v2 handling ([fd79b908](https://github.com/zowe/zowe-explorer-intellij/commit/fd79b908)) +* Bugfix: JES Explorer bug when ABEND job is being displayed ([614aa6cf](https://github.com/zowe/zowe-explorer-intellij/commit/614aa6cf)) +* Bugfix: GitHub issue #167: Zowe explorer config is not converted ([b5eae7a2](https://github.com/zowe/zowe-explorer-intellij/commit/b5eae7a2)) + ## `1.1.1 (2023-11-23)` * Bugfix: Dataset color does not change when diff --git a/build.gradle.kts b/build.gradle.kts index f6a15eb84..5c317e2df 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,8 +33,8 @@ apply(from = "gradle/sonar.gradle") group = "org.zowe" version = "1.1.2-221" -val remoteRobotVersion = "0.11.19" -val okHttp3Version = "4.10.0" +val remoteRobotVersion = "0.11.21" +val okHttp3Version = "4.12.0" val kotestVersion = "5.6.2" repositories { @@ -71,7 +71,7 @@ dependencies { implementation("org.jgrapht:jgrapht-core:1.5.1") implementation("com.starxg:java-keytar:1.0.0") implementation("org.zowe.sdk:zowe-kotlin-sdk:0.4.0") - implementation("com.ibm.mq:com.ibm.mq.allclient:9.3.3.0") + implementation("com.ibm.mq:com.ibm.mq.allclient:9.3.4.1") testImplementation("io.mockk:mockk:1.13.5") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testImplementation("io.kotest:kotest-assertions-core:$kotestVersion") @@ -108,19 +108,16 @@ tasks {
Fixed bugs: """ ) } diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/AbstractPdsToUssFolderMover.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/AbstractPdsToUssFolderMover.kt index 7c5d9e107..443e40357 100644 --- a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/AbstractPdsToUssFolderMover.kt +++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/AbstractPdsToUssFolderMover.kt @@ -121,7 +121,8 @@ abstract class AbstractPdsToUssFolderMover(val dataOpsManager: DataOpsManager) : var throwable: Throwable? = null if (sourceFileFetchProvider.isCacheValid(sourceQuery)) { - val destinationPath = "${destinationAttributes.path}/${sourceAttributes.name}" + val newName = operation.newName ?: sourceAttributes.name + val destinationPath = "${destinationAttributes.path}/${newName}" if (operation.forceOverwriting) { log.info("Overwriting directory $destinationPath") @@ -137,7 +138,7 @@ abstract class AbstractPdsToUssFolderMover(val dataOpsManager: DataOpsManager) : val response = api(destConnectionConfig).createUssFile( authorizationToken = destConnectionConfig.authToken, - filePath = FilePath(destinationAttributes.path + "/" + sourceAttributes.name), + filePath = FilePath(destinationPath), body = CreateUssFile(FileType.DIR, destinationAttributes.fileMode ?: FileMode(7, 7, 7)) ).cancelByIndicator(progressIndicator).execute() diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileOrSequentialToUssDirMover.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileOrSequentialToUssDirMover.kt index 5ca848d3d..2ad583259 100644 --- a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileOrSequentialToUssDirMover.kt +++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileOrSequentialToUssDirMover.kt @@ -87,7 +87,9 @@ class CrossSystemMemberOrUssFileOrSequentialToUssDirMover(val dataOpsManager: Da contentSynchronizer.synchronizeWithRemote(syncProvider, progressIndicator) val contentMode = XIBMDataType(XIBMDataType.Type.BINARY) - val pathToFile = destAttributes.path + "/" + op.source.name + + val newName = op.newName ?: op.source.name + val pathToFile = destAttributes.path + "/" + newName progressIndicator.text = "Uploading file '$pathToFile'" val response = apiWithBytesConverter(destConnectionConfig).writeToUssFile( authorizationToken = destConnectionConfig.authToken, @@ -99,7 +101,7 @@ class CrossSystemMemberOrUssFileOrSequentialToUssDirMover(val dataOpsManager: Da }.execute() if (!response.isSuccessful) { - throw CallException(response, "Cannot upload data to ${op.destination.path}${op.source.name}") + throw CallException(response, "Cannot upload data to ${op.destination.path}${newName}") } else { setUssFileTag(op.source.charset.name(), pathToFile, destConnectionConfig) if (op.isMove) { diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileToPdsMover.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileToPdsMover.kt index bf85ceaf7..bb15d0d39 100644 --- a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileToPdsMover.kt +++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/CrossSystemMemberOrUssFileToPdsMover.kt @@ -84,7 +84,7 @@ class CrossSystemMemberOrUssFileToPdsMover(val dataOpsManager: DataOpsManager) : contentSynchronizer?.synchronizeWithRemote(syncProvider, progressIndicator) } - var memberName = sourceFile.name.filter { it.isLetterOrDigit() }.take(8) + var memberName = operation.newName ?: sourceFile.name.filter { it.isLetterOrDigit() }.take(8) if (memberName.isEmpty()) { memberName = "empty" } diff --git a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/SequentialToPdsMover.kt b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/SequentialToPdsMover.kt index e278f8bdf..3588587a8 100644 --- a/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/SequentialToPdsMover.kt +++ b/src/main/kotlin/org/zowe/explorer/dataops/operations/mover/SequentialToPdsMover.kt @@ -66,7 +66,7 @@ class SequentialToPdsMover(val dataOpsManager: DataOpsManager) : AbstractFileMov val destinationAttributes = operation.destinationAttributes as RemoteDatasetAttributes var memberName: String val dataset = (operation.sourceAttributes as RemoteDatasetAttributes).also { - memberName = it.name.split(".").last() + memberName = operation.newName ?: it.name.split(".").last() } val response = api( url = connectionConfig.url, @@ -83,7 +83,8 @@ class SequentialToPdsMover(val dataOpsManager: DataOpsManager) : AbstractFileMov memberName = memberName ).cancelByIndicator(progressIndicator).execute() - if (!response.isSuccessful && response.errorBody()?.string()?.contains("data set is empty") == true) { + // Proceed with deletion of source dataset in case of successful response or dataset was empty, throw exception otherwise + if (response.isSuccessful || response.errorBody()?.string()?.contains("data set is empty") == true) { if (operation.isMove) { val deleteResponse = api( url = connectionConfig.url, diff --git a/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt b/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt index 4d7af1539..408d6a048 100644 --- a/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt +++ b/src/main/kotlin/org/zowe/explorer/editor/FileEditorEventsListener.kt @@ -37,22 +37,23 @@ class FileEditorEventsListener : FileEditorManagerListener { * @param file the file that was opened. */ override fun fileOpened(source: FileEditorManager, file: VirtualFile) { - val editor = source.selectedTextEditor as? EditorEx + if (file is MFVirtualFile) { + val editor = source.selectedTextEditor as? EditorEx - // TODO: remove in v1.*.*-223 and greater - if (editor != null) { - editor.addFocusListener(focusListener) - val isDumbMode = ActionUtil.isDumbMode(editor.project) - if (isDumbMode) { - editor.document.setReadOnly(true) - editor.isViewer = true + // TODO: remove in v1.*.*-223 and greater + if (editor != null) { + editor.addFocusListener(focusListener) + val isDumbMode = ActionUtil.isDumbMode(editor.project) + if (isDumbMode) { + editor.document.setReadOnly(true) + editor.isViewer = true + } } - super.fileOpened(source, file) - } - // TODO: use in v1.*.*-223 and greater - //editor?.addFocusListener(focusListener) - //super.fileOpened(source, file) + // TODO: use in v1.*.*-223 and greater + //editor?.addFocusListener(focusListener) + } + super.fileOpened(source, file) } } @@ -70,8 +71,9 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before { * @param file the file to be checked and synchronized */ override fun beforeFileClosed(source: FileEditorManager, file: VirtualFile) { + val project = source.project val configService = service() - val syncProvider = DocumentedSyncProvider(file, SaveStrategy.default(source.project)) + val syncProvider = DocumentedSyncProvider(file, SaveStrategy.default(project)) val attributes = dataOpsManager.tryToGetAttributes(file) if (file is MFVirtualFile && file.isWritable && attributes != null) { val contentSynchronizer = service().getContentSynchronizer(file) @@ -79,15 +81,15 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before { val previousContent = contentSynchronizer?.successfulContentStorage(syncProvider) val needToUpload = contentSynchronizer?.isFileUploadNeeded(syncProvider) == true if (!(currentContent contentEquals previousContent) && needToUpload) { - val incompatibleEncoding = !checkEncodingCompatibility(file, source.project) + val incompatibleEncoding = !checkEncodingCompatibility(file, project) if (!configService.isAutoSyncEnabled) { - if (showSyncOnCloseDialog(file.name, source.project)) { + if (showSyncOnCloseDialog(file.name, project)) { if (incompatibleEncoding && !showSaveAnywayDialog(file.charset)) { return } runModalTask( title = "Syncing ${file.name}", - project = source.project, + project = project, cancellable = true ) { runWriteActionInEdtAndWait { @@ -101,7 +103,7 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before { return } runWriteActionInEdtAndWait { syncProvider.saveDocument() } - sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, DataOpsManager.instance.componentManager).sync(file) + sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, project).sync(file) } } } @@ -114,7 +116,9 @@ class FileEditorBeforeEventsListener : FileEditorManagerListener.Before { * @param file the file that opens */ override fun beforeFileOpened(source: FileEditorManager, file: VirtualFile) { - file.putUserData() + if (file is MFVirtualFile) { + putUserDataInFile(file) + } super.beforeFileOpened(source, file) } } diff --git a/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt b/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt index c7a6b1e52..d96da0595 100644 --- a/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt +++ b/src/main/kotlin/org/zowe/explorer/editor/FileEditorFocusListener.kt @@ -62,7 +62,7 @@ class FileEditorFocusListener: FocusChangeListener { return } runWriteActionInEdtAndWait { syncProvider.saveDocument() } - sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, DataOpsManager.instance.componentManager).sync(file) + sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, project).sync(file) } } } diff --git a/src/main/kotlin/org/zowe/explorer/editor/utils.kt b/src/main/kotlin/org/zowe/explorer/editor/utils.kt index d91d140a7..7d1d29023 100644 --- a/src/main/kotlin/org/zowe/explorer/editor/utils.kt +++ b/src/main/kotlin/org/zowe/explorer/editor/utils.kt @@ -45,15 +45,11 @@ val MF_VIRTUAL_FILE = Key.create(MF_VIRTUAL_FILE_KEY_NAME) val USS_VIRTUAL_FILE = Key.create(USS_VIRTUAL_FILE_KEY_NAME) /** Puts user data in file. */ -fun VirtualFile.putUserData() { - val file = this - if (file is MFVirtualFile) { - file.putUserData(MF_VIRTUAL_FILE, true) - val attributes = DataOpsManager.instance.tryToGetAttributes(file) - if (attributes is RemoteUssAttributes) { - file.putUserData(USS_VIRTUAL_FILE, true) - } - } +fun putUserDataInFile(file: MFVirtualFile) { + file.putUserData(MF_VIRTUAL_FILE, true) + DataOpsManager.instance.tryToGetAttributes(file) + ?.takeIf { it is RemoteUssAttributes } + ?.let { file.putUserData(USS_VIRTUAL_FILE, true) } } /** diff --git a/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobAction.kt b/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobAction.kt index 14715e046..a6fd0fc67 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobAction.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobAction.kt @@ -69,7 +69,7 @@ class SubmitJobAction : AnAction() { ), it ).also { result -> e.project?.let { project -> - sendTopic(JOB_ADDED_TOPIC).submitted(project, requestData.second, submitFilePath, result) + sendTopic(JOB_ADDED_TOPIC, project).submitted(project, requestData.second, submitFilePath, result) } } }.onSuccess { diff --git a/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobToolbarAction.kt b/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobToolbarAction.kt index bd3c2d7ce..8cb882b7c 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobToolbarAction.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/actions/SubmitJobToolbarAction.kt @@ -54,7 +54,7 @@ class SubmitJobToolbarAction: AnAction() { progressIndicator = it ).also { result -> e.project?.let { project -> - sendTopic(JOB_ADDED_TOPIC).submitted(project, connectionConfig, file.parent.path, result) + sendTopic(JOB_ADDED_TOPIC, project).submitted(project, connectionConfig, file.parent.path, result) } } }.onFailure { diff --git a/src/main/kotlin/org/zowe/explorer/explorer/actions/ViewJobAction.kt b/src/main/kotlin/org/zowe/explorer/explorer/actions/ViewJobAction.kt index 548be43a0..0fe43d4ca 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/actions/ViewJobAction.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/actions/ViewJobAction.kt @@ -37,7 +37,7 @@ class ViewJobAction : AnAction() { dataOpsManager.tryToGetAttributes(virtualFile)?.clone() as RemoteJobAttributes val project = e.project ?: return - sendTopic(JOB_ADDED_TOPIC).viewed( + sendTopic(JOB_ADDED_TOPIC, project).viewed( project, attributes.requesters[0].connectionConfig, virtualFile.filenameInternal, diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt index dd0cd9c84..d32eaa093 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProvider.kt @@ -426,19 +426,19 @@ class ExplorerPasteProvider : PasteProvider { val listOfAllConflicts = pasteDestinations .mapNotNull { destFile -> + val destAttributes = dataOpsManager.tryToGetAttributes(destFile) destFile.children ?.map conflicts@{ destChild -> val filteredSourceFiles = sourceFiles.filter { source -> val sourceAttributes = dataOpsManager.tryToGetAttributes(source) - val destAttributes = dataOpsManager.tryToGetAttributes(destChild) if ( - destAttributes is RemoteMemberAttributes && + destAttributes is RemoteDatasetAttributes && (sourceAttributes is RemoteUssAttributes || source is VirtualFileImpl) ) { val memberName = source.name.filter { it.isLetterOrDigit() }.take(8).uppercase() if (memberName.isNotEmpty()) memberName == destChild.name else "EMPTY" == destChild.name } else if ( - destAttributes is RemoteMemberAttributes && + destAttributes is RemoteDatasetAttributes && sourceAttributes is RemoteDatasetAttributes ) { sourceAttributes.name.split(".").last() == destChild.name @@ -550,12 +550,17 @@ class ExplorerPasteProvider : PasteProvider { allConflicts.forEach { conflict -> var copyIndex = 1 val sourceName = conflict.second.name + val isSourceDirectory = conflict.second.isDirectory var newName: String val destAttributes = dataOpsManager.tryToGetAttributes(conflict.first) - + val sourceAttributes = dataOpsManager.tryToGetAttributes(conflict.second) do { - newName = if (destAttributes is RemoteDatasetAttributes) { + newName = if (destAttributes is RemoteDatasetAttributes && sourceAttributes is RemoteDatasetAttributes) { + "${sourceAttributes.name.split(".").last().take(7)}$copyIndex" + } else if (destAttributes is RemoteDatasetAttributes) { if (sourceName.length >= 8) "${sourceName.take(7)}$copyIndex" else "$sourceName$copyIndex" + } else if (isSourceDirectory || sourceAttributes is RemoteDatasetAttributes) { + "${sourceName}_(${copyIndex})" } else { val extension = if (sourceName.contains(".")) sourceName.substringAfterLast(".") else null val newNameWithoutExtension = "${sourceName.substringBeforeLast(".")}_(${copyIndex})" diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt index 90cc5c6bf..f44032bc9 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/ExplorerTreeView.kt @@ -310,6 +310,7 @@ abstract class ExplorerTreeView() if (dataOpsManager.isSyncSupported(file)) { diff --git a/src/main/kotlin/org/zowe/explorer/explorer/ui/JobNode.kt b/src/main/kotlin/org/zowe/explorer/explorer/ui/JobNode.kt index 92c967d76..4f2384d63 100644 --- a/src/main/kotlin/org/zowe/explorer/explorer/ui/JobNode.kt +++ b/src/main/kotlin/org/zowe/explorer/explorer/ui/JobNode.kt @@ -168,8 +168,8 @@ class JobNode( */ private fun isErrorReturnCode(returnCode : String?) : Boolean { if (returnCode != null) { - return if (!returnCode.startsWith("CANCELED")) { - val numberedRC = returnCode.split(" ")[1].toIntOrNull() + return if (!returnCode.contains(Regex("ERR|ABEND|CANCEL|FAIL"))) { + val numberedRC = returnCode.split(" ").getOrNull(1)?.toIntOrNull() if (numberedRC != null) { numberedRC > 0 } else { diff --git a/src/main/kotlin/org/zowe/explorer/ui/build/jobs/JobsWindowFactory.kt b/src/main/kotlin/org/zowe/explorer/ui/build/jobs/JobsWindowFactory.kt index c8e0efb34..82d647e59 100644 --- a/src/main/kotlin/org/zowe/explorer/ui/build/jobs/JobsWindowFactory.kt +++ b/src/main/kotlin/org/zowe/explorer/ui/build/jobs/JobsWindowFactory.kt @@ -95,8 +95,9 @@ class JobsWindowFactory: ToolWindowFactory { override fun init(toolWindow: ToolWindow) { subscribe( - JOB_ADDED_TOPIC, - object: JobHandler { + project = toolWindow.project, + topic = JOB_ADDED_TOPIC, + handler = object: JobHandler { override fun submitted(project: Project, connectionConfig: ConnectionConfig, mfFilePath: String, jobRequest: SubmitJobRequest) { addJobBuildContentTab(project, toolWindow, connectionConfig, mfFilePath, jobRequest.jobid, jobRequest.jobname) } diff --git a/src/test/kotlin/org/zowe/explorer/editor/EditorTestSpec.kt b/src/test/kotlin/org/zowe/explorer/editor/EditorTestSpec.kt index d8f6e6821..b3edf216c 100644 --- a/src/test/kotlin/org/zowe/explorer/editor/EditorTestSpec.kt +++ b/src/test/kotlin/org/zowe/explorer/editor/EditorTestSpec.kt @@ -131,9 +131,9 @@ class EditorTestSpec : WithApplicationShouldSpec({ every { virtualFileMock.charset } returns charsetMock var isSynced = false - val sendTopicRef: (Topic, ComponentManager) -> AutoSyncFileListener = ::sendTopic + val sendTopicRef: (Topic, Project) -> AutoSyncFileListener = ::sendTopic mockkStatic(sendTopicRef as KFunction<*>) - every { sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, any()) } answers { + every { sendTopic(AutoSyncFileListener.AUTO_SYNC_FILE, any()) } answers { isSynced = true val autoSyncFileListenerMock = mockk() every { autoSyncFileListenerMock.sync(virtualFileMock) } returns Unit diff --git a/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt b/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt index 5db773819..9f2b1c50b 100644 --- a/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt +++ b/src/test/kotlin/org/zowe/explorer/explorer/ui/ExplorerPasteProviderTestSpec.kt @@ -1182,10 +1182,14 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({ val copyPasteNodeDataList = mutableListOf>() val destinationChildFiles = mutableListOf() + val mockedTargetFile = mockk() + val targetAttributes = mockk() + afterEach { copyPasteNodeDataList.clear() destinationChildFiles.clear() // clearMocks(dataOpsManagerService.testInstance) + every { dataOpsManagerService.testInstance.tryToGetAttributes(mockedTargetFile) } returns targetAttributes } // prepare base mocks @@ -1210,10 +1214,9 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({ } // target to paste - val mockedTargetFile = mockk() + val mockedStructureTreeModelNodeTarget = mockk() val mockedNodeTarget = mockk() - val targetAttributes = mockk() every { mockedTargetFile.name } returns "test_folder" every { targetAttributes.isDirectory } returns true every { mockedTargetFile.children } answers { destinationChildFiles.toTypedArray() } @@ -1231,15 +1234,22 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({ fileName: String, isPastePossible: Boolean = false, isDirectory: Boolean = false, - parent: MFVirtualFile? = null + parent: MFVirtualFile? = null, + sourceAttributes: FileAttributes? = null ): MFVirtualFile { - val mockedSourceAttributes = mockk() val mockedSourceFile = mockk() every { mockedSourceFile.name } returns fileName every { mockedSourceFile.isDirectory } returns isDirectory every { mockedSourceFile.parent } returns parent - every { mockedSourceAttributes.isPastePossible } returns isPastePossible - every { mockedSourceAttributes.isDirectory } returns isDirectory + + val mockedSourceAttributes = if (sourceAttributes != null) { + sourceAttributes + } else { + val attributes = mockk() + every { attributes.isPastePossible } returns isPastePossible + every { attributes.isDirectory } returns isDirectory + attributes + } val mockedSourceNodeData = mockk>() val mockedSourceNode = mockk() @@ -1448,6 +1458,118 @@ class ExplorerPasteProviderTestSpec : WithApplicationShouldSpec({ overwriteSelected shouldBe true } } + should("Use new name for dataset or directory") { + isPastePerformed = false + val datasetAttributes = mockk() + every { datasetAttributes.isPastePossible } returns false + every { datasetAttributes.isDirectory } returns false + + addMockedSourceFile("directory.test", isDirectory=true) + addMockedSourceFile("DATASET.TEST", sourceAttributes = datasetAttributes) + addMockedTargetChildFile("directory.test", true) + addMockedTargetChildFile("DATASET.TEST") + mockkStatic(Messages::class) + var decideOptionSelected = false + + every { + Messages.showYesNoDialog( + any() as Project?, any() as String, any() as String, any() as String, any() as String, any() as Icon? + ) + } returns Messages.YES + every { + Messages.showDialog( + any() as Project?, + any() as String, + any() as String, + any() as Array, + 0, + any() as Icon?, + null + ) + } answers { + if (!decideOptionSelected) { + decideOptionSelected = true + 2 + } else { + 2 + } + } + + var dirNewName: String? = null + var datasetNewName: String? = null + every { + dataOpsManagerService.testInstance.performOperation(any() as MoveCopyOperation, any() as ProgressIndicator) + } answers { + val op = firstArg() + if (op.source.name == "directory.test") { + dirNewName = op.newName + } + if (op.source.name == "DATASET.TEST") { + datasetNewName = op.newName + } + } + + mockedExplorerPasteProvider.performPaste(mockedDataContext) + + assertSoftly { + dirNewName shouldBe "directory.test_(1)" + datasetNewName shouldBe "DATASET.TEST_(1)" + } + } + should("Use new name for sequential dataset (moving to pds)") { + + isPastePerformed = false + val datasetAttributes = mockk() + every { datasetAttributes.name } returns "DATASET.TEST" + every { datasetAttributes.isDirectory } returns false + every { datasetAttributes.isPastePossible } returns false + val targetAttributesPDS = mockk() + + addMockedSourceFile("DATASET.TEST", sourceAttributes = datasetAttributes) + addMockedTargetChildFile("TEST") + every { dataOpsManagerService.testInstance.tryToGetAttributes(mockedTargetFile) } returns targetAttributesPDS + + mockkStatic(Messages::class) + var decideOptionSelected = false + + every { + Messages.showYesNoDialog( + any() as Project?, any() as String, any() as String, any() as String, any() as String, any() as Icon? + ) + } returns Messages.YES + every { + Messages.showDialog( + any() as Project?, + any() as String, + any() as String, + any() as Array, + 0, + any() as Icon?, + null + ) + } answers { + if (!decideOptionSelected) { + decideOptionSelected = true + 2 + } else { + 2 + } + } + + var memberNewName: String? = null + every { + dataOpsManagerService.testInstance.performOperation(any() as MoveCopyOperation, any() as ProgressIndicator) + } answers { + val op = firstArg() + memberNewName = op.newName + } + + mockedExplorerPasteProvider.performPaste(mockedDataContext) + + assertSoftly { + memberNewName shouldBe "TEST1" + } + } should("Resolve conflicts between directory and file") { isPastePerformed = false addMockedSourceFile("dir1")