6
6
import * as vscode from 'vscode'
7
7
import * as sinon from 'sinon'
8
8
import assert from 'assert'
9
- import { EditDecorationManager } from '../../../../../src/app/inline/EditRendering/displayImage'
9
+ import { EditDecorationManager , displaySvgDecoration } from '../../../../../src/app/inline/EditRendering/displayImage'
10
+ import { EditSuggestionState } from '../../../../../src/app/inline/editSuggestionState'
11
+
12
+ // Shared helper function to create common stubs
13
+ function createCommonStubs ( sandbox : sinon . SinonSandbox ) {
14
+ const documentStub = {
15
+ getText : sandbox . stub ( ) . returns ( 'Original code content' ) ,
16
+ uri : vscode . Uri . file ( '/test/file.ts' ) ,
17
+ lineAt : sandbox . stub ( ) . returns ( {
18
+ text : 'Line text content' ,
19
+ range : new vscode . Range ( 0 , 0 , 0 , 18 ) ,
20
+ rangeIncludingLineBreak : new vscode . Range ( 0 , 0 , 0 , 19 ) ,
21
+ firstNonWhitespaceCharacterIndex : 0 ,
22
+ isEmptyOrWhitespace : false ,
23
+ } ) ,
24
+ } as unknown as sinon . SinonStubbedInstance < vscode . TextDocument >
25
+
26
+ const editorStub = {
27
+ document : documentStub ,
28
+ setDecorations : sandbox . stub ( ) ,
29
+ } as unknown as sinon . SinonStubbedInstance < vscode . TextEditor >
30
+
31
+ return { documentStub, editorStub }
32
+ }
10
33
11
34
describe ( 'EditDecorationManager' , function ( ) {
12
35
let sandbox : sinon . SinonSandbox
@@ -25,23 +48,13 @@ describe('EditDecorationManager', function () {
25
48
dispose : sandbox . stub ( ) ,
26
49
} as unknown as sinon . SinonStubbedInstance < vscode . TextEditorDecorationType >
27
50
28
- documentStub = {
29
- getText : sandbox . stub ( ) . returns ( 'Original code content' ) ,
30
- lineCount : 5 ,
31
- lineAt : sandbox . stub ( ) . returns ( {
32
- text : 'Line text content' ,
33
- range : new vscode . Range ( 0 , 0 , 0 , 18 ) ,
34
- rangeIncludingLineBreak : new vscode . Range ( 0 , 0 , 0 , 19 ) ,
35
- firstNonWhitespaceCharacterIndex : 0 ,
36
- isEmptyOrWhitespace : false ,
37
- } ) ,
38
- } as unknown as sinon . SinonStubbedInstance < vscode . TextDocument >
39
-
40
- editorStub = {
41
- document : documentStub ,
42
- setDecorations : sandbox . stub ( ) ,
43
- edit : sandbox . stub ( ) . resolves ( true ) ,
44
- } as unknown as sinon . SinonStubbedInstance < vscode . TextEditor >
51
+ const commonStubs = createCommonStubs ( sandbox )
52
+ documentStub = commonStubs . documentStub
53
+ editorStub = commonStubs . editorStub
54
+
55
+ // Add additional properties needed for this test suite - extend the stub objects
56
+ Object . assign ( documentStub , { lineCount : 5 } )
57
+ Object . assign ( editorStub , { edit : sandbox . stub ( ) . resolves ( true ) } )
45
58
46
59
windowStub = sandbox . stub ( vscode . window )
47
60
windowStub . createTextEditorDecorationType . returns ( decorationTypeStub as any )
@@ -174,3 +187,124 @@ describe('EditDecorationManager', function () {
174
187
sinon . assert . calledWith ( editorStub . setDecorations . secondCall , manager [ 'removedCodeDecorationType' ] , [ ] )
175
188
} )
176
189
} )
190
+
191
+ describe ( 'displaySvgDecoration cursor distance auto-reject' , function ( ) {
192
+ let sandbox : sinon . SinonSandbox
193
+ let editorStub : sinon . SinonStubbedInstance < vscode . TextEditor >
194
+ let windowStub : sinon . SinonStub
195
+ let commandsStub : sinon . SinonStub
196
+ let editSuggestionStateStub : sinon . SinonStub
197
+ let onDidChangeTextEditorSelectionStub : sinon . SinonStub
198
+ let selectionChangeListener : ( e : vscode . TextEditorSelectionChangeEvent ) => void
199
+
200
+ // Helper function to setup displaySvgDecoration
201
+ async function setupDisplaySvgDecoration ( startLine : number ) {
202
+ return await displaySvgDecoration (
203
+ editorStub as unknown as vscode . TextEditor ,
204
+ vscode . Uri . parse ( 'data:image/svg+xml;base64,test' ) ,
205
+ startLine ,
206
+ 'new code' ,
207
+ [ ] ,
208
+ { } as any ,
209
+ { } as any ,
210
+ { itemId : 'test' , insertText : 'patch' } as any
211
+ )
212
+ }
213
+
214
+ // Helper function to create selection change event
215
+ function createSelectionChangeEvent ( line : number ) : vscode . TextEditorSelectionChangeEvent {
216
+ const position = new vscode . Position ( line , 0 )
217
+ const selection = new vscode . Selection ( position , position )
218
+ return {
219
+ textEditor : editorStub ,
220
+ selections : [ selection ] ,
221
+ kind : vscode . TextEditorSelectionChangeKind . Mouse ,
222
+ } as vscode . TextEditorSelectionChangeEvent
223
+ }
224
+
225
+ beforeEach ( function ( ) {
226
+ sandbox = sinon . createSandbox ( )
227
+
228
+ const commonStubs = createCommonStubs ( sandbox )
229
+ editorStub = commonStubs . editorStub
230
+
231
+ // Mock vscode.window.onDidChangeTextEditorSelection
232
+ onDidChangeTextEditorSelectionStub = sandbox . stub ( )
233
+ onDidChangeTextEditorSelectionStub . returns ( { dispose : sandbox . stub ( ) } )
234
+ windowStub = sandbox . stub ( vscode . window , 'onDidChangeTextEditorSelection' )
235
+ windowStub . callsFake ( ( callback ) => {
236
+ selectionChangeListener = callback
237
+ return { dispose : sandbox . stub ( ) }
238
+ } )
239
+
240
+ // Mock vscode.commands.executeCommand
241
+ commandsStub = sandbox . stub ( vscode . commands , 'executeCommand' )
242
+
243
+ // Mock EditSuggestionState
244
+ editSuggestionStateStub = sandbox . stub ( EditSuggestionState , 'isEditSuggestionActive' )
245
+ editSuggestionStateStub . returns ( true )
246
+
247
+ // Mock other required dependencies
248
+ sandbox . stub ( vscode . workspace , 'onDidChangeTextDocument' ) . returns ( { dispose : sandbox . stub ( ) } )
249
+ } )
250
+
251
+ afterEach ( function ( ) {
252
+ sandbox . restore ( )
253
+ } )
254
+
255
+ it ( 'should not reject when cursor moves less than 25 lines away' , async function ( ) {
256
+ const startLine = 50
257
+ await setupDisplaySvgDecoration ( startLine )
258
+
259
+ selectionChangeListener ( createSelectionChangeEvent ( startLine + 24 ) )
260
+
261
+ sinon . assert . notCalled ( commandsStub )
262
+ } )
263
+
264
+ it ( 'should not reject when cursor moves exactly 25 lines away' , async function ( ) {
265
+ const startLine = 50
266
+ await setupDisplaySvgDecoration ( startLine )
267
+
268
+ selectionChangeListener ( createSelectionChangeEvent ( startLine + 25 ) )
269
+
270
+ sinon . assert . notCalled ( commandsStub )
271
+ } )
272
+
273
+ it ( 'should reject when cursor moves more than 25 lines away' , async function ( ) {
274
+ const startLine = 50
275
+ await setupDisplaySvgDecoration ( startLine )
276
+
277
+ selectionChangeListener ( createSelectionChangeEvent ( startLine + 26 ) )
278
+
279
+ sinon . assert . calledOnceWithExactly ( commandsStub , 'aws.amazonq.inline.rejectEdit' )
280
+ } )
281
+
282
+ it ( 'should reject when cursor moves more than 25 lines before the edit' , async function ( ) {
283
+ const startLine = 50
284
+ await setupDisplaySvgDecoration ( startLine )
285
+
286
+ selectionChangeListener ( createSelectionChangeEvent ( startLine - 26 ) )
287
+
288
+ sinon . assert . calledOnceWithExactly ( commandsStub , 'aws.amazonq.inline.rejectEdit' )
289
+ } )
290
+
291
+ it ( 'should not reject when edit is near beginning of file and cursor cannot move far enough' , async function ( ) {
292
+ const startLine = 10
293
+ await setupDisplaySvgDecoration ( startLine )
294
+
295
+ selectionChangeListener ( createSelectionChangeEvent ( 0 ) )
296
+
297
+ sinon . assert . notCalled ( commandsStub )
298
+ } )
299
+
300
+ it ( 'should not reject when edit suggestion is not active' , async function ( ) {
301
+ editSuggestionStateStub . returns ( false )
302
+
303
+ const startLine = 50
304
+ await setupDisplaySvgDecoration ( startLine )
305
+
306
+ selectionChangeListener ( createSelectionChangeEvent ( startLine + 100 ) )
307
+
308
+ sinon . assert . notCalled ( commandsStub )
309
+ } )
310
+ } )
0 commit comments