@@ -19,7 +19,7 @@ import {
1919 handleDeleteLines ,
2020 handleHighlightLines ,
2121} from '@/editing' ;
22- import { createTestFile , checkNoErrorWithTimeout } from '../../test_utils' ;
22+ import { createTestFile , checkNoErrorWithTimeout , setupDocument } from '../../test_utils' ;
2323
2424import { NeuroClient } from 'neuro-game-sdk' ;
2525
@@ -54,16 +54,8 @@ suite('Integration: Editing actions', () => {
5454 } ) ;
5555
5656 setup ( async ( ) => {
57- // Ensure every test starts from the same content and cursor position
58- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : initialContent } } as ActionData ) ;
59- await checkNoErrorWithTimeout ( async ( ) => {
60- const t = ( await vscode . workspace . openTextDocument ( docUri ) ) . getText ( ) ;
61- assert . strictEqual ( t , initialContent ) ;
62- } , 5000 , 100 ) ;
63- // Clear any sendContext calls from the reset
64- reset ( mockedClient ) ;
65- // Establish a consistent cursor baseline for tests that read it
66- handlePlaceCursor ( { id : 't' , name : 'place_cursor' , params : { line : 2 , column : 1 , type : 'absolute' } } as ActionData ) ;
57+ // Ensure every test starts from the same content and cursor position (2:1)
58+ await setupDocument ( initialContent , { cursorPosition : new vscode . Position ( 1 , 0 ) } ) ;
6759 } ) ;
6860
6961 suiteTeardown ( ( ) => {
@@ -90,7 +82,7 @@ suite('Integration: Editing actions', () => {
9082
9183 test ( 'get_cursor returns current position and context' , ( ) => {
9284 // === Act ===
93- const result = handleGetCursor ( { id : 't' , name : 'get_cursor' } as ActionData ) ;
85+ const result = handleGetCursor ( { id : 't' , name : 'get_cursor' } ) ;
9486
9587 // === Assert ===
9688 assert . ok ( result && result . includes ( '2:1' ) ) ;
@@ -149,10 +141,7 @@ suite('Integration: Editing actions', () => {
149141 test ( 'insert_text supports relative position' , async ( ) => {
150142 // === Arrange ===
151143 // Place at start of file, then insert relative
152- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : [ 'Aaa' , 'Bbb' , 'Ccc' ] . join ( '\n' ) } } as ActionData ) ;
153- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
154- reset ( mockedClient ) ;
155- handlePlaceCursor ( { id : 't' , name : 'place_cursor' , params : { line : 1 , column : 1 , type : 'absolute' } } ) ;
144+ await setupDocument ( 'Aaa\nBbb\nCcc' ) ;
156145 const ad : ActionData = { id : 't' , name : 'insert_text' , params : { text : '-' , position : { line : 1 , column : 2 , type : 'relative' } } } ;
157146
158147 // === Act ===
@@ -182,12 +171,10 @@ suite('Integration: Editing actions', () => {
182171 test ( 'insert_lines inserts beyond EOF by padding newlines' , async ( ) => {
183172 // === Arrange ===
184173 // Reset to small file
185- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : [ 'A' , 'B' ] . join ( '\n' ) } } as ActionData ) ;
186- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
187- reset ( mockedClient ) ;
174+ await setupDocument ( 'A\nB' ) ;
188175
189176 // === Act ===
190- handleInsertLines ( { id : 't' , name : 'insert_lines' , params : { text : 'C' , insertUnder : 6 } } as ActionData ) ;
177+ handleInsertLines ( { id : 't' , name : 'insert_lines' , params : { text : 'C' , insertUnder : 6 } } ) ;
191178
192179 // === Assert ===
193180 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
@@ -212,10 +199,7 @@ suite('Integration: Editing actions', () => {
212199
213200 test ( 'replace_text supports regex substitution and allInFile' , async ( ) => {
214201 // === Arrange ===
215- const content = [ 'foo1' , 'foo2' , 'bar3' ] . join ( '\n' ) ;
216- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
217- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 5000 , 100 ) ;
218- reset ( mockedClient ) ;
202+ await setupDocument ( 'foo1\nfoo2\nbar3' ) ;
219203 const actionData : ActionData = { id : 't' , name : 'replace_text' , params : { find : '(foo)(\\d)' , replaceWith : '$1X' , match : 'allInFile' , useRegex : true } } ;
220204
221205 // === Act ===
@@ -229,10 +213,7 @@ suite('Integration: Editing actions', () => {
229213
230214 test ( 'replace_text respects lineRange' , async ( ) => {
231215 // === Arrange ===
232- const content = [ 'a' , 'a' , 'a' ] . join ( '\n' ) ;
233- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
234- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
235- reset ( mockedClient ) ;
216+ await setupDocument ( 'a\na\na' ) ;
236217
237218 // === Act ===
238219 handleReplaceText ( { id : 't' , name : 'replace_text' , params : { find : 'a' , replaceWith : 'b' , match : 'allInFile' , useRegex : false , lineRange : { startLine : 2 , endLine : 3 } } } ) ;
@@ -259,10 +240,7 @@ suite('Integration: Editing actions', () => {
259240 test ( 'delete_text deletes multiple matches and can use lineRange' , async function ( ) {
260241 // === Arrange ===
261242 // Multiple delete
262- const content = 'x 1 x 2 x' ;
263- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
264- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 5000 , 100 ) ;
265- reset ( mockedClient ) ;
243+ await setupDocument ( 'x 1 x 2 x' ) ;
266244
267245 // === Act ===
268246 handleDeleteText ( { id : 't' , name : 'delete_text' , params : { find : 'x' , match : 'allInFile' , useRegex : false } } ) ;
@@ -278,13 +256,7 @@ suite('Integration: Editing actions', () => {
278256
279257 // === Arrange ===
280258 // Range-limited delete
281- const content2 = [ 'p' , 'q' , 'p' , 'q' ] . join ( '\n' ) ;
282- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : content2 } } as ActionData ) ;
283- await checkNoErrorWithTimeout ( async ( ) => {
284- const t = vscode . window . activeTextEditor ?. document . getText ( ) ?? '' ;
285- assert . strictEqual ( t , content2 ) ;
286- } , 5000 , 100 ) ;
287- reset ( mockedClient ) ;
259+ await setupDocument ( 'p\nq\np\nq' ) ;
288260
289261 // === Act ===
290262 handleDeleteText ( { id : 't' , name : 'delete_text' , params : { find : 'p' , match : 'allInFile' , useRegex : false , lineRange : { startLine : 2 , endLine : 3 } } } ) ;
@@ -308,13 +280,7 @@ suite('Integration: Editing actions', () => {
308280
309281 test ( 'find_text single match returns description string' , async ( ) => {
310282 // === Arrange ===
311- const content = [ 'Echo' , 'Zulu' ] . join ( '\n' ) ;
312- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
313- // Ensure rewrite_all applied before running find
314- await checkNoErrorWithTimeout ( async ( ) => {
315- const t = ( await vscode . workspace . openTextDocument ( docUri ) ) . getText ( ) ;
316- assert . strictEqual ( t , content ) ;
317- } , 5000 , 100 ) ;
283+ await setupDocument ( 'Echo\nZulu' ) ;
318284 const actionData : ActionData = { id : 't' , name : 'find_text' , params : { find : 'Echo' , match : 'firstInFile' , useRegex : false , highlight : false } } ;
319285 // === Act & Assert ===
320286 const result = handleFindText ( actionData ) ;
@@ -323,12 +289,8 @@ suite('Integration: Editing actions', () => {
323289
324290 test ( 'find_text multiple matches with highlight returns count and lines' , async ( ) => {
325291 // === Arrange ===
326- const content = [ 'z' , 'z' , 'z' ] . join ( '\n' ) ;
327- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
328- await checkNoErrorWithTimeout ( async ( ) => {
329- const t = ( await vscode . workspace . openTextDocument ( docUri ) ) . getText ( ) ;
330- assert . strictEqual ( t , content ) ;
331- } , 5000 , 100 ) ;
292+ await setupDocument ( 'z\nz\nz' ) ;
293+
332294 // === Act & Assert ===
333295 const result = handleFindText ( { id : 't' , name : 'find_text' , params : { find : 'z' , match : 'allInFile' , useRegex : false , highlight : true } } ) ;
334296 assert . ok ( typeof result === 'string' && result . includes ( 'z' ) ) ;
@@ -343,7 +305,7 @@ suite('Integration: Editing actions', () => {
343305 await vscode . workspace . applyEdit ( edit ) ;
344306
345307 // === Act ===
346- handleUndo ( { id : 't' , name : 'undo' } as ActionData ) ;
308+ handleUndo ( { id : 't' , name : 'undo' } ) ;
347309
348310 // === Assert ===
349311 // Poll until content equals baseline
@@ -361,7 +323,7 @@ suite('Integration: Editing actions', () => {
361323 await vscode . workspace . applyEdit ( edit ) ;
362324
363325 // === Act ===
364- handleSave ( { id : 't' , name : 'save' } as ActionData ) ;
326+ handleSave ( { id : 't' , name : 'save' } ) ;
365327
366328 // === Assert ===
367329 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) , anything ( ) ) ) . once ( ) ; } , 5000 , 100 ) ;
@@ -372,7 +334,7 @@ suite('Integration: Editing actions', () => {
372334 const newContent = [ 'One' , 'Two' , 'Three' ] . join ( '\n' ) ;
373335
374336 // === Act ===
375- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } as ActionData ) ;
337+ handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } ) ;
376338
377339 // === Assert ===
378340 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
@@ -385,11 +347,11 @@ suite('Integration: Editing actions', () => {
385347 const newContent = [ 'X1' , 'X2' ] . join ( '\n' ) ;
386348
387349 // === Act ===
388- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } as ActionData ) ;
350+ handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } ) ;
389351
390352 // === Assert ===
391353 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
392- const cursorInfo = handleGetCursor ( { id : 't' , name : 'get_cursor' } as ActionData ) as string ;
354+ const cursorInfo = handleGetCursor ( { id : 't' , name : 'get_cursor' } ) ! ;
393355 assert . ok ( cursorInfo . includes ( '1:1' ) ) ;
394356 } ) ;
395357
@@ -398,7 +360,7 @@ suite('Integration: Editing actions', () => {
398360 const newContent = '' ;
399361
400362 // === Act ===
401- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } as ActionData ) ;
363+ handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } ) ;
402364
403365 // === Assert ===
404366 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
@@ -411,7 +373,7 @@ suite('Integration: Editing actions', () => {
411373 const newContent = Array . from ( { length : 500 } , ( _ , i ) => `L ${ i + 1 } ` ) . join ( '\n' ) ;
412374
413375 // === Act ===
414- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } as ActionData ) ;
376+ handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : newContent } } ) ;
415377
416378 // === Assert ===
417379 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 5000 , 100 ) ;
@@ -422,13 +384,10 @@ suite('Integration: Editing actions', () => {
422384
423385 test ( 'rewrite_lines replaces a range and sends context; delete_lines removes a range and sends context' , async ( ) => {
424386 // === Arrange ===
425- const resetContent = [ 'L1' , 'L2' , 'L3' , 'L4' , 'L5' ] . join ( '\n' ) ;
426- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : resetContent } } as ActionData ) ;
427- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
428- reset ( mockedClient ) ;
387+ await setupDocument ( 'L1\nL2\nL3\nL4\nL5' ) ;
429388
430389 // === Act ===
431- handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'X\nY' } } as ActionData ) ;
390+ handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'X\nY' } } ) ;
432391
433392 // === Assert ===
434393 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
@@ -440,7 +399,7 @@ suite('Integration: Editing actions', () => {
440399 reset ( mockedClient ) ;
441400
442401 // === Act ===
443- handleDeleteLines ( { id : 't' , name : 'delete_lines' , params : { startLine : 4 , endLine : 4 } } as ActionData ) ;
402+ handleDeleteLines ( { id : 't' , name : 'delete_lines' , params : { startLine : 4 , endLine : 4 } } ) ;
444403
445404 // === Assert ===
446405 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
@@ -449,56 +408,47 @@ suite('Integration: Editing actions', () => {
449408 } ) ;
450409
451410 test ( 'rewrite_lines cursor position depends on trailing newline' , async ( ) => {
452- // === Arrange ===
453- reset ( mockedClient ) ;
454-
455411 // With trailing newline: logicalLines = 1, cursor ends on line 2
456412 // === Act ===
457- handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'X\n' } } as ActionData ) ;
413+ handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'X\n' } } ) ;
458414
459415 // === Assert ===
460416 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
461- let info = handleGetCursor ( { id : 't' , name : 'get_cursor' } as ActionData ) as string ;
417+ let info = handleGetCursor ( { id : 't' , name : 'get_cursor' } ) ! ;
462418 assert . ok ( info . includes ( '2:' ) ) ;
463419
464420 // Without trailing newline: logicalLines = 2, cursor ends on line 3
465- reset ( mockedClient ) ;
466421 // === Arrange ===
467422 reset ( mockedClient ) ;
468423
469424 // === Act ===
470- handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'Y\nZ' } } as ActionData ) ;
425+ handleRewriteLines ( { id : 't' , name : 'rewrite_lines' , params : { startLine : 2 , endLine : 3 , content : 'Y\nZ' } } ) ;
471426
472427 // === Assert ===
473428 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
474- info = handleGetCursor ( { id : 't' , name : 'get_cursor' } as ActionData ) as string ;
429+ info = handleGetCursor ( { id : 't' , name : 'get_cursor' } ) ! ;
475430 assert . ok ( info . includes ( '3:' ) ) ;
476431 } ) ;
477432
478433 test ( 'delete_lines from first line moves cursor to start of file' , async ( ) => {
479434 // === Arrange ===
480- const content = [ 'A' , 'B' , 'C' ] . join ( '\n' ) ;
481- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content } } as ActionData ) ;
482- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
483- reset ( mockedClient ) ;
435+ await setupDocument ( 'A\nB\nC' , { cursorPosition : new vscode . Position ( 2 , 0 ) } ) ; // Cursor at (3:1)
484436
485437 // === Act ===
486- handleDeleteLines ( { id : 't' , name : 'delete_lines' , params : { startLine : 1 , endLine : 2 } } as ActionData ) ;
438+ handleDeleteLines ( { id : 't' , name : 'delete_lines' , params : { startLine : 1 , endLine : 2 } } ) ;
487439
488440 // === Assert ===
489441 await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 3000 , 100 ) ;
490- const info = handleGetCursor ( { id : 't' , name : 'get_cursor' } as ActionData ) as string ;
442+ const info = handleGetCursor ( { id : 't' , name : 'get_cursor' } ) ! ;
491443 assert . ok ( info . includes ( '1:1' ) ) ;
492444 } ) ;
493445
494446 test ( 'highlight_lines returns description string' , async function ( ) {
495447 // === Arrange ===
496448 // Ensure at least two lines exist for the highlight range
497- const resetContent = [ 'H1' , 'H2' ] . join ( '\n' ) ;
498- handleRewriteAll ( { id : 't' , name : 'rewrite_all' , params : { content : resetContent } } as ActionData ) ;
499- await checkNoErrorWithTimeout ( ( ) => { verify ( mockedClient . sendContext ( anything ( ) ) ) . once ( ) ; } , 5000 , 100 ) ;
449+ await setupDocument ( 'H1\nH2' ) ;
500450 // === Act & Assert ===
501- const result = handleHighlightLines ( { id : 't' , name : 'highlight_lines' , params : { startLine : 1 , endLine : 2 } } as ActionData ) ;
451+ const result = handleHighlightLines ( { id : 't' , name : 'highlight_lines' , params : { startLine : 1 , endLine : 2 } } ) ;
502452 assert . ok ( typeof result === 'string' && result . includes ( '1-2' ) ) ;
503453 } ) ;
504454} ) ;
0 commit comments