3
3
4
4
package software.aws.toolkits.jetbrains.services.amazonq.lsp.textdocument
5
5
6
- import com.intellij.openapi.Disposable
7
- import com.intellij.openapi.components.serviceIfCreated
6
+ import com.intellij.openapi.application.writeAction
8
7
import com.intellij.openapi.editor.Document
9
8
import com.intellij.openapi.fileEditor.FileDocumentManager
10
- import com.intellij.openapi.fileEditor.FileEditorManager
11
9
import com.intellij.openapi.fileTypes.FileType
12
- import com.intellij.openapi.project.Project
13
10
import com.intellij.openapi.vfs.VirtualFile
14
11
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent
15
12
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
16
- import com.intellij.testFramework.ApplicationRule
13
+ import com.intellij.openapi.vfs.writeText
14
+ import com.intellij.testFramework.DisposableRule
17
15
import com.intellij.testFramework.LightVirtualFile
18
- import com.intellij.testFramework.runInEdtAndWait
19
- import com.intellij.util.messages.MessageBus
20
- import com.intellij.util.messages.MessageBusConnection
16
+ import com.intellij.testFramework.fixtures.CodeInsightTestFixture
17
+ import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory
18
+ import com.intellij.testFramework.replaceService
21
19
import io.mockk.every
22
- import io.mockk.just
23
20
import io.mockk.mockk
24
21
import io.mockk.mockkObject
25
22
import io.mockk.mockkStatic
26
- import io.mockk.runs
27
23
import io.mockk.slot
28
24
import io.mockk.spyk
29
25
import io.mockk.verify
30
26
import kotlinx.coroutines.test.runTest
27
+ import kotlinx.coroutines.withContext
31
28
import org.assertj.core.api.Assertions.assertThat
32
29
import org.eclipse.lsp4j.DidChangeTextDocumentParams
33
30
import org.eclipse.lsp4j.DidCloseTextDocumentParams
@@ -38,37 +35,49 @@ import org.eclipse.lsp4j.services.TextDocumentService
38
35
import org.junit.Before
39
36
import org.junit.Rule
40
37
import org.junit.Test
38
+ import software.aws.toolkits.jetbrains.core.coroutines.EDT
41
39
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
42
40
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
43
41
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil
42
+ import software.aws.toolkits.jetbrains.utils.rules.CodeInsightTestFixtureRule
43
+ import software.aws.toolkits.jetbrains.utils.satisfiesKt
44
44
import java.net.URI
45
45
import java.nio.file.Path
46
46
import java.util.concurrent.CompletableFuture
47
+ import kotlin.collections.first
47
48
48
49
class TextDocumentServiceHandlerTest {
49
- @Rule
50
- @JvmField
51
- val application = ApplicationRule ()
52
-
53
- private lateinit var project: Project
54
- private lateinit var mockFileEditorManager: FileEditorManager
55
50
private lateinit var mockLanguageServer: AmazonQLanguageServer
56
51
private lateinit var mockTextDocumentService: TextDocumentService
57
52
private lateinit var sut: TextDocumentServiceHandler
58
- // private lateinit var mockApplication: Application
53
+
54
+ @get:Rule
55
+ val projectRule = object : CodeInsightTestFixtureRule () {
56
+ override fun createTestFixture (): CodeInsightTestFixture {
57
+ val fixtureFactory = IdeaTestFixtureFactory .getFixtureFactory()
58
+ val fixtureBuilder = fixtureFactory.createLightFixtureBuilder(testDescription, testName)
59
+ val newFixture = fixtureFactory
60
+ .createCodeInsightFixture(fixtureBuilder.fixture, fixtureFactory.createTempDirTestFixture())
61
+ newFixture.setUp()
62
+ newFixture.testDataPath = testDataPath
63
+
64
+ return newFixture
65
+ }
66
+ }
67
+
68
+ @get:Rule
69
+ val disposableRule = DisposableRule ()
59
70
60
71
@Before
61
72
fun setup () {
62
- project = mockk<Project >()
63
73
mockTextDocumentService = mockk<TextDocumentService >()
64
74
mockLanguageServer = mockk<AmazonQLanguageServer >()
65
75
66
76
// Mock the LSP service
67
- val mockLspService = mockk<AmazonQLspService >()
77
+ val mockLspService = mockk<AmazonQLspService >(relaxed = true )
68
78
69
79
// Mock the service methods on Project
70
- every { project.getService(AmazonQLspService ::class .java) } returns mockLspService
71
- every { project.serviceIfCreated<AmazonQLspService >() } returns mockLspService
80
+ projectRule.project.replaceService(AmazonQLspService ::class .java, mockLspService, disposableRule.disposable)
72
81
73
82
// Mock the LSP service's executeSync method as a suspend function
74
83
every {
@@ -85,19 +94,7 @@ class TextDocumentServiceHandlerTest {
85
94
every { mockTextDocumentService.didOpen(any()) } returns Unit
86
95
every { mockTextDocumentService.didClose(any()) } returns Unit
87
96
88
- // Mock message bus
89
- val messageBus = mockk<MessageBus >()
90
- every { project.messageBus } returns messageBus
91
- val mockConnection = mockk<MessageBusConnection >()
92
- every { messageBus.connect(any<Disposable >()) } returns mockConnection
93
- every { mockConnection.subscribe(any(), any()) } just runs
94
-
95
- // Mock FileEditorManager
96
- mockFileEditorManager = mockk<FileEditorManager >()
97
- every { mockFileEditorManager.openFiles } returns emptyArray()
98
- every { project.getService(FileEditorManager ::class .java) } returns mockFileEditorManager
99
-
100
- sut = TextDocumentServiceHandler (project, mockk())
97
+ sut = TextDocumentServiceHandler (projectRule.project, mockk())
101
98
}
102
99
103
100
@Test
@@ -135,41 +132,39 @@ class TextDocumentServiceHandlerTest {
135
132
136
133
@Test
137
134
fun `didOpen runs on service init` () = runTest {
138
- val uri = URI .create(" file:///test/path/file.txt" )
139
135
val content = " test content"
140
- val file = createMockVirtualFile(uri, content)
141
-
142
- every { mockFileEditorManager.openFiles } returns arrayOf(file)
136
+ val file = withContext( EDT ) {
137
+ projectRule.fixture.createFile( " name " , content). also { projectRule.fixture.openFileInEditor(it) }
138
+ }
143
139
144
- sut = TextDocumentServiceHandler (project, mockk())
140
+ sut = TextDocumentServiceHandler (projectRule. project, mockk())
145
141
146
- val paramsSlot = slot <DidOpenTextDocumentParams >()
142
+ val paramsSlot = mutableListOf <DidOpenTextDocumentParams >()
147
143
verify { mockTextDocumentService.didOpen(capture(paramsSlot)) }
148
144
149
- with (paramsSlot.captured.textDocument) {
150
- assertThat(this .uri).isEqualTo(normalizeFileUri(uri.toString()))
151
- assertThat(text).isEqualTo(content)
152
- assertThat(languageId).isEqualTo(" java" )
153
- assertThat(version).isEqualTo(1 )
145
+ assertThat(paramsSlot.first().textDocument).satisfiesKt {
146
+ assertThat(it.uri).isEqualTo(file.toNioPath().toUri().toString())
147
+ assertThat(it.text).isEqualTo(content)
148
+ assertThat(it.languageId).isEqualTo(" plain_text" )
154
149
}
155
150
}
156
151
157
152
@Test
158
153
fun `didOpen runs on fileOpened` () = runTest {
159
- val uri = URI .create(" file:///test/path/file.txt" )
160
154
val content = " test content"
161
- val file = createMockVirtualFile(uri, content)
155
+ val file = withContext(EDT ) {
156
+ projectRule.fixture.createFile(" name" , content).also { projectRule.fixture.openFileInEditor(it) }
157
+ }
162
158
163
159
sut.fileOpened(mockk(), file)
164
160
165
- val paramsSlot = slot <DidOpenTextDocumentParams >()
161
+ val paramsSlot = mutableListOf <DidOpenTextDocumentParams >()
166
162
verify { mockTextDocumentService.didOpen(capture(paramsSlot)) }
167
163
168
- with (paramsSlot.captured.textDocument) {
169
- assertThat(this .uri).isEqualTo(normalizeFileUri(uri.toString()))
170
- assertThat(text).isEqualTo(content)
171
- assertThat(languageId).isEqualTo(" java" )
172
- assertThat(version).isEqualTo(1 )
164
+ assertThat(paramsSlot.first().textDocument).satisfiesKt {
165
+ assertThat(it.uri).isEqualTo(file.toNioPath().toUri().toString())
166
+ assertThat(it.text).isEqualTo(content)
167
+ assertThat(it.languageId).isEqualTo(" plain_text" )
173
168
}
174
169
}
175
170
@@ -188,40 +183,23 @@ class TextDocumentServiceHandlerTest {
188
183
189
184
@Test
190
185
fun `didChange runs on content change events` () = runTest {
191
- val uri = URI .create(" file:///test/path/file.txt" )
192
- val document = mockk<Document > {
193
- every { text } returns " changed content"
194
- every { modificationStamp } returns 123L
195
- }
186
+ val file = withContext(EDT ) {
187
+ projectRule.fixture.createFile(" name" , " " ).also {
188
+ projectRule.fixture.openFileInEditor(it)
196
189
197
- val file = createMockVirtualFile(uri)
198
-
199
- val changeEvent = mockk<VFileContentChangeEvent > {
200
- every { this @mockk.file } returns file
201
- }
202
-
203
- // Mock FileDocumentManager
204
- val fileDocumentManager = mockk<FileDocumentManager > {
205
- every { getCachedDocument(file) } returns document
206
- }
207
-
208
- mockkStatic(FileDocumentManager ::class ) {
209
- every { FileDocumentManager .getInstance() } returns fileDocumentManager
210
-
211
- // Call the handler method
212
- runInEdtAndWait {
213
- sut.after(mutableListOf (changeEvent))
190
+ writeAction {
191
+ it.writeText(" changed content" )
192
+ }
214
193
}
215
194
}
216
195
217
196
// Verify the correct LSP method was called with matching parameters
218
- val paramsSlot = slot <DidChangeTextDocumentParams >()
197
+ val paramsSlot = mutableListOf <DidChangeTextDocumentParams >()
219
198
verify { mockTextDocumentService.didChange(capture(paramsSlot)) }
220
199
221
- with (paramsSlot.captured) {
222
- assertThat(textDocument.uri).isEqualTo(normalizeFileUri(uri.toString()))
223
- assertThat(textDocument.version).isEqualTo(123 )
224
- assertThat(contentChanges[0 ].text).isEqualTo(" changed content" )
200
+ assertThat(paramsSlot.first()).satisfiesKt {
201
+ assertThat(it.textDocument.uri).isEqualTo(file.toNioPath().toUri().toString())
202
+ assertThat(it.contentChanges[0 ].text).isEqualTo(" changed content" )
225
203
}
226
204
}
227
205
@@ -337,6 +315,11 @@ class TextDocumentServiceHandlerTest {
337
315
return uri
338
316
}
339
317
318
+ if (uri.startsWith(" file://C:/" )) {
319
+ val path = uri.substringAfter(" file://C:/" )
320
+ return " file:///C:/$path "
321
+ }
322
+
340
323
val path = uri.substringAfter(" file:///" )
341
324
return " file:///C:/$path "
342
325
}
0 commit comments