Skip to content

feat(amazonq): add virtualFile -> URI util #5381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.jetbrains.services.amazonq.lsp.util

import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.core.utils.warn
import java.io.File
import java.net.URI
import java.net.URISyntaxException

object FileUriUtil {

fun toUriString(virtualFile: VirtualFile): String? {
val protocol = virtualFile.fileSystem.protocol
val uri = when (protocol) {
"jar" -> VfsUtilCore.convertToURL(virtualFile.url)?.toExternalForm()
"jrt" -> virtualFile.url
else -> toUri(VfsUtilCore.virtualToIoFile(virtualFile)).toASCIIString()
} ?: return null

return if (virtualFile.isDirectory) {
uri.trimEnd('/', '\\')
} else {
uri
}
}

private fun toUri(file: File): URI {
try {
// URI scheme specified by language server protocol
return URI("file", "", file.absoluteFile.toURI().path, null)
} catch (e: URISyntaxException) {
LOG.warn { "${e.localizedMessage}: $e" }
return file.absoluteFile.toURI()
}
}

private val LOG = getLogger<FileUriUtil>()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package software.aws.toolkits.jetbrains.services.amazonq.lsp.util

import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import io.mockk.every
import io.mockk.mockk
import org.junit.Test

class FileUriUtilTest : BasePlatformTestCase() {

private fun createMockVirtualFile(path: String, protocol: String = "file", isDirectory: Boolean = false): VirtualFile =
mockk<VirtualFile> {
every { fileSystem } returns mockk {
every { this@mockk.protocol } returns protocol
}
every { url } returns path
every { this@mockk.isDirectory } returns isDirectory
}

private fun normalizeFileUri(uri: String): String {
if (!System.getProperty("os.name").lowercase().contains("windows")) {
return uri
}

if (!uri.startsWith("file:///")) {
return uri
}

val path = uri.substringAfter("file:///")
return "file:///C:/$path"
}

@Test
fun `test basic unix path`() {
val virtualFile = createMockVirtualFile("/path/to/file.txt")
val uri = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("file:///path/to/file.txt")
assertEquals(expected, uri)
}

@Test
fun `test unix directory path`() {
val virtualFile = createMockVirtualFile("/path/to/directory/", isDirectory = true)
val uri = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("file:///path/to/directory")
assertEquals(expected, uri)
}

@Test
fun `test path with spaces`() {
val virtualFile = createMockVirtualFile("/path/with spaces/file.txt")
val uri = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("file:///path/with%20spaces/file.txt")
assertEquals(expected, uri)
}

@Test
fun `test root path`() {
val virtualFile = createMockVirtualFile("/")
val uri = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("file:///")
assertEquals(expected, uri)
}

@Test
fun `test path with multiple separators`() {
val virtualFile = createMockVirtualFile("/path//to///file.txt")
val uri = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("file:///path/to/file.txt")
assertEquals(expected, uri)
}

@Test
fun `test very long path`() {
val longPath = "/a".repeat(256) + "/file.txt"
val virtualFile = createMockVirtualFile(longPath)
val uri = FileUriUtil.toUriString(virtualFile)
if (uri != null) {
assertTrue(uri.startsWith("file:///"))
assertTrue(uri.endsWith("/file.txt"))
}
}

@Test
fun `test relative path`() {
val virtualFile = createMockVirtualFile("./relative/path/file.txt")
val uri = FileUriUtil.toUriString(virtualFile)
if (uri != null) {
assertTrue(uri.contains("file.txt"))
assertTrue(uri.startsWith("file:///"))
}
}

@Test
fun `test jar protocol conversion`() {
val virtualFile = createMockVirtualFile(
"jar:file:///path/to/archive.jar!/com/example/Test.class",
"jar"
)
val result = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("jar:file:///path/to/archive.jar!/com/example/Test.class")
assertEquals(expected, result)
}

@Test
fun `test jrt protocol conversion`() {
val virtualFile = createMockVirtualFile(
"jrt://java.base/java/lang/String.class",
"jrt"
)
val result = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("jrt://java.base/java/lang/String.class")
assertEquals(expected, result)
}

@Test
fun `test invalid jar url returns null`() {
val virtualFile = createMockVirtualFile(
"invalid:url:format",
"jar"
)
val result = FileUriUtil.toUriString(virtualFile)
assertNull(result)
}

@Test
fun `test jar protocol with directory`() {
val virtualFile = createMockVirtualFile(
"jar:file:///path/to/archive.jar!/com/example/",
"jar",
true
)
val result = FileUriUtil.toUriString(virtualFile)
val expected = normalizeFileUri("jar:file:///path/to/archive.jar!/com/example")
assertEquals(expected, result)
}

@Test
fun `test empty url in jar protocol`() {
val virtualFile = createMockVirtualFile(
"",
"jar",
true
)
val result = FileUriUtil.toUriString(virtualFile)
assertNull(result)
}
}
Loading