Skip to content

Commit 1fd1e73

Browse files
feat(amazonq): add virtualFile -> URI util (#5381)
* add virtualFile -> URI util * add string function * utility object instead of class * tests * detekt * detekt * redhat impl * deteckt * missing license * fix tests * detekt * OS handling for tests * detekt
1 parent 0af95e3 commit 1fd1e73

File tree

2 files changed

+192
-0
lines changed
  • plugins/amazonq/shared/jetbrains-community

2 files changed

+192
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.util
5+
6+
import com.intellij.openapi.vfs.VfsUtilCore
7+
import com.intellij.openapi.vfs.VirtualFile
8+
import software.aws.toolkits.core.utils.getLogger
9+
import software.aws.toolkits.core.utils.warn
10+
import java.io.File
11+
import java.net.URI
12+
import java.net.URISyntaxException
13+
14+
object FileUriUtil {
15+
16+
fun toUriString(virtualFile: VirtualFile): String? {
17+
val protocol = virtualFile.fileSystem.protocol
18+
val uri = when (protocol) {
19+
"jar" -> VfsUtilCore.convertToURL(virtualFile.url)?.toExternalForm()
20+
"jrt" -> virtualFile.url
21+
else -> toUri(VfsUtilCore.virtualToIoFile(virtualFile)).toASCIIString()
22+
} ?: return null
23+
24+
return if (virtualFile.isDirectory) {
25+
uri.trimEnd('/', '\\')
26+
} else {
27+
uri
28+
}
29+
}
30+
31+
private fun toUri(file: File): URI {
32+
try {
33+
// URI scheme specified by language server protocol
34+
return URI("file", "", file.absoluteFile.toURI().path, null)
35+
} catch (e: URISyntaxException) {
36+
LOG.warn { "${e.localizedMessage}: $e" }
37+
return file.absoluteFile.toURI()
38+
}
39+
}
40+
41+
private val LOG = getLogger<FileUriUtil>()
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package software.aws.toolkits.jetbrains.services.amazonq.lsp.util
4+
5+
import com.intellij.openapi.vfs.VirtualFile
6+
import com.intellij.testFramework.fixtures.BasePlatformTestCase
7+
import io.mockk.every
8+
import io.mockk.mockk
9+
import org.junit.Test
10+
11+
class FileUriUtilTest : BasePlatformTestCase() {
12+
13+
private fun createMockVirtualFile(path: String, protocol: String = "file", isDirectory: Boolean = false): VirtualFile =
14+
mockk<VirtualFile> {
15+
every { fileSystem } returns mockk {
16+
every { this@mockk.protocol } returns protocol
17+
}
18+
every { url } returns path
19+
every { this@mockk.isDirectory } returns isDirectory
20+
}
21+
22+
private fun normalizeFileUri(uri: String): String {
23+
if (!System.getProperty("os.name").lowercase().contains("windows")) {
24+
return uri
25+
}
26+
27+
if (!uri.startsWith("file:///")) {
28+
return uri
29+
}
30+
31+
val path = uri.substringAfter("file:///")
32+
return "file:///C:/$path"
33+
}
34+
35+
@Test
36+
fun `test basic unix path`() {
37+
val virtualFile = createMockVirtualFile("/path/to/file.txt")
38+
val uri = FileUriUtil.toUriString(virtualFile)
39+
val expected = normalizeFileUri("file:///path/to/file.txt")
40+
assertEquals(expected, uri)
41+
}
42+
43+
@Test
44+
fun `test unix directory path`() {
45+
val virtualFile = createMockVirtualFile("/path/to/directory/", isDirectory = true)
46+
val uri = FileUriUtil.toUriString(virtualFile)
47+
val expected = normalizeFileUri("file:///path/to/directory")
48+
assertEquals(expected, uri)
49+
}
50+
51+
@Test
52+
fun `test path with spaces`() {
53+
val virtualFile = createMockVirtualFile("/path/with spaces/file.txt")
54+
val uri = FileUriUtil.toUriString(virtualFile)
55+
val expected = normalizeFileUri("file:///path/with%20spaces/file.txt")
56+
assertEquals(expected, uri)
57+
}
58+
59+
@Test
60+
fun `test root path`() {
61+
val virtualFile = createMockVirtualFile("/")
62+
val uri = FileUriUtil.toUriString(virtualFile)
63+
val expected = normalizeFileUri("file:///")
64+
assertEquals(expected, uri)
65+
}
66+
67+
@Test
68+
fun `test path with multiple separators`() {
69+
val virtualFile = createMockVirtualFile("/path//to///file.txt")
70+
val uri = FileUriUtil.toUriString(virtualFile)
71+
val expected = normalizeFileUri("file:///path/to/file.txt")
72+
assertEquals(expected, uri)
73+
}
74+
75+
@Test
76+
fun `test very long path`() {
77+
val longPath = "/a".repeat(256) + "/file.txt"
78+
val virtualFile = createMockVirtualFile(longPath)
79+
val uri = FileUriUtil.toUriString(virtualFile)
80+
if (uri != null) {
81+
assertTrue(uri.startsWith("file:///"))
82+
assertTrue(uri.endsWith("/file.txt"))
83+
}
84+
}
85+
86+
@Test
87+
fun `test relative path`() {
88+
val virtualFile = createMockVirtualFile("./relative/path/file.txt")
89+
val uri = FileUriUtil.toUriString(virtualFile)
90+
if (uri != null) {
91+
assertTrue(uri.contains("file.txt"))
92+
assertTrue(uri.startsWith("file:///"))
93+
}
94+
}
95+
96+
@Test
97+
fun `test jar protocol conversion`() {
98+
val virtualFile = createMockVirtualFile(
99+
"jar:file:///path/to/archive.jar!/com/example/Test.class",
100+
"jar"
101+
)
102+
val result = FileUriUtil.toUriString(virtualFile)
103+
val expected = normalizeFileUri("jar:file:///path/to/archive.jar!/com/example/Test.class")
104+
assertEquals(expected, result)
105+
}
106+
107+
@Test
108+
fun `test jrt protocol conversion`() {
109+
val virtualFile = createMockVirtualFile(
110+
"jrt://java.base/java/lang/String.class",
111+
"jrt"
112+
)
113+
val result = FileUriUtil.toUriString(virtualFile)
114+
val expected = normalizeFileUri("jrt://java.base/java/lang/String.class")
115+
assertEquals(expected, result)
116+
}
117+
118+
@Test
119+
fun `test invalid jar url returns null`() {
120+
val virtualFile = createMockVirtualFile(
121+
"invalid:url:format",
122+
"jar"
123+
)
124+
val result = FileUriUtil.toUriString(virtualFile)
125+
assertNull(result)
126+
}
127+
128+
@Test
129+
fun `test jar protocol with directory`() {
130+
val virtualFile = createMockVirtualFile(
131+
"jar:file:///path/to/archive.jar!/com/example/",
132+
"jar",
133+
true
134+
)
135+
val result = FileUriUtil.toUriString(virtualFile)
136+
val expected = normalizeFileUri("jar:file:///path/to/archive.jar!/com/example")
137+
assertEquals(expected, result)
138+
}
139+
140+
@Test
141+
fun `test empty url in jar protocol`() {
142+
val virtualFile = createMockVirtualFile(
143+
"",
144+
"jar",
145+
true
146+
)
147+
val result = FileUriUtil.toUriString(virtualFile)
148+
assertNull(result)
149+
}
150+
}

0 commit comments

Comments
 (0)