33
44package software.aws.toolkits.jetbrains.services.amazonq.lsp.textdocument
55
6- import com.intellij.openapi.Disposable
7- import com.intellij.openapi.components.serviceIfCreated
6+ import com.intellij.openapi.application.writeAction
87import com.intellij.openapi.editor.Document
98import com.intellij.openapi.fileEditor.FileDocumentManager
10- import com.intellij.openapi.fileEditor.FileEditorManager
119import com.intellij.openapi.fileTypes.FileType
12- import com.intellij.openapi.project.Project
1310import com.intellij.openapi.vfs.VirtualFile
1411import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent
1512import 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
1715import 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
2119import io.mockk.every
22- import io.mockk.just
2320import io.mockk.mockk
2421import io.mockk.mockkObject
2522import io.mockk.mockkStatic
26- import io.mockk.runs
2723import io.mockk.slot
2824import io.mockk.spyk
2925import io.mockk.verify
3026import kotlinx.coroutines.test.runTest
27+ import kotlinx.coroutines.withContext
3128import org.assertj.core.api.Assertions.assertThat
3229import org.eclipse.lsp4j.DidChangeTextDocumentParams
3330import org.eclipse.lsp4j.DidCloseTextDocumentParams
@@ -38,37 +35,49 @@ import org.eclipse.lsp4j.services.TextDocumentService
3835import org.junit.Before
3936import org.junit.Rule
4037import org.junit.Test
38+ import software.aws.toolkits.jetbrains.core.coroutines.EDT
4139import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
4240import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
4341import 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
4444import java.net.URI
4545import java.nio.file.Path
4646import java.util.concurrent.CompletableFuture
47+ import kotlin.collections.first
4748
4849class TextDocumentServiceHandlerTest {
49- @Rule
50- @JvmField
51- val application = ApplicationRule ()
52-
53- private lateinit var project: Project
54- private lateinit var mockFileEditorManager: FileEditorManager
5550 private lateinit var mockLanguageServer: AmazonQLanguageServer
5651 private lateinit var mockTextDocumentService: TextDocumentService
5752 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 ()
5970
6071 @Before
6172 fun setup () {
62- project = mockk<Project >()
6373 mockTextDocumentService = mockk<TextDocumentService >()
6474 mockLanguageServer = mockk<AmazonQLanguageServer >()
6575
6676 // Mock the LSP service
67- val mockLspService = mockk<AmazonQLspService >()
77+ val mockLspService = mockk<AmazonQLspService >(relaxed = true )
6878
6979 // 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)
7281
7382 // Mock the LSP service's executeSync method as a suspend function
7483 every {
@@ -85,19 +94,7 @@ class TextDocumentServiceHandlerTest {
8594 every { mockTextDocumentService.didOpen(any()) } returns Unit
8695 every { mockTextDocumentService.didClose(any()) } returns Unit
8796
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())
10198 }
10299
103100 @Test
@@ -135,41 +132,39 @@ class TextDocumentServiceHandlerTest {
135132
136133 @Test
137134 fun `didOpen runs on service init` () = runTest {
138- val uri = URI .create(" file:///test/path/file.txt" )
139135 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+ }
143139
144- sut = TextDocumentServiceHandler (project, mockk())
140+ sut = TextDocumentServiceHandler (projectRule. project, mockk())
145141
146- val paramsSlot = slot <DidOpenTextDocumentParams >()
142+ val paramsSlot = mutableListOf <DidOpenTextDocumentParams >()
147143 verify { mockTextDocumentService.didOpen(capture(paramsSlot)) }
148144
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" )
154149 }
155150 }
156151
157152 @Test
158153 fun `didOpen runs on fileOpened` () = runTest {
159- val uri = URI .create(" file:///test/path/file.txt" )
160154 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+ }
162158
163159 sut.fileOpened(mockk(), file)
164160
165- val paramsSlot = slot <DidOpenTextDocumentParams >()
161+ val paramsSlot = mutableListOf <DidOpenTextDocumentParams >()
166162 verify { mockTextDocumentService.didOpen(capture(paramsSlot)) }
167163
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" )
173168 }
174169 }
175170
@@ -188,40 +183,23 @@ class TextDocumentServiceHandlerTest {
188183
189184 @Test
190185 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)
196189
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+ }
214193 }
215194 }
216195
217196 // Verify the correct LSP method was called with matching parameters
218- val paramsSlot = slot <DidChangeTextDocumentParams >()
197+ val paramsSlot = mutableListOf <DidChangeTextDocumentParams >()
219198 verify { mockTextDocumentService.didChange(capture(paramsSlot)) }
220199
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" )
225203 }
226204 }
227205
@@ -337,6 +315,11 @@ class TextDocumentServiceHandlerTest {
337315 return uri
338316 }
339317
318+ if (uri.startsWith(" file://C:/" )) {
319+ val path = uri.substringAfter(" file://C:/" )
320+ return " file:///C:/$path "
321+ }
322+
340323 val path = uri.substringAfter(" file:///" )
341324 return " file:///C:/$path "
342325 }
0 commit comments