diff --git a/.gitignore b/.gitignore
index b63da45..cc5d98b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ build/
out/
!**/src/main/**/out/
!**/src/test/**/out/
+.intellijPlatform
### Eclipse ###
.apt_generated
@@ -39,4 +40,4 @@ bin/
.vscode/
### Mac OS ###
-.DS_Store
\ No newline at end of file
+.DS_Store
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index ae3f30a..d310da5 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d450a79..bce7180 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,10 @@
+
+
+
+
+
+
diff --git a/README.md b/README.md
index df10c53..dc26f47 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,43 @@ Provides:
- syntax highlighting support using TextMate bundle from [eclipse-che4z/che-che4z-lsp-for-cobol](https://github.com/eclipse-che4z/che-che4z-lsp-for-cobol)
- code actions using LSP technology with client from [redhat-developer/lsp4ij](https://github.com/redhat-developer/lsp4ij) and server from [eclipse-che4z/che-che4z-lsp-for-cobol](https://github.com/eclipse-che4z/che-che4z-lsp-for-cobol)
+## Supported features
+
+### Syntax Highlighting and Coloring
+
+The feature allows to inspect COBOL sources with highlighted instructions, recognized as COBOL language elements, colored respective to their type.
+
+### Syntax and Semantic Code Check
+
+The plug-in walks through the content of COBOL source files and checks it for mistakes and errors, highlighting it respectively with suggestions on how to fix them.
+
+### Code Autocompletion
+
+The feature provides a functionality to autocomplete instructions, suggesting the possible options to complete the words being typed (works for .cob/.cbl files, not for copybooks).
+
+### Copybooks Recognition
+
+The plug-in recognizes local copybooks, used in COBOL sources. The .cpy/.copy files content is highlighted as COBOL source code.
+To use local copybooks:
+1. Create **.vscode** folder in your opened workspace
+2. Create **settings.json** in the **.vscode** folder
+3. Enter relative or absolute paths of the folders, where copybooks are placed
+
+Example of the **settings.json** content:
+```json5
+{
+ //...
+ "cobol-lsp.cpy-manager.paths-local": [
+ ".copybooks/zowe-profile-1/DATA.SET.PATH1",
+ ".copybooks/some-path",
+ "/some/absolute/path"
+ ],
+ //...
+}
+```
+
+The plug-in will search through the paths to find related copybook files. Using "Go To Definition" functionality will open the found copybook.
+
## Prerequisites
- Java v17
diff --git a/build.gradle.kts b/build.gradle.kts
index 7169a61..8c16fdd 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -12,71 +12,89 @@
* Zowe Community
*/
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.jetbrains.intellij.platform.gradle.TestFrameworkType
+
+//!IMPORTANT!: to refer "libs", use ./gradle/libs.versions.toml
fun properties(key: String) = providers.gradleProperty(key)
plugins {
- id("java")
- id("org.jetbrains.kotlin.jvm") version "1.9.21"
- id("org.jetbrains.intellij") version "1.16.1"
- id("org.jetbrains.kotlinx.kover") version "0.8.1"
+ alias(libs.plugins.gradle) // IntelliJ Platform Gradle Plugin
+ alias(libs.plugins.kotlinJvm)
+ alias(libs.plugins.kover)
+ java
}
group = properties("pluginGroup").get()
version = properties("pluginVersion").get()
-val kotestVersion = "5.9.1"
-val mockkVersion = "1.13.12"
-val junitVersion = "1.10.3"
+val lsp4ijVersion = "0.7.0"
repositories {
mavenCentral()
+ intellijPlatform {
+ defaultRepositories()
+ jetbrainsRuntime()
+ }
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+kotlin {
+ jvmToolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.toString()))
+ }
}
// Configure Gradle IntelliJ Plugin
-// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
-intellij {
- version.set(properties("platformVersion").get())
-// pluginsRepositories {
-// custom("https://plugins.jetbrains.com/plugins/nightly/23257")
-// }
- plugins.set(listOf("org.jetbrains.plugins.textmate", "com.redhat.devtools.lsp4ij:0.4.0"))
+// Read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin.html
+intellijPlatform {
+ pluginConfiguration {
+ version = properties("platformVersion").get()
+ ideaVersion {
+ sinceBuild = properties("pluginSinceBuild").get()
+ untilBuild = provider { null }
+ }
+ }
}
dependencies {
+ // ===== Runtime env setup ===
+ // IntelliJ
+ intellijPlatform {
+ intellijIdeaCommunity(properties("platformVersion").get(), useInstaller = false)
+ jetbrainsRuntime()
+ instrumentationTools()
+ bundledPlugin("org.jetbrains.plugins.textmate")
+//// pluginsRepositories {
+//// custom("https://plugins.jetbrains.com/plugins/nightly/23257")
+//// }
+ plugin("com.redhat.devtools.lsp4ij:$lsp4ijVersion")
+ testFramework(TestFrameworkType.Plugin.Java)
+ }
+ // Gson
+ implementation(libs.gson)
// ===== Test env setup =====
// Kotest
- testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
- testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
+ testImplementation(libs.kotest.runner.junit5)
+ testImplementation(libs.kotest.assertions.core)
// MockK
- testImplementation("io.mockk:mockk:$mockkVersion")
+ testImplementation(libs.mockk)
// JUnit Platform (needed for Kotest)
- testImplementation("org.junit.platform:junit-platform-launcher:$junitVersion")
+ testImplementation(libs.junit.platform.launcher)
// ==========================
}
tasks {
- // Set the JVM compatibility versions
- withType {
- sourceCompatibility = JavaVersion.VERSION_17.toString()
- targetCompatibility = JavaVersion.VERSION_17.toString()
- }
- withType {
- kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
- }
-
- patchPluginXml {
- version.set(properties("pluginVersion").get())
- sinceBuild.set(properties("pluginSinceBuild").get())
- untilBuild.set(properties("pluginUntilBuild").get())
- }
-
test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
}
finalizedBy("koverHtmlReport")
+// testLogging.showStandardStreams = true
}
}
diff --git a/gradle.properties b/gradle.properties
index a1307ba..a2206b0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,3 +17,4 @@ pluginGroup = org.zowe
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 232
pluginUntilBuild =
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..14a9d35
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,26 @@
+[versions]
+# libraries
+gson = "2.11.0"
+kotest = "5.9.1"
+mockk = "1.13.13"
+junit = "1.11.3"
+
+# plugins
+gradle = "2.1.0"
+kotlinJvm = "1.9.22"
+kover = "0.8.3"
+
+[libraries]
+# build deps
+gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
+
+# test deps
+kotest-runner-junit5 = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotest" }
+kotest-assertions-core = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotest" }
+mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
+junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version = "junit" }
+
+[plugins]
+gradle = { id = "org.jetbrains.intellij.platform", version.ref = "gradle" }
+kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlinJvm" }
+kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 249e583..d64cd49 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a595206..79eb9d0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c787..1aa94a4 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd3..93e3f59 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/src/main/kotlin/org/zowe/cobol/CobolProjectManagerListener.kt b/src/main/kotlin/org/zowe/cobol/CobolProjectManagerListener.kt
index f8ffba1..1a1c459 100644
--- a/src/main/kotlin/org/zowe/cobol/CobolProjectManagerListener.kt
+++ b/src/main/kotlin/org/zowe/cobol/CobolProjectManagerListener.kt
@@ -31,7 +31,7 @@ class CobolProjectManagerListener : ProjectManagerListener {
*/
@OptIn(InitializationOnly::class)
override fun projectClosing(project: Project) {
- val lsStateService = LanguageSupportStateService.instance
+ val lsStateService = LanguageSupportStateService.getService()
val pluginState = lsStateService.getPluginState(project) { CobolPluginState(project) }
if (isLastProjectClosing() && (pluginState.isLSPClientReady() || pluginState.isLSPServerConnectionReady())) {
diff --git a/src/main/kotlin/org/zowe/cobol/Sections.kt b/src/main/kotlin/org/zowe/cobol/Sections.kt
new file mode 100644
index 0000000..6de39a0
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/Sections.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol
+
+/**
+ * Various config section options that could be found across configuration files
+ * @property section the section string representation
+ */
+enum class Sections(val section: String) {
+ DIALECTS_SECTION("cobol-lsp.dialects"),
+ DIALECT_REGISTRY("cobol-lsp.dialect.registry"),
+ DIALECT_LIBS("cobol-lsp.dialect.libs"),
+ CPY_SECTION("cobol-lsp.cpy-manager"),
+ CPY_LOCAL_PATH("cobol-lsp.cpy-manager.paths-local"),
+ CPY_EXTENSIONS("cobol-lsp.cpy-manager.copybook-extensions"),
+ CPY_FILE_ENCODING("cobol-lsp.cpy-manager.copybook-file-encoding"),
+ SQL_BACKEND("cobol-lsp.target-sql-backend"),
+ COMPILER_OPTIONS("cobol-lsp.compiler.options"),
+ LOGGIN_LEVEL_ROOT("cobol-lsp.logging.level.root"),
+ LOCALE("cobol-lsp.locale"),
+ COBOL_PROGRAM_LAYOUT("cobol-lsp.cobol.program.layout"),
+ SUBROUTINE_LOCAL_PATH("cobol-lsp.subroutine-manager.paths-local"),
+ CICS_TRANSLATOR("cobol-lsp.cics.translator"),
+ UNRECOGNIZED("unrecognized-section");
+
+ companion object {
+ operator fun invoke(section: String): Sections {
+ return entries.find { it.section == section } ?: UNRECOGNIZED
+ }
+ }
+
+ override fun toString(): String {
+ return section
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/zowe/cobol/VSCodeSettingsAdapterService.kt b/src/main/kotlin/org/zowe/cobol/VSCodeSettingsAdapterService.kt
new file mode 100644
index 0000000..00ca16a
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/VSCodeSettingsAdapterService.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol
+
+import com.google.gson.JsonParser
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.FileReader
+import java.nio.file.Path
+
+/** VS Code settings adapter service. Needed to recognize configs in .vscode folder */
+@Service
+class VSCodeSettingsAdapterService {
+
+ companion object {
+ fun getService(): VSCodeSettingsAdapterService = service()
+ }
+
+ /**
+ * Read the .vscode/settings.json file section
+ * @param workspaceFolder the workspace folder path to search for the file in
+ * @param readBlock the function to handle the read section
+ * @return the result of the read section handling or error if file is not found
+ */
+ private fun readConfigFileSection(workspaceFolder: Path, readBlock: (FileReader) -> T?): T? {
+ return try {
+ val settingsPath = workspaceFolder.resolve(".vscode").resolve("settings.json")
+ val settingsFile = File(settingsPath.toUri())
+ FileReader(settingsFile).use(readBlock)
+ } catch (e: FileNotFoundException) {
+ // TODO: logger
+// println("settings.json file not found")
+ null
+ }
+ }
+
+ /**
+ * Read the .vscode/settings.json file section and expect to return a list of strings as a result
+ * @param workspaceFolder the workspace folder path to search for the file in
+ * @param section the section to read
+ * @return the list of strings, read from the section, or empty list on failure or if there are no items
+ */
+ fun getListOfStringsConfiguration(workspaceFolder: Path, section: Sections): List {
+ return readConfigFileSection(workspaceFolder) { settingsJsonReader ->
+ val settingsJsonElement = JsonParser.parseReader(settingsJsonReader)
+ if (settingsJsonElement.isJsonObject) {
+ val settingsJsonObject = settingsJsonElement.asJsonObject
+ val settingsDialectJsonArray = settingsJsonObject.get(section.toString())?.asJsonArray
+ settingsDialectJsonArray?.map { it.asString } ?: listOf()
+ } else {
+ listOf()
+ }
+ } ?: listOf()
+ }
+
+}
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionService.kt b/src/main/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionService.kt
new file mode 100644
index 0000000..5509491
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionService.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import com.google.gson.*
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import org.eclipse.lsp4j.ConfigurationItem
+import org.zowe.cobol.findFilesInPath
+import java.io.File
+import java.lang.reflect.Type
+import java.net.URI
+import java.nio.file.*
+
+private const val PROCESSOR_GROUP_FOLDER = ".cobolplugin"
+private const val PROCESSOR_GROUP_PGM = "pgm_conf.json"
+private const val PROCESSOR_GROUP_PROC = "proc_grps.json"
+private val COBOL_EXTENSTIONS = listOf(".CBL", ".COB", ".COBOL")
+
+/** Service to handle COBOL-related configs */
+@Service
+class CobolConfigsRecognitionService {
+
+ companion object {
+ fun getService(): CobolConfigsRecognitionService = service()
+ }
+
+ /**
+ * Preprocessor description item class
+ * @property name the name of the preprocessor
+ * @property libs the optional preprocessor libs
+ */
+ private data class PreprocessorItem(val name: String, val libs: List = emptyList())
+
+ /**
+ * Processor group class to represent processor groups
+ * @property name the name of the processor group
+ * @property libs the optional libs to be used
+ * @property preprocessor the optional preprocessors list to be used with the processor group
+ */
+ private data class ProcessorGroup(
+ val name: String,
+ val libs: List = emptyList(),
+ val preprocessor: List = emptyList()
+ )
+
+ /**
+ * Processor groups container class
+ * @property pgroups the processor groups list
+ */
+ private data class PGroupContainer(val pgroups: List)
+
+ /** Class to provide a deserialization mechanism for processor groups */
+ private class ProcessorGroupDeserializer : JsonDeserializer {
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ProcessorGroup {
+ val jsonObject = json.asJsonObject
+
+ val name = jsonObject.get("name").asString
+ val libs = jsonObject.getAsJsonArray("libs")?.map { it.asString } ?: emptyList()
+
+ val preprocessor = when {
+ jsonObject.has("preprocessor") -> {
+ val preprocessorElement = jsonObject.get("preprocessor")
+ if (preprocessorElement.isJsonArray) {
+ preprocessorElement.asJsonArray.map { parsePreprocessorItem(it) }
+ } else {
+ listOf(parsePreprocessorItem(preprocessorElement))
+ }
+ }
+ else -> emptyList()
+ }
+
+ return ProcessorGroup(name, libs, preprocessor)
+ }
+
+ /**
+ * Parse preprocessor item from JSON. It is either a string or an object
+ * @param element the [JsonElement] to parse preprocessor item from
+ * @return parsed and formed [PreprocessorItem] instance
+ */
+ private fun parsePreprocessorItem(element: JsonElement): PreprocessorItem {
+ return if (element.isJsonPrimitive && element.asJsonPrimitive.isString) {
+ PreprocessorItem(name = element.asString)
+ } else {
+ val jsonObject = element.asJsonObject
+ val name = jsonObject.get("name").asString
+ val libs = jsonObject.getAsJsonArray("libs")?.map { it.asString } ?: emptyList()
+ PreprocessorItem(name = name, libs = libs)
+ }
+ }
+ }
+
+ /**
+ * Program config item class to represent a single COBOL program configuration
+ * @param program a name or a wildcard of a file to be considered as the main program (open code)
+ * @param pgroup name of a processor group as defined in proc_grps.json
+ */
+ private data class ProgramItem(val program: String, val pgroup: String)
+
+ /**
+ * Programs config class to represent program configuration options for the COBOL programs
+ * @param pgms a list of main programs
+ */
+ private data class ProgramContainer(val pgms: List)
+
+ // TODO: recheck functionality correctness
+ /**
+ * Match provided processor group path from the deserialized JSON with the actual document path
+ * @param pgmCfg the [ProgramContainer] config item to find the proc group path that matches with the document path
+ * @param documentPathStr the document path as a string
+ * @param workspaceFolder the workspace folder to find the paths match in
+ * @return the matched processor group name or null
+ */
+ private fun matchProcessorGroup(pgmCfg: ProgramContainer, documentPathStr: String, workspaceFolder: Path): String? {
+ val documentPath = Paths.get(documentPathStr)
+ val relativeDocPath = workspaceFolder.relativize(documentPath)
+
+ val candidates = mutableListOf()
+
+ for ((program, pgroup) in pgmCfg.pgms) {
+ val programPath = try {
+ Paths.get(program)
+ } catch (e: InvalidPathException) {
+ null
+ }
+ // exact match
+ if (programPath != null && programPath.isAbsolute) {
+ if (
+ programPath == documentPath
+ || programPath.toString().uppercase() == documentPath.toString().uppercase()
+ ) {
+ return pgroup
+ }
+ } else {
+ if (relativeDocPath == programPath) {
+ candidates.add(pgroup)
+ }
+ }
+
+ val relativeDocPathIgnoreCase = Paths.get(relativeDocPath.toString().uppercase())
+ val matcher = FileSystems.getDefault().getPathMatcher("glob:${program.uppercase()}")
+ if (matcher.matches(relativeDocPathIgnoreCase)) {
+ candidates.add(pgroup)
+ }
+ }
+
+ return candidates.getOrNull(0)
+ }
+
+ /**
+ * Load processors config for the related document
+ * @param workspaceFolder the workspace folder to load configs in
+ * @param documentUri the document to find config for
+ * @return the [ProcessorGroup] config or null
+ */
+ private fun loadProcessorsConfig(workspaceFolder: Path, documentUri: URI): ProcessorGroup? {
+ val documentPath = Paths.get(documentUri).toString()
+ val cfgPath = workspaceFolder.resolve(PROCESSOR_GROUP_FOLDER)
+ val procCfgPath = cfgPath.resolve(PROCESSOR_GROUP_PROC)
+ val pgmCfgPath = cfgPath.resolve(PROCESSOR_GROUP_PGM)
+ if (!Files.exists(pgmCfgPath) || !Files.exists(procCfgPath)) {
+ return null
+ }
+ val procCfgFile = File(procCfgPath.toUri()).readText()
+ val procCfgGson = GsonBuilder()
+ .registerTypeAdapter(ProcessorGroup::class.java, ProcessorGroupDeserializer())
+ .create()
+ val procCfg = procCfgGson.fromJson(procCfgFile, PGroupContainer::class.java)
+
+ val pgmCfgFile = File(pgmCfgPath.toUri()).readText()
+ val pgmCfgGson = Gson()
+ val pgmCfg = pgmCfgGson.fromJson(pgmCfgFile, ProgramContainer::class.java)
+
+ val pgroup = matchProcessorGroup(pgmCfg, documentPath, workspaceFolder)
+
+ val result = procCfg.pgroups.find { p -> pgroup == p.name }
+ return result
+ }
+
+ // TODO: doc
+ fun loadProcessorGroupDialectConfig(
+ workspaceFolder: Path,
+ item: ConfigurationItem,
+ configObject: List
+ ): List {
+ return try {
+ // "SQL" is not a real dialect, we will use it only to set up sql backend for now
+ loadProcessorsConfig(workspaceFolder, URI(item.scopeUri))
+ ?.preprocessor
+ ?.map { (name, _) -> name }
+ ?.filter { name -> name != "SQL" }
+ ?.ifEmpty { configObject }
+ ?: configObject
+ } catch (e: Exception) {
+ println(e)
+ configObject
+ }
+ }
+
+ /**
+ * Load copybook paths from the related to the [item] processor config
+ * @param workspaceFolder the workspace folder to find and load config in
+ * @param item the configuration item to find the related processor configs for
+ * @param configObject the config object to return as a default configuration if no specific configs found
+ * @return the related copybook paths
+ */
+ fun loadProcessorGroupCopybookPathsConfig(
+ workspaceFolder: Path,
+ item: ConfigurationItem,
+ configObject: List
+ ): List {
+// val copybookPaths = loadProcessorsConfig(workspaceFolder, URI(item.scopeUri))
+// ?.libs
+// ?.ifEmpty { configObject }
+// ?: configObject
+ val copybookPaths = configObject
+ return findFilesInPath(copybookPaths, workspaceFolder)
+ }
+
+ // TODO: doc
+ // TODO: implement
+// fun resolveSubroutineURI(project: Project, name: String): String {
+// val folders = VSCodeSettingsAdapterService
+// .getService(project)
+// .getListOfStringsConfiguration(Sections.SUBROUTINE_LOCAL_PATH)
+// return searchCopybookInWorkspace(project, name, folders, COBOL_EXTENSTIONS)
+// }
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/CobolCopybooksService.kt b/src/main/kotlin/org/zowe/cobol/lsp/CobolCopybooksService.kt
new file mode 100644
index 0000000..d0063f0
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/lsp/CobolCopybooksService.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import org.zowe.cobol.searchForFileInPath
+import java.nio.file.Path
+import java.nio.file.Paths
+
+/** Service to handle the functionalities around copybooks */
+@Service
+class CobolCopybooksService {
+
+ companion object {
+ fun getService(): CobolCopybooksService = service()
+ }
+
+ // TODO: doc
+ // TODO: implement
+ // TODO: resolve the actual functionality
+// private fun getTargetFolderForCopybook(
+// folderKind: string | CopybookFolderKind,
+// documentUri: string,
+// dialectType: string,
+// ) {
+// let result: string[] = [];
+// const profile = SettingsService.getProfileName()!;
+// switch (folderKind) {
+// case CopybookFolderKind[CopybookFolderKind.local]:
+// result = SettingsService.getCopybookLocalPath(documentUri, dialectType);
+// break;
+// case CopybookFolderKind[CopybookFolderKind["downloaded-dsn"]]:
+// result = SettingsService.getDsnPath(documentUri, dialectType).map(
+// (dnsPath) => CopybookURI.createDatasetPath(profile, dnsPath),
+// );
+// break;
+// case CopybookFolderKind[CopybookFolderKind["downloaded-uss"]]:
+// result = SettingsService.getUssPath(documentUri, dialectType).map(
+// (dnsPath) => CopybookURI.createDatasetPath(profile, dnsPath),
+// );
+// break;
+// }
+// return result;
+// }
+
+ // TODO: doc
+ // TODO: implement
+ // TODO: resolve the actual functionality
+// private fun searchCopybook(
+// documentUri: String,
+// copybookName: String,
+// dialectType: String
+// ) {
+// let result: string | undefined;
+// for (let i = 0; i < Object.values(CopybookFolderKind).length; i++) {
+// const folderKind = Object.values(CopybookFolderKind)[i];
+// const targetFolder = getTargetFolderForCopybook(
+// folderKind,
+// documentUri,
+// dialectType,
+// );
+// const allowedExtensions = resolveAllowedExtensions(folderKind, documentUri);
+// result = searchCopybookInWorkspace(
+// copybookName,
+// targetFolder,
+// allowedExtensions,
+// );
+// if (result) {
+// return result;
+// }
+// }
+// return result;
+// }
+
+ /**
+ * Search for the specified copybook in the workspace folder
+ * @param workspaceFolder the workspace folder path to search for the copybook in
+ * @param copybookName the name of the copybook to search for
+ * @param copybookFolders the copybook folders in the workspace to search for the copybook in
+ * @param extensions the potential copybook extensions to search for the exact copybook by
+ * @return the found copybook path string or null
+ */
+ private fun searchCopybookInWorkspace(
+ workspaceFolder: Path,
+ copybookName: String,
+ copybookFolders: List,
+ extensions: List
+ ): String? {
+ if (copybookName.isEmpty() || extensions.isEmpty()) return null
+ for (copybookFolder in copybookFolders) {
+ for (ext in extensions) {
+ val foundCopybookPath = searchForFileInPath(workspaceFolder, copybookFolder, copybookName, ext)
+ if (foundCopybookPath != null) return Paths.get(foundCopybookPath).toUri().toString()
+ }
+ }
+ return null
+ }
+
+ // TODO: finalize the functionality when interaction with Zowe Explorer is set up
+ /**
+ * Resolve a path of the provided copybook
+ * @param workspaceFolder the workspace folder path
+ * @param copybookFolders the folders containing the copybooks
+ * @param copybookName the name of the copybook to search for
+ * @param copybookExtensions the potential copybook extension to search for the exact copybook
+ * @return the copybook path in a URI string style
+ */
+ fun resolveCopybookPath(
+ workspaceFolder: Path,
+ copybookFolders: List,
+ copybookName: String,
+ copybookExtensions: List
+ ): String? {
+// val copybook = searchCopybook(documentUri, copybookName, dialectType);
+ val result = searchCopybookInWorkspace(workspaceFolder, copybookName, copybookFolders, copybookExtensions)
+ return result
+ }
+
+}
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageClient.kt b/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageClient.kt
index f509b14..44ff317 100644
--- a/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageClient.kt
+++ b/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageClient.kt
@@ -16,24 +16,13 @@ package org.zowe.cobol.lsp
import com.intellij.openapi.project.Project
import com.redhat.devtools.lsp4ij.client.LanguageClientImpl
-import org.eclipse.lsp4j.ConfigurationParams
-import org.eclipse.lsp4j.MessageParams
-import org.eclipse.lsp4j.MessageType
+import org.eclipse.lsp4j.*
+import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
+import org.zowe.cobol.Sections
+import org.zowe.cobol.VSCodeSettingsAdapterService
+import java.net.URI
import java.util.concurrent.CompletableFuture
-
-const val DIALECT_REGISTRY_SECTION = "cobol-lsp.dialect.registry"
-const val SETTINGS_DIALECT = "cobol-lsp.dialects"
-const val SETTINGS_CPY_LOCAL_PATH = "cobol-lsp.cpy-manager.paths-local"
-const val DIALECT_LIBS = "cobol-lsp.dialect.libs"
-const val SETTINGS_CPY_EXTENSIONS = "cobol-lsp.cpy-manager.copybook-extensions"
-const val SETTINGS_SQL_BACKEND = "cobol-lsp.target-sql-backend"
-const val SETTINGS_CPY_FILE_ENCODING = "cobol-lsp.cpy-manager.copybook-file-encoding"
-const val SETTINGS_COMPILE_OPTIONS = "cobol-lsp.compiler.options"
-const val SETTINGS_CLIENT_LOGGING_LEVEL = "cobol-lsp.logging.level.root"
-const val SETTINGS_LOCALE = "cobol-lsp.locale"
-const val SETTINGS_COBOL_PROGRAM_LAYOUT = "cobol-lsp.cobol.program.layout"
-const val SETTINGS_SUBROUTINE_LOCAL_PATH = "cobol-lsp.subroutine-manager.paths-local"
-const val SETTINGS_CICS_TRANSLATOR = "cobol-lsp.cics.translator"
+import kotlin.io.path.toPath
/** COBOL LSP client wrapper. Provides a comprehensive support for the COBOL LSP communications */
class CobolLanguageClient(project: Project) : LanguageClientImpl(project) {
@@ -48,84 +37,109 @@ class CobolLanguageClient(project: Project) : LanguageClientImpl(project) {
override fun configuration(configurationParams: ConfigurationParams?): CompletableFuture> {
val result = mutableListOf()
for (item in configurationParams?.items ?: emptyList()) {
+ val section = Sections(item.section)
try {
- if (item.section == DIALECT_REGISTRY_SECTION) {
+ if (section == Sections.DIALECT_REGISTRY) {
logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 1"))
result.add(emptyList())
-// val computed = DialectRegistry.getDialects()
-// result.add(computed)
- } else if (item.scopeUri != "") {
+// val dialectInfos = DialectsService.getService().getDialects()
+// logMessage(MessageParams(MessageType.Info, "Registered dialects: $dialectInfos"))
+// result.add(dialectInfos)
+ } else if (item.scopeUri != null && item.scopeUri != "") {
+ val workspaceFolders = this.workspaceFolders().get().map { pathObj -> URI.create(pathObj.uri).toPath() }
// val cfg = vscode.workspace.getConfiguration().get(item.section)
- when (item.section) {
- SETTINGS_DIALECT -> {
+ when (section) {
+ Sections.DIALECTS_SECTION -> {
logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 2"))
result.add(emptyList())
- // val computed = loadProcessorGroupDialectConfig(item, cfg)
- // result.add(computed)
+// val settingsCfg = VSCodeSettingsAdapterService.getService()
+// .getListOfStringsConfiguration(workspaceFolders[0], Sections.DIALECTS_SECTION)
+// val dialects = CobolConfigsRecognitionService.getService()
+// .loadProcessorGroupDialectConfig(workspaceFolders[0], item, settingsCfg)
+// logMessage(MessageParams(MessageType.Info, "For ${item.scopeUri} using dialects: $dialects"))
+// result.add()
+// result.add(dialects)
}
- SETTINGS_CPY_LOCAL_PATH -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not recognized yet 3"))
- // val computed = loadProcessorGroupCopybookPathsConfig(item, cfg as List)
- // result.add(computed)
- // } else if (item.section === DIALECT_LIBS && !!item.dialect) {
+
+ Sections.CPY_LOCAL_PATH -> {
+ val settingsCfg = VSCodeSettingsAdapterService.getService()
+ .getListOfStringsConfiguration(workspaceFolders[0], Sections.CPY_LOCAL_PATH)
+ val cpyLocalPaths = CobolConfigsRecognitionService.getService()
+ .loadProcessorGroupCopybookPathsConfig(workspaceFolders[0], item, settingsCfg)
+ logMessage(
+ MessageParams(MessageType.Info, "For ${item.scopeUri} using cpy local paths: $cpyLocalPaths")
+ )
+ result.add(cpyLocalPaths)
}
- DIALECT_LIBS -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not recognized yet 4"))
- // val dialectLibs = SettingsService.getCopybookLocalPath(item.scopeUri, item.dialect)
- // result.add(dialectLibs)
+
+ Sections.DIALECT_LIBS -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not recognized yet 3"))
+ // val dialectLibs = SettingsService.getCopybookLocalPath(item.scopeUri, item.dialect)
+ // result.add(dialectLibs)
}
- SETTINGS_CPY_EXTENSIONS -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized 5"))
- result.add(listOf(".CPY", ".COPY", ".cpy", ".copy",""))
- // val computed = loadProcessorGroupCopybookExtensionsConfig(item, cfg as List)
- // result.add(computed)
+
+ Sections.CPY_EXTENSIONS -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 4"))
+ result.add(listOf(".CPY", ".COPY", ".cpy", ".copy", ""))
+ // val computed = loadProcessorGroupCopybookExtensionsConfig(item, cfg as List)
+ // result.add(computed)
}
- SETTINGS_SQL_BACKEND -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 6"))
+
+ Sections.SQL_BACKEND -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 5"))
result.add("DB2_SERVER")
- // val computed = loadProcessorGroupSqlBackendConfig(item, cfg as String)
- // result.add(computed)
+ // val computed = loadProcessorGroupSqlBackendConfig(item, cfg as String)
+ // result.add(computed)
}
- SETTINGS_CPY_FILE_ENCODING -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not recognized yet 7"))
- // val computed = loadProcessorGroupCopybookEncodingConfig(item, cfg as String)
- // result.add(computed)
+
+ Sections.CPY_FILE_ENCODING -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not recognized yet 6"))
+ // val computed = loadProcessorGroupCopybookEncodingConfig(item, cfg as String)
+ // result.add(computed)
}
- SETTINGS_COMPILE_OPTIONS -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 8"))
+
+ Sections.COMPILER_OPTIONS -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 7"))
result.add(null)
- // val computed = loadProcessorGroupCompileOptionsConfig(item, cfg as String)
- // result.add(computed)
+ // val computed = loadProcessorGroupCompileOptionsConfig(item, cfg as String)
+ // result.add(computed)
}
- SETTINGS_CLIENT_LOGGING_LEVEL -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized 11"))
+
+ Sections.LOGGIN_LEVEL_ROOT -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 8"))
result.add("ERROR")
}
- SETTINGS_LOCALE -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized 12"))
+
+ Sections.LOCALE -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 9"))
result.add("en")
}
- SETTINGS_COBOL_PROGRAM_LAYOUT -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 12"))
+
+ Sections.COBOL_PROGRAM_LAYOUT -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 10"))
result.add(null)
}
- SETTINGS_SUBROUTINE_LOCAL_PATH -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 14"))
+
+ Sections.SUBROUTINE_LOCAL_PATH -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 11"))
result.add(emptyList())
+ //
}
- SETTINGS_CICS_TRANSLATOR -> {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 15"))
+
+ Sections.CICS_TRANSLATOR -> {
+ logMessage(MessageParams(MessageType.Info, "$section is not correctly recognized yet 12"))
result.add("true")
}
+
else -> {
- // result.add(cfg)
- logMessage(MessageParams(MessageType.Info, "${item.section} is not recognized yet 9"))
+ // result.add(cfg)
+ logMessage(MessageParams(MessageType.Info, "${item.section} is not recognized yet 13"))
}
}
} else {
- logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 10"))
+ logMessage(MessageParams(MessageType.Info, "${item.section} is not correctly recognized yet 14"))
result.add(emptyList())
-// result.add(vscode.workspace.getConfiguration().get(item.section));
+// result.add(vscode.workspace.getConfiguration().get(item.section))
}
} catch (error: Throwable) {
logMessage(MessageParams(MessageType.Error, "${error.message}\n${error.stackTrace}"))
@@ -134,4 +148,40 @@ class CobolLanguageClient(project: Project) : LanguageClientImpl(project) {
return CompletableFuture.completedFuture(result)
}
+ /**
+ * Handle the "copybook/resolve" request
+ * @param documentUri the document uri string, that triggered the request
+ * @param copybookName the copybook name to resolve
+ * @param dialectType the dialect type to resolve the copybook with
+ * @return the URI path string to the resolved copybook
+ */
+ @JsonRequest("copybook/resolve")
+ fun resolveCopybook(documentUri: String, copybookName: String, dialectType: String): CompletableFuture {
+ val cpyExtenstionsConfigItem = ConfigurationItem()
+ cpyExtenstionsConfigItem.section = Sections.CPY_EXTENSIONS.toString()
+ cpyExtenstionsConfigItem.scopeUri = documentUri
+
+ val cpyLocalPathsConfigItem = ConfigurationItem()
+ cpyLocalPathsConfigItem.section = Sections.CPY_LOCAL_PATH.toString()
+ cpyLocalPathsConfigItem.scopeUri = documentUri
+
+ val configParams = ConfigurationParams(listOf(cpyExtenstionsConfigItem, cpyLocalPathsConfigItem))
+
+ return this.workspaceFolders()
+ .thenCombine?, String?>(this.configuration(configParams)) { workspaceFolders, cpyConfigsAny ->
+ val workspaceFolder = URI.create(workspaceFolders[0].uri).toPath()
+
+ val cpyConfigs = cpyConfigsAny as List>
+ val cpyExtensions = cpyConfigs[0]
+ val cpyLocalPaths = cpyConfigs[1]
+
+ CobolCopybooksService.getService()
+ .resolveCopybookPath(workspaceFolder, cpyLocalPaths, copybookName, cpyExtensions)
+ }
+ }
+
+// TODO: implement custom requests
+// @JsonRequest("cobol/resolveSubroutine")
+// @JsonRequest("copybook/download")
+
}
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactory.kt b/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactory.kt
index 07f3a41..bc75090 100644
--- a/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactory.kt
+++ b/src/main/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactory.kt
@@ -14,7 +14,6 @@
package org.zowe.cobol.lsp
-import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.redhat.devtools.lsp4ij.LanguageServerFactory
import com.redhat.devtools.lsp4ij.client.LanguageClientImpl
@@ -28,7 +27,7 @@ import org.zowe.cobol.state.LanguageSupportStateService
class CobolLanguageServerFactory : LanguageServerFactory {
override fun createConnectionProvider(project: Project): StreamConnectionProvider {
- val lsStateService = LanguageSupportStateService.instance
+ val lsStateService = LanguageSupportStateService.getService()
val pluginState = lsStateService.getPluginState(project) { CobolPluginState(project) }
@OptIn(InitializationOnly::class)
@@ -41,7 +40,7 @@ class CobolLanguageServerFactory : LanguageServerFactory {
}
override fun createLanguageClient(project: Project): LanguageClientImpl {
- val lsStateService = LanguageSupportStateService.instance
+ val lsStateService = LanguageSupportStateService.getService()
val pluginState = lsStateService.getPluginState(project) { CobolPluginState(project) }
@OptIn(InitializationOnly::class)
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/DialectInfo.kt b/src/main/kotlin/org/zowe/cobol/lsp/DialectInfo.kt
new file mode 100644
index 0000000..b35fbec
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/lsp/DialectInfo.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import java.net.URI
+
+// TODO: doc
+// TODO: clarify the usage
+data class DialectInfo(
+ val name: String,
+ val uri: URI,
+ val description: String,
+ val extensionId: String,
+ val snippetPath: String
+)
diff --git a/src/main/kotlin/org/zowe/cobol/lsp/DialectsService.kt b/src/main/kotlin/org/zowe/cobol/lsp/DialectsService.kt
new file mode 100644
index 0000000..037721c
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/lsp/DialectsService.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import java.net.URI
+
+/** Service class that provides read/write dialect settings functionality */
+@Service
+class DialectsService {
+
+ private val dialects: MutableMap = mutableMapOf()
+
+ companion object {
+ fun getService(): DialectsService = service()
+ }
+
+ /**
+ * Gets registered [DialectInfo]s
+ * @return the list of [DialectInfo]s
+ */
+ fun getDialects(): List {
+ return dialects.values.toList()
+ }
+
+ /** Clears the registry */
+ fun clear() {
+ dialects.clear()
+ }
+
+ /**
+ * Registers dialect in the system
+ * @param extensionId the extension id
+ * @param name the name of the dialect
+ * @param uri the path to jar file
+ * @param description the description of the dialect
+ * @param snippetPath the snippet map path for the dialect
+ */
+ fun register(extensionId: String, name: String, uri: URI, description: String, snippetPath: String) {
+ val dialectInfo = DialectInfo(name, uri, description, extensionId, snippetPath)
+ dialects[dialectInfo.name] = dialectInfo
+ }
+
+ /**
+ * Unregisters dialect from the system
+ * @param name the name of the dialect
+ */
+ fun unregister(name: String) {
+ dialects.remove(name)
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/org/zowe/cobol/state/LanguageSupportStateService.kt b/src/main/kotlin/org/zowe/cobol/state/LanguageSupportStateService.kt
index 1af0a1e..e43a443 100644
--- a/src/main/kotlin/org/zowe/cobol/state/LanguageSupportStateService.kt
+++ b/src/main/kotlin/org/zowe/cobol/state/LanguageSupportStateService.kt
@@ -23,9 +23,7 @@ import com.intellij.openapi.project.Project
class LanguageSupportStateService {
companion object {
- @JvmStatic
- val instance
- get() = service()
+ fun getService(): LanguageSupportStateService = service()
}
private val projectToPluginState = mutableMapOf()
diff --git a/src/main/kotlin/org/zowe/cobol/utils.kt b/src/main/kotlin/org/zowe/cobol/utils.kt
new file mode 100644
index 0000000..c96b4e1
--- /dev/null
+++ b/src/main/kotlin/org/zowe/cobol/utils.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol
+
+import java.nio.file.FileSystems
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.util.stream.Stream
+
+/**
+ * Find related files in the provided paths
+ * @param patterns the patterns to search for the files by
+ * @param paths the paths to search for the files in
+ * @return list of path strings
+ */
+fun findRelatedFilesInPaths(patterns: List, paths: Stream): List {
+ return paths.toList().fold(mutableListOf()) { resultFiles, nextPath ->
+ val nextResultFiles = patterns.filter { pattern ->
+ val matcher = FileSystems.getDefault().getPathMatcher("glob:**$pattern")
+ matcher.matches(nextPath)
+ }
+ resultFiles.addAll(nextResultFiles)
+ resultFiles
+ }
+}
+
+/**
+ * Find all file paths that are provided in the config in the specified path
+ * @param patterns the file patterns to search for (should be as a Unix-style paths or path parts)
+ * @param pathToSearchBy the path to search in the patterns by
+ * @return list of file paths as strings
+ */
+fun findFilesInPath(patterns: List, pathToSearchBy: Path): List {
+ val matchedFiles: MutableList = mutableListOf()
+ Files.walk(pathToSearchBy).use { paths ->
+ matchedFiles.addAll(findRelatedFilesInPaths(patterns, paths))
+ }
+ return matchedFiles
+}
+
+/**
+ * Cleans the [sourceStr] from the "magic" characters (such as *?[])
+ * @param sourceStr the string to clean
+ * @return a cleaned string
+ */
+fun getStringWithoutMagic(sourceStr: String): String {
+ val magicRegex = Regex("[*?\\[\\]]")
+ val magicFound = magicRegex.find(sourceStr)
+ val firstMagicCharIdx = magicFound?.range?.first ?: sourceStr.length
+ return sourceStr.substring(0, firstMagicCharIdx)
+}
+
+/**
+ * Search for a specific file by the provided parameters in the [parentFolder] path
+ * @param parentFolder the parent folder path to search for the file in
+ * @param resource the folder of file in the parent folder path to search for the file in
+ * @param fileName the file name to search file by
+ * @param ext the file extension to search the exact file by
+ */
+fun searchForFileInPath(
+ parentFolder: Path,
+ resource: String,
+ fileName: String,
+ ext: String
+): String? {
+ val resourcePathStr = getStringWithoutMagic(resource)
+ val resourcePath = Paths.get(resourcePathStr)
+ val absResourcePath = if (resourcePath.isAbsolute) resourcePath else parentFolder.resolve(resource)
+ val fileAbsPathRegex = ".*$fileName\\$ext$".toRegex()
+ val foundPaths = if (fileAbsPathRegex.matches(absResourcePath.toString())) {
+ listOf(absResourcePath.toString())
+ } else {
+ val formedPatternPath = absResourcePath.resolve("$fileName$ext")
+ findFilesInPath(
+ listOf(formedPatternPath.toString().replace("\\", "/")),
+ absResourcePath
+ )
+ }
+ return if (foundPaths.isNotEmpty()) foundPaths[0] else null
+}
diff --git a/src/test/kotlin/org/zowe/cobol/CobolProjectManagerListenerTestSpec.kt b/src/test/kotlin/org/zowe/cobol/CobolProjectManagerListenerTestSpec.kt
index f13285f..08c7c9c 100644
--- a/src/test/kotlin/org/zowe/cobol/CobolProjectManagerListenerTestSpec.kt
+++ b/src/test/kotlin/org/zowe/cobol/CobolProjectManagerListenerTestSpec.kt
@@ -69,7 +69,7 @@ class CobolProjectManagerListenerTestSpec : FunSpec({
every { getPluginState(projectMock, any<() -> LanguageSupportState>()) } returns lsStateMock
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateServiceMock
+ every { LanguageSupportStateService.getService() } returns lsStateServiceMock
cobolProjectManagerListener.projectClosing(projectMock)
@@ -89,7 +89,7 @@ class CobolProjectManagerListenerTestSpec : FunSpec({
}
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateServiceMock
+ every { LanguageSupportStateService.getService() } returns lsStateServiceMock
cobolProjectManagerListener.projectClosing(projectMock)
@@ -109,7 +109,7 @@ class CobolProjectManagerListenerTestSpec : FunSpec({
every { getPluginState(projectMock, any<() -> LanguageSupportState>()) } returns lsStateMock
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateServiceMock
+ every { LanguageSupportStateService.getService() } returns lsStateServiceMock
cobolProjectManagerListener.projectClosing(projectMock)
diff --git a/src/test/kotlin/org/zowe/cobol/UtilsTestSpec.kt b/src/test/kotlin/org/zowe/cobol/UtilsTestSpec.kt
new file mode 100644
index 0000000..35c65d9
--- /dev/null
+++ b/src/test/kotlin/org/zowe/cobol/UtilsTestSpec.kt
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol
+
+import io.kotest.assertions.assertSoftly
+import io.kotest.core.spec.style.FunSpec
+import io.kotest.matchers.shouldBe
+import io.mockk.*
+import java.nio.file.*
+
+class UtilsTestSpec : FunSpec({
+ context("utils.kt tests") {
+ afterTest {
+ unmockkAll()
+ clearAllMocks()
+ }
+
+ context("findRelatedFilesInPaths") {
+ test("return a list of found files") {
+ mockkStatic(FileSystems::getDefault)
+ val testPatterns = listOf("test1", "test2", "test3")
+ val testPath1 = Paths.get("test1")
+ val testPaths = listOf(testPath1, Paths.get("test4")).stream()
+
+ val mockedDefault = mockk {
+ every { getPathMatcher(any()) } answers {
+ if (firstArg() == "glob:**test1") {
+ mockk {
+ every { matches(any()) } answers {
+ firstArg() == testPath1
+ }
+ }
+ } else {
+ mockk {
+ every { matches(any()) } returns false
+ }
+ }
+ }
+ }
+ every { FileSystems.getDefault() } returns mockedDefault
+
+ val result = findRelatedFilesInPaths(testPatterns, testPaths)
+ assertSoftly { result shouldBe listOf(testPath1.toString()) }
+ }
+ }
+ context("searchForFileInPath") {
+ test("return found path in absolute resource path as folder, that contains the provided file path") {
+ val testWorkspaceStr = "test_workspace"
+ val testResourceStr = "test1"
+ var isPathResolvedWithParent = false
+
+ mockkStatic(::findFilesInPath)
+ every { findFilesInPath(any(), any()) } answers { listOf(testResourceStr) }
+
+ val workspacePathMock = mockk()
+ every { workspacePathMock.resolve(any()) } answers {
+ isPathResolvedWithParent = true
+ workspacePathMock
+ }
+
+ mockkStatic(FileSystems::getDefault)
+ val defaultFileSystem = mockk {
+ every { getPath(any(), *anyVararg()) } answers {
+ val pathStr = firstArg()
+ when (pathStr) {
+ testWorkspaceStr -> workspacePathMock
+ testResourceStr -> {
+ mockk {
+ every { isAbsolute } returns true
+ every { resolve(any()) } returns this
+ }
+ }
+ else -> mockk()
+ }
+ }
+ }
+ every { FileSystems.getDefault() } returns defaultFileSystem
+
+ val testWorkspace = Paths.get(testWorkspaceStr)
+
+ val result = searchForFileInPath(
+ testWorkspace,
+ "$testResourceStr?with[magic]",
+ "test_file",
+ ".cpy"
+ )
+ assertSoftly { result shouldBe testResourceStr }
+ assertSoftly { isPathResolvedWithParent shouldBe false }
+ }
+ test("return found path in absolute resource path as file, that corresponds to the provided file path") {
+ val testWorkspaceStr = "test_workspace"
+ val testResourceStr = "test1/test_file.cpy"
+ var isPathResolvedWithParent = false
+ var isFindFilesInPathCalled = false
+
+ mockkStatic(::findFilesInPath)
+ every {
+ findFilesInPath(any(), any())
+ } answers {
+ isFindFilesInPathCalled = true
+ listOf(testResourceStr)
+ }
+
+ val workspacePathMock = mockk()
+ every { workspacePathMock.resolve(any()) } answers {
+ isPathResolvedWithParent = true
+ workspacePathMock
+ }
+
+ mockkStatic(FileSystems::getDefault)
+ val defaultFileSystem = mockk {
+ every { getPath(any(), *anyVararg()) } answers {
+ val pathStr = firstArg()
+ when (pathStr) {
+ testWorkspaceStr -> workspacePathMock
+ testResourceStr -> {
+ mockk pathMockk@ {
+ every { isAbsolute } returns true
+ every { resolve(any()) } returns this
+ every { this@pathMockk.toString() } returns "test1/test_file.cpy"
+ }
+ }
+ else -> mockk()
+ }
+ }
+ }
+ every { FileSystems.getDefault() } returns defaultFileSystem
+
+ val testWorkspace = Paths.get(testWorkspaceStr)
+
+ val result = searchForFileInPath(
+ testWorkspace,
+ testResourceStr,
+ "test_file",
+ ".cpy"
+ )
+ assertSoftly { result shouldBe testResourceStr }
+ assertSoftly { isPathResolvedWithParent shouldBe false }
+ assertSoftly { isFindFilesInPathCalled shouldBe false }
+ }
+ test("return found path in workspace, that contains the provided file path") {
+ val testWorkspaceStr = "test_workspace"
+ val testResourceStr = "test1"
+ var isPathResolvedWithParent = false
+
+ mockkStatic(::findFilesInPath)
+ every { findFilesInPath(any(), any()) } answers { listOf(testWorkspaceStr) }
+
+ val workspacePathMock = mockk()
+ every { workspacePathMock.resolve(any()) } answers {
+ isPathResolvedWithParent = true
+ workspacePathMock
+ }
+
+ mockkStatic(FileSystems::getDefault)
+ val defaultFileSystem = mockk {
+ every { getPath(any(), *anyVararg()) } answers {
+ val pathStr = firstArg()
+ when (pathStr) {
+ testWorkspaceStr -> workspacePathMock
+ testResourceStr -> {
+ mockk {
+ every { isAbsolute } returns false
+ every { resolve(any()) } returns this
+ }
+ }
+ else -> mockk()
+ }
+ }
+ }
+ every { FileSystems.getDefault() } returns defaultFileSystem
+
+ val testWorkspace = Paths.get(testWorkspaceStr)
+
+ val result = searchForFileInPath(
+ testWorkspace,
+ "$testResourceStr?with[magic]",
+ "test_file",
+ ".cpy"
+ )
+ assertSoftly { result shouldBe testWorkspaceStr }
+ assertSoftly { isPathResolvedWithParent shouldBe true }
+ }
+ test("return null as path is not found in a workspace") {
+ val testWorkspaceStr = "test_workspace"
+ val testResourceStr = "test1"
+ var isPathResolvedWithParent = false
+
+ mockkStatic(::findFilesInPath)
+ every { findFilesInPath(any(), any()) } answers { listOf() }
+
+ val workspacePathMock = mockk()
+ every { workspacePathMock.resolve(any()) } answers {
+ isPathResolvedWithParent = true
+ workspacePathMock
+ }
+
+ mockkStatic(FileSystems::getDefault)
+ val defaultFileSystem = mockk {
+ every { getPath(any(), *anyVararg()) } answers {
+ val pathStr = firstArg()
+ when (pathStr) {
+ testWorkspaceStr -> workspacePathMock
+ testResourceStr -> {
+ mockk {
+ every { isAbsolute } returns false
+ every { resolve(any()) } returns this
+ }
+ }
+ else -> mockk()
+ }
+ }
+ }
+ every { FileSystems.getDefault() } returns defaultFileSystem
+
+ val testWorkspace = Paths.get(testWorkspaceStr)
+
+ val result = searchForFileInPath(testWorkspace, testResourceStr, "test_file", ".cpy")
+ assertSoftly { result shouldBe null }
+ assertSoftly { isPathResolvedWithParent shouldBe true }
+ }
+ }
+ }
+})
diff --git a/src/test/kotlin/org/zowe/cobol/VSCodeSettingsAdapterServiceTestSpec.kt b/src/test/kotlin/org/zowe/cobol/VSCodeSettingsAdapterServiceTestSpec.kt
new file mode 100644
index 0000000..bfe7287
--- /dev/null
+++ b/src/test/kotlin/org/zowe/cobol/VSCodeSettingsAdapterServiceTestSpec.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol
+
+import com.google.gson.JsonArray
+import com.google.gson.JsonElement
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import com.google.gson.stream.JsonReader
+import io.kotest.assertions.assertSoftly
+import io.kotest.core.spec.style.FunSpec
+import io.kotest.matchers.shouldBe
+import io.mockk.*
+import java.io.FileReader
+import java.io.Reader
+import java.nio.file.Paths
+import kotlin.reflect.KFunction
+
+class VSCodeSettingsAdapterServiceTestSpec : FunSpec({
+ context("VSCodeSettingsAdapterService.getListOfStringsConfiguration") {
+ afterTest {
+ unmockkAll()
+ clearAllMocks()
+ }
+
+ test("get list of strings as the result of a request to the adapter service") {
+ val testWorkspacePath = Paths.get("test_workspace")
+
+ val settingsJsonReaderMock = mockk()
+
+ val jsonArray = JsonArray()
+ jsonArray.add(mockk{ every { asString } returns "test_elem" })
+
+ val jsonObj = mockk()
+ every { jsonObj.get(Sections.UNRECOGNIZED.toString()) } returns mockk {
+ every { asJsonArray } returns jsonArray
+ }
+
+ val parseReaderFun: (Reader) -> JsonElement = JsonParser::parseReader
+ mockkStatic(parseReaderFun as KFunction<*>)
+ every { parseReaderFun(settingsJsonReaderMock) } returns mockk {
+ every { isJsonObject } returns true
+ every { asJsonObject } returns jsonObj
+ }
+
+ mockkObject(VSCodeSettingsAdapterService, recordPrivateCalls = true)
+ val vscodeAdapterService = spyk()
+ every {
+ vscodeAdapterService invoke "readConfigFileSection" withArguments listOf(testWorkspacePath, any<(FileReader) -> Any?>())
+ } answers {
+ secondArg<(FileReader) -> List>().invoke(settingsJsonReaderMock)
+ }
+ every { VSCodeSettingsAdapterService.getService() } returns vscodeAdapterService
+ val result = vscodeAdapterService.getListOfStringsConfiguration(testWorkspacePath, Sections.UNRECOGNIZED)
+ assertSoftly { result shouldBe listOf("test_elem") }
+ }
+ test("get empty list cause there is no related section in the json file") {
+ val testWorkspacePath = Paths.get("test_workspace")
+
+ val settingsJsonReaderMock = mockk()
+
+ val jsonArray = JsonArray()
+ jsonArray.add(mockk{ every { asString } returns "test_elem" })
+
+ val jsonObj = mockk()
+ every { jsonObj.get(Sections.UNRECOGNIZED.toString()) } returns mockk {
+ every { asJsonArray } returns null
+ }
+
+ val parseReaderFun: (Reader) -> JsonElement = JsonParser::parseReader
+ mockkStatic(parseReaderFun as KFunction<*>)
+ every { parseReaderFun(settingsJsonReaderMock) } returns mockk {
+ every { isJsonObject } returns true
+ every { asJsonObject } returns jsonObj
+ }
+
+ mockkObject(VSCodeSettingsAdapterService, recordPrivateCalls = true)
+ val vscodeAdapterService = spyk()
+ every {
+ vscodeAdapterService invoke "readConfigFileSection" withArguments listOf(testWorkspacePath, any<(FileReader) -> Any?>())
+ } answers {
+ secondArg<(FileReader) -> List>().invoke(settingsJsonReaderMock)
+ }
+ every { VSCodeSettingsAdapterService.getService() } returns vscodeAdapterService
+ val result = vscodeAdapterService.getListOfStringsConfiguration(testWorkspacePath, Sections.UNRECOGNIZED)
+ assertSoftly { result shouldBe listOf() }
+ }
+ test("get empty list cause the json file is not a json object") {
+ val testWorkspacePath = Paths.get("test_workspace")
+
+ val settingsJsonReaderMock = mockk()
+
+ val parseReaderFun: (Reader) -> JsonElement = JsonParser::parseReader
+ mockkStatic(parseReaderFun as KFunction<*>)
+ every { parseReaderFun(settingsJsonReaderMock) } returns mockk {
+ every { isJsonObject } returns false
+ }
+
+ mockkObject(VSCodeSettingsAdapterService, recordPrivateCalls = true)
+ val vscodeAdapterService = spyk()
+ every {
+ vscodeAdapterService invoke "readConfigFileSection" withArguments listOf(testWorkspacePath, any<(FileReader) -> Any?>())
+ } answers {
+ secondArg<(FileReader) -> List>().invoke(settingsJsonReaderMock)
+ }
+ every { VSCodeSettingsAdapterService.getService() } returns vscodeAdapterService
+ val result = vscodeAdapterService.getListOfStringsConfiguration(testWorkspacePath, Sections.UNRECOGNIZED)
+ assertSoftly { result shouldBe listOf() }
+ }
+ test("get empty list cause the json file is not found") {
+ val testWorkspacePath = Paths.get("test_workspace")
+
+ mockkObject(VSCodeSettingsAdapterService, recordPrivateCalls = true)
+ val vscodeAdapterService = spyk()
+ every {
+ vscodeAdapterService invoke "readConfigFileSection" withArguments listOf(testWorkspacePath, any<(FileReader) -> Any?>())
+ } returns null
+ every { VSCodeSettingsAdapterService.getService() } returns vscodeAdapterService
+ val result = vscodeAdapterService.getListOfStringsConfiguration(testWorkspacePath, Sections.UNRECOGNIZED)
+ assertSoftly { result shouldBe listOf() }
+ }
+ }
+})
diff --git a/src/test/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionServiceTestSpec.kt b/src/test/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionServiceTestSpec.kt
new file mode 100644
index 0000000..5ba51e3
--- /dev/null
+++ b/src/test/kotlin/org/zowe/cobol/lsp/CobolConfigsRecognitionServiceTestSpec.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import io.kotest.core.spec.style.FunSpec
+
+class CobolConfigsRecognitionServiceTestSpec : FunSpec({
+ // TODO: finish
+})
\ No newline at end of file
diff --git a/src/test/kotlin/org/zowe/cobol/lsp/CobolCopybooksServiceTestSpec.kt b/src/test/kotlin/org/zowe/cobol/lsp/CobolCopybooksServiceTestSpec.kt
new file mode 100644
index 0000000..4bc78fc
--- /dev/null
+++ b/src/test/kotlin/org/zowe/cobol/lsp/CobolCopybooksServiceTestSpec.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import io.kotest.assertions.assertSoftly
+import io.kotest.core.spec.style.FunSpec
+import io.kotest.matchers.shouldBe
+import io.mockk.*
+import org.zowe.cobol.searchForFileInPath
+import java.nio.file.Paths
+
+class CobolCopybooksServiceTestSpec : FunSpec({
+ context("CobolCopybooksService.resolveCopybookPath") {
+ afterTest {
+ unmockkAll()
+ clearAllMocks()
+ }
+
+ test("resolve copybook path") {
+ val testWorkspacePathStr = "test_workspace"
+ val testWorkspacePath = Paths.get(testWorkspacePathStr)
+ val testCopybookName = "TSTCPY"
+ val testCopybookFolders = listOf("test_res")
+ val testExtensions = listOf(".TST")
+
+ val fullTestPath = "$testWorkspacePathStr/${testCopybookFolders[0]}/$testCopybookName${testExtensions[0]}"
+
+ mockkStatic(::searchForFileInPath)
+ every { searchForFileInPath(any(), any(), any(), any()) } returns fullTestPath
+
+ val cobolCopybooksService = spyk()
+
+ mockkObject(CobolCopybooksService)
+ every { CobolCopybooksService.getService() } returns cobolCopybooksService
+
+ val result = cobolCopybooksService
+ .resolveCopybookPath(testWorkspacePath, testCopybookFolders, testCopybookName, testExtensions)
+ val expected = Paths.get(fullTestPath).toUri().toString()
+ assertSoftly { result shouldBe expected }
+ }
+ test("return null as no suitable copybook path found") {
+ val testWorkspacePathStr = "test_workspace"
+ val testWorkspacePath = Paths.get(testWorkspacePathStr)
+ val testCopybookName = "TSTCPY"
+ val testCopybookFolders = listOf("test_res")
+ val testExtensions = listOf(".TST")
+
+ mockkStatic(::searchForFileInPath)
+ every { searchForFileInPath(any(), any(), any(), any()) } returns null
+
+ val cobolCopybooksService = spyk()
+
+ mockkObject(CobolCopybooksService)
+ every { CobolCopybooksService.getService() } returns cobolCopybooksService
+
+ val result = cobolCopybooksService
+ .resolveCopybookPath(testWorkspacePath, testCopybookFolders, testCopybookName, testExtensions)
+ assertSoftly { result shouldBe null }
+ }
+ test("return null as there are no extensions") {
+ val testWorkspacePathStr = "test_workspace"
+ val testWorkspacePath = Paths.get(testWorkspacePathStr)
+ val testCopybookName = "test"
+ val testCopybookFolders = listOf()
+ val testExtensions = listOf()
+
+ val cobolCopybooksService = spyk()
+
+ mockkObject(CobolCopybooksService)
+ every { CobolCopybooksService.getService() } returns cobolCopybooksService
+
+ val result = cobolCopybooksService
+ .resolveCopybookPath(testWorkspacePath, testCopybookFolders, testCopybookName, testExtensions)
+ assertSoftly { result shouldBe null }
+ }
+ test("return null as there is no copybook name") {
+ val testWorkspacePathStr = "test_workspace"
+ val testWorkspacePath = Paths.get(testWorkspacePathStr)
+ val testCopybookName = ""
+ val testCopybookFolders = listOf()
+ val testExtensions = listOf()
+
+ val cobolCopybooksService = spyk()
+
+ mockkObject(CobolCopybooksService)
+ every { CobolCopybooksService.getService() } returns cobolCopybooksService
+
+ val result = cobolCopybooksService
+ .resolveCopybookPath(testWorkspacePath, testCopybookFolders, testCopybookName, testExtensions)
+ assertSoftly { result shouldBe null }
+ }
+ }
+})
diff --git a/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientTestSpec.kt b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientConfigurationTestSpec.kt
similarity index 72%
rename from src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientTestSpec.kt
rename to src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientConfigurationTestSpec.kt
index 2cfd147..011a509 100644
--- a/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientTestSpec.kt
+++ b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientConfigurationTestSpec.kt
@@ -23,8 +23,14 @@ import io.mockk.*
import org.eclipse.lsp4j.ConfigurationItem
import org.eclipse.lsp4j.ConfigurationParams
import org.eclipse.lsp4j.MessageParams
+import org.eclipse.lsp4j.WorkspaceFolder
+import org.zowe.cobol.Sections
+import org.zowe.cobol.VSCodeSettingsAdapterService
+import java.net.URI
+import java.util.concurrent.CompletableFuture
+import kotlin.io.path.toPath
-class CobolLanguageClientTestSpec : FunSpec({
+class CobolLanguageClientConfigurationTestSpec : FunSpec({
context("CobolLanguageClientTestSpec.configuration") {
afterTest {
@@ -37,14 +43,14 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
- every { section } returns DIALECT_REGISTRY_SECTION
+ every { section } returns Sections.DIALECT_REGISTRY.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(DIALECT_REGISTRY_SECTION)) {
+ if (firstArg().message.contains(Sections.DIALECT_REGISTRY.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -68,6 +74,9 @@ class CobolLanguageClientTestSpec : FunSpec({
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
if (firstArg().message.contains(someTestSection)) {
isLogMessageTriggeredCorrectly = true
@@ -86,14 +95,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_DIALECT
+ every { section } returns Sections.DIALECTS_SECTION.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_DIALECT)) {
+ if (firstArg().message.contains(Sections.DIALECTS_SECTION.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -107,17 +119,40 @@ class CobolLanguageClientTestSpec : FunSpec({
test("process 'workspace/configuration' for cpy-manager paths-local request with scope URI") {
var isLogMessageTriggeredCorrectly = false
+ val fakeUriPath = "file:///c/test"
+ val fakeFinalPath = "final_test_path"
+
+ val vscodeSettingsAdapterService = mockk {
+ every {
+ getListOfStringsConfiguration(URI.create(fakeUriPath).toPath(), Sections.CPY_LOCAL_PATH)
+ } returns listOf()
+ }
+ mockkObject(VSCodeSettingsAdapterService)
+ every { VSCodeSettingsAdapterService.getService() } returns vscodeSettingsAdapterService
+
+ val cobolConfigsRecognitionService = mockk {
+ every {
+ loadProcessorGroupCopybookPathsConfig(URI.create(fakeUriPath).toPath(), any(), listOf())
+ } returns listOf(fakeFinalPath)
+ }
+
+ mockkObject(CobolConfigsRecognitionService)
+ every { CobolConfigsRecognitionService.getService() } returns cobolConfigsRecognitionService
+
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_CPY_LOCAL_PATH
+ every { section } returns Sections.CPY_LOCAL_PATH.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder(fakeUriPath)))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_CPY_LOCAL_PATH)) {
+ if (firstArg().message.contains(fakeFinalPath)) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -125,7 +160,7 @@ class CobolLanguageClientTestSpec : FunSpec({
val result = cobolLanguageClient.configuration(configurationParamsMock).join()
assertSoftly { isLogMessageTriggeredCorrectly shouldBe true }
- assertSoftly { result shouldBeEqual listOf() }
+ assertSoftly { result shouldBeEqual listOf(listOf(fakeFinalPath)) }
}
test("process 'workspace/configuration' for dialect libs request with scope URI") {
@@ -134,14 +169,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns DIALECT_LIBS
+ every { section } returns Sections.DIALECT_LIBS.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(DIALECT_LIBS)) {
+ if (firstArg().message.contains(Sections.DIALECT_LIBS.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -158,14 +196,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_CPY_EXTENSIONS
+ every { section } returns Sections.CPY_EXTENSIONS.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_CPY_EXTENSIONS)) {
+ if (firstArg().message.contains(Sections.CPY_EXTENSIONS.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -182,14 +223,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_SQL_BACKEND
+ every { section } returns Sections.SQL_BACKEND.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_SQL_BACKEND)) {
+ if (firstArg().message.contains(Sections.SQL_BACKEND.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -206,14 +250,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_CPY_FILE_ENCODING
+ every { section } returns Sections.CPY_FILE_ENCODING.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_CPY_FILE_ENCODING)) {
+ if (firstArg().message.contains(Sections.CPY_FILE_ENCODING.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -230,14 +277,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_COMPILE_OPTIONS
+ every { section } returns Sections.COMPILER_OPTIONS.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_COMPILE_OPTIONS)) {
+ if (firstArg().message.contains(Sections.COMPILER_OPTIONS.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -254,14 +304,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_CLIENT_LOGGING_LEVEL
+ every { section } returns Sections.LOGGIN_LEVEL_ROOT.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_CLIENT_LOGGING_LEVEL)) {
+ if (firstArg().message.contains(Sections.LOGGIN_LEVEL_ROOT.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -278,14 +331,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_LOCALE
+ every { section } returns Sections.LOCALE.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_LOCALE)) {
+ if (firstArg().message.contains(Sections.LOCALE.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -302,14 +358,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_COBOL_PROGRAM_LAYOUT
+ every { section } returns Sections.COBOL_PROGRAM_LAYOUT.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_COBOL_PROGRAM_LAYOUT)) {
+ if (firstArg().message.contains(Sections.COBOL_PROGRAM_LAYOUT.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -326,14 +385,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_SUBROUTINE_LOCAL_PATH
+ every { section } returns Sections.SUBROUTINE_LOCAL_PATH.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_SUBROUTINE_LOCAL_PATH)) {
+ if (firstArg().message.contains(Sections.SUBROUTINE_LOCAL_PATH.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -350,14 +412,17 @@ class CobolLanguageClientTestSpec : FunSpec({
val projectMock = mockk()
val configurationItemMock = mockk {
every { scopeUri } returns "test"
- every { section } returns SETTINGS_CICS_TRANSLATOR
+ every { section } returns Sections.CICS_TRANSLATOR.toString()
}
val configurationParamsMock = mockk {
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
- if (firstArg().message.contains(SETTINGS_CICS_TRANSLATOR)) {
+ if (firstArg().message.contains(Sections.CICS_TRANSLATOR.toString())) {
isLogMessageTriggeredCorrectly = true
}
}
@@ -380,6 +445,9 @@ class CobolLanguageClientTestSpec : FunSpec({
every { items } returns listOf(configurationItemMock)
}
val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder("file:///c/test")))
every { cobolLanguageClient.logMessage(any()) } answers {
if (firstArg().message.contains(someTestSection)) {
isLogMessageTriggeredCorrectly = true
diff --git a/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientResolveCopybookTestSpec.kt b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientResolveCopybookTestSpec.kt
new file mode 100644
index 0000000..cc9f1a3
--- /dev/null
+++ b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageClientResolveCopybookTestSpec.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024 IBA Group.
+ *
+ * This program and the accompanying materials are made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v20.html
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBA Group
+ * Zowe Community
+ */
+
+package org.zowe.cobol.lsp
+
+import com.intellij.openapi.project.Project
+import io.kotest.assertions.assertSoftly
+import io.kotest.core.spec.style.FunSpec
+import io.kotest.matchers.equals.shouldBeEqual
+import io.kotest.matchers.shouldBe
+import io.mockk.*
+import org.eclipse.lsp4j.ConfigurationItem
+import org.eclipse.lsp4j.ConfigurationParams
+import org.eclipse.lsp4j.MessageParams
+import org.eclipse.lsp4j.WorkspaceFolder
+import org.zowe.cobol.Sections
+import org.zowe.cobol.VSCodeSettingsAdapterService
+import java.net.URI
+import java.util.concurrent.CompletableFuture
+import kotlin.io.path.toPath
+
+class CobolLanguageClientResolveCopybookTestSpec : FunSpec({
+
+ context("CobolLanguageClientTestSpec.resolveCopybook") {
+ afterTest {
+ unmockkAll()
+ clearAllMocks()
+ }
+
+ test("process 'copybook/resolve' request") {
+ val fakeUriPath = "file:///c/test"
+ val testCopybookName = "TSTCPY"
+ val testCpyExtensions = listOf(".testext")
+ val testCpyLocalPaths = listOf("test_local_path")
+ val fakeFinalPath = "final_test_path"
+
+ val cobolCopybooksService = mockk {
+ every {
+ resolveCopybookPath(URI.create(fakeUriPath).toPath(), testCpyLocalPaths, testCopybookName, testCpyExtensions)
+ } returns fakeFinalPath
+ }
+ mockkObject(CobolCopybooksService)
+ every { CobolCopybooksService.getService() } returns cobolCopybooksService
+
+ val projectMock = mockk()
+ val cobolLanguageClient = spyk(CobolLanguageClient(projectMock))
+ every {
+ cobolLanguageClient.workspaceFolders()
+ } returns CompletableFuture.completedFuture(listOf(WorkspaceFolder(fakeUriPath)))
+ every {
+ cobolLanguageClient.configuration(any())
+ } returns CompletableFuture.completedFuture(mutableListOf(testCpyExtensions, testCpyLocalPaths))
+
+ val result = cobolLanguageClient.resolveCopybook("test", testCopybookName, "test").join()
+ assertSoftly { result shouldBe fakeFinalPath }
+ }
+ }
+
+})
diff --git a/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactoryTestSpec.kt b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactoryTestSpec.kt
index 1cfaf0e..f29f57d 100644
--- a/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactoryTestSpec.kt
+++ b/src/test/kotlin/org/zowe/cobol/lsp/CobolLanguageServerFactoryTestSpec.kt
@@ -60,7 +60,7 @@ class CobolLanguageServerFactoryTestSpec : FunSpec({
every { getPluginState(projectMock, any<() -> LanguageSupportState>()) } returns lsStateMock
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
val cobolLanguageServerFactory = spyk(CobolLanguageServerFactory())
@@ -99,7 +99,7 @@ class CobolLanguageServerFactoryTestSpec : FunSpec({
}
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
val cobolLanguageServerFactory = spyk(CobolLanguageServerFactory())
@@ -144,7 +144,7 @@ class CobolLanguageServerFactoryTestSpec : FunSpec({
every { getPluginState(projectMock, any<() -> LanguageSupportState>()) } returns lsStateMock
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
val cobolLanguageServerFactory = spyk(CobolLanguageServerFactory())
@@ -183,7 +183,7 @@ class CobolLanguageServerFactoryTestSpec : FunSpec({
}
}
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
val cobolLanguageServerFactory = spyk(CobolLanguageServerFactory())
diff --git a/src/test/kotlin/org/zowe/cobol/state/CobolPluginStateTestSpec.kt b/src/test/kotlin/org/zowe/cobol/state/CobolPluginStateTestSpec.kt
index e24f1bb..ae76db3 100644
--- a/src/test/kotlin/org/zowe/cobol/state/CobolPluginStateTestSpec.kt
+++ b/src/test/kotlin/org/zowe/cobol/state/CobolPluginStateTestSpec.kt
@@ -39,12 +39,12 @@ class CobolPluginStateTestSpec : FunSpec({
context("CobolPluginStateTestSpec: lateinit vars") {
val cobolState = spyk(CobolPluginState(mockk()))
- test("make a try to get not yet initialized lateinit var") {
+ test("make a try to get not yet initialized lateinit var of LSP server") {
val exception = assertThrows { cobolState.getReadyLSPServerConnection() }
assertSoftly { exception.message shouldContain "LSP server connection is not ready" }
}
- test("make a try to get not yet initialized lateinit var") {
+ test("make a try to get not yet initialized lateinit var of LSP client") {
val exception = assertThrows { cobolState.getReadyLSPClient() }
assertSoftly { exception.message shouldContain "LSP client is not ready" }
}
diff --git a/src/test/kotlin/org/zowe/cobol/state/LanguageSupportStateServiceTestSpec.kt b/src/test/kotlin/org/zowe/cobol/state/LanguageSupportStateServiceTestSpec.kt
index 235d3fa..81b2fe6 100644
--- a/src/test/kotlin/org/zowe/cobol/state/LanguageSupportStateServiceTestSpec.kt
+++ b/src/test/kotlin/org/zowe/cobol/state/LanguageSupportStateServiceTestSpec.kt
@@ -40,7 +40,7 @@ class LanguageSupportStateServiceTestSpec : FunSpec({
val lsStateService = spyk(LanguageSupportStateService(), recordPrivateCalls = true)
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
setPrivateFieldValue(
lsStateService,
@@ -49,7 +49,7 @@ class LanguageSupportStateServiceTestSpec : FunSpec({
mutableMapOf(projectMock to lsStateMock)
)
- val result = LanguageSupportStateService.instance.getPluginState(projectMock) { defaultLSStateMock }
+ val result = LanguageSupportStateService.getService().getPluginState(projectMock) { defaultLSStateMock }
assertSoftly { result shouldBe lsStateMock }
}
@@ -61,7 +61,7 @@ class LanguageSupportStateServiceTestSpec : FunSpec({
val lsStateService = spyk(LanguageSupportStateService(), recordPrivateCalls = true)
mockkObject(LanguageSupportStateService)
- every { LanguageSupportStateService.instance } returns lsStateService
+ every { LanguageSupportStateService.getService() } returns lsStateService
setPrivateFieldValue(
lsStateService,
@@ -70,7 +70,7 @@ class LanguageSupportStateServiceTestSpec : FunSpec({
mutableMapOf(mockk() to lsStateMock)
)
- val result = LanguageSupportStateService.instance.getPluginState(projectMock) { defaultLSStateMock }
+ val result = LanguageSupportStateService.getService().getPluginState(projectMock) { defaultLSStateMock }
assertSoftly { result shouldBe defaultLSStateMock }
}