@@ -36,19 +36,20 @@ import * as vscode from 'vscode';
3636import { extensionContextFactory } from '../../../vscode-api/extension-context.factories' ;
3737import { commandsProviderFactory , MockCommandsProvider } from '../../../vscode-api/commands-provider.factories' ;
3838import { MergeCommand } from './merge-command' ;
39- import * as manifest from '../../../manifest' ;
4039import { COutlineItem } from '../tree-structure/solution-outline-item' ;
4140import * as child_process from 'child_process' ;
4241import * as os from 'os' ;
4342import * as path from 'path' ;
4443import * as fsUtils from '../../../utils/fs-utils' ;
44+ import { MergeSessionCoordinator } from './merge-session-coordinator' ;
4545
4646jest . mock ( 'child_process' ) ;
4747jest . mock ( 'os' ) ;
4848
4949describe ( 'MergeCommand' , ( ) => {
5050 let commandsProvider : MockCommandsProvider ;
5151 let command : MergeCommand ;
52+ let mergeSessionCoordinator : jest . Mocked < MergeSessionCoordinator > ;
5253 const testDataHandler = new TestDataHandler ( ) ;
5354 let tmpDir : string ;
5455
@@ -79,7 +80,12 @@ describe('MergeCommand', () => {
7980 fsUtils . writeTextFile ( path . join ( tmpDir , 'component.c.base@1.0.0' ) , '// base\n' ) ;
8081
8182 commandsProvider = commandsProviderFactory ( ) ;
82- command = new MergeCommand ( commandsProvider ) ;
83+ mergeSessionCoordinator = {
84+ activate : jest . fn ( ) . mockResolvedValue ( ) ,
85+ startSession : jest . fn ( ) ,
86+ onMergeProcessExit : jest . fn ( ) . mockResolvedValue ( ) ,
87+ } ;
88+ command = new MergeCommand ( commandsProvider , mergeSessionCoordinator ) ;
8389
8490 componentNode = new COutlineItem ( 'component' ) ;
8591 componentNode . setTag ( 'component' ) ;
@@ -98,6 +104,7 @@ describe('MergeCommand', () => {
98104 it ( 'registers the command on activation' , async ( ) => {
99105 await command . activate ( extensionContextFactory ( ) ) ;
100106
107+ expect ( mergeSessionCoordinator . activate ) . toHaveBeenCalledTimes ( 1 ) ;
101108 expect ( commandsProvider . registerCommand ) . toHaveBeenCalledTimes ( 1 ) ;
102109 expect ( commandsProvider . registerCommand ) . toHaveBeenCalledWith ( MergeCommand . mergeFile , expect . any ( Function ) , expect . anything ( ) ) ;
103110 } ) ;
@@ -337,13 +344,11 @@ describe('MergeCommand', () => {
337344 } ) ;
338345
339346 describe ( 'merge execution flow' , ( ) => {
340- it ( 'warns and skips post-merge file operations on non-zero merge exit code' , async ( ) => {
347+ it ( 'warns and delegates process exit handling on non-zero merge exit code' , async ( ) => {
341348 const commandPrivate = command as unknown as {
342349 getVSCodeExecutablePath : ( ) => string | undefined ;
343350 doOpen3WayMerge : ( cmd : string ) => Promise < number > ;
344351 } ;
345- const deleteFileIfExistsSpy = jest . spyOn ( fsUtils , 'deleteFileIfExists' ) ;
346- const renameFileSpy = jest . spyOn ( fsUtils , 'renameFile' ) ;
347352 jest . spyOn ( fsUtils , 'copyFile' ) . mockImplementation ( ( ) => { } ) ;
348353 jest . spyOn ( fsUtils , 'getFileModificationTime' ) . mockReturnValue ( 1000 ) ;
349354 jest . spyOn ( commandPrivate , 'getVSCodeExecutablePath' ) . mockReturnValue ( '/usr/bin/code' ) ;
@@ -354,9 +359,8 @@ describe('MergeCommand', () => {
354359 await command [ 'runVSCodeMerge' ] ( fileNode ) ;
355360
356361 expect ( warningSpy ) . toHaveBeenCalledWith ( 'Merge exited with code 1. Conflicts may exist.' ) ;
357- expect ( deleteFileIfExistsSpy ) . not . toHaveBeenCalled ( ) ;
358- expect ( renameFileSpy ) . not . toHaveBeenCalled ( ) ;
359- expect ( commandsProvider . executeCommand ) . not . toHaveBeenCalledWith ( manifest . REFRESH_COMMAND_ID ) ;
362+ expect ( mergeSessionCoordinator . startSession ) . toHaveBeenCalledTimes ( 1 ) ;
363+ expect ( mergeSessionCoordinator . onMergeProcessExit ) . toHaveBeenCalledWith ( 1 ) ;
360364 } ) ;
361365
362366 it ( 'handles merge errors gracefully' , async ( ) => {
@@ -400,12 +404,11 @@ describe('MergeCommand', () => {
400404 expect ( showErrorMessageSpy ) . toHaveBeenCalledWith ( 'Merge operation failed: Invalid update file: contains unsupported shell-sensitive characters.' ) ;
401405 } ) ;
402406
403- it ( 'performs post- merge file operations and triggers reload when merged file changes ' , async ( ) => {
407+ it ( 'starts merge session and notifies coordinator when merge exits successfully ' , async ( ) => {
404408 const local = path . join ( tmpDir , 'component.c' ) ;
405409 const update = path . join ( tmpDir , 'component.c.update@1.0.0' ) ;
406410 const base = path . join ( tmpDir , 'component.c.base@1.0.0' ) ;
407411 const merged = `${ local } .merged` ;
408- const expectedBase = path . join ( path . dirname ( update ) , path . basename ( update ) . replaceAll ( 'update' , 'base' ) ) ;
409412 const node = new COutlineItem ( 'file' ) ;
410413 node . setTag ( 'file' ) ;
411414 node . setAttribute ( 'label' , 'Component X' ) ;
@@ -417,24 +420,21 @@ describe('MergeCommand', () => {
417420 doOpen3WayMerge : ( cmd : string ) => Promise < number > ;
418421 } ;
419422 const copyFileSpy = jest . spyOn ( fsUtils , 'copyFile' ) . mockImplementation ( ( ) => { } ) ;
420- const getFileModificationTimeSpy = jest . spyOn ( fsUtils , 'getFileModificationTime' )
421- . mockReturnValueOnce ( 1000 )
422- . mockReturnValueOnce ( 2000 ) ;
423- const deleteFileIfExistsSpy = jest . spyOn ( fsUtils , 'deleteFileIfExists' ) . mockImplementation ( ( ) => { } ) ;
424- const renameFileSpy = jest . spyOn ( fsUtils , 'renameFile' ) . mockImplementation ( ( ) => { } ) ;
423+ jest . spyOn ( fsUtils , 'getFileModificationTime' ) . mockReturnValue ( 1000 ) ;
425424 jest . spyOn ( commandPrivate , 'getVSCodeExecutablePath' ) . mockReturnValue ( '/usr/bin/code' ) ;
426425 jest . spyOn ( commandPrivate , 'doOpen3WayMerge' ) . mockResolvedValue ( 0 ) ;
427426
428427 await command [ 'runVSCodeMerge' ] ( node ) ;
429428
430429 expect ( copyFileSpy ) . toHaveBeenCalledWith ( local , merged ) ;
431- expect ( copyFileSpy ) . toHaveBeenCalledWith ( local , `${ local } .bak` ) ;
432- expect ( getFileModificationTimeSpy ) . toHaveBeenCalledTimes ( 2 ) ;
433- expect ( deleteFileIfExistsSpy ) . toHaveBeenCalledWith ( local ) ;
434- expect ( deleteFileIfExistsSpy ) . toHaveBeenCalledWith ( base ) ;
435- expect ( renameFileSpy ) . toHaveBeenCalledWith ( update , expectedBase ) ;
436- expect ( renameFileSpy ) . toHaveBeenCalledWith ( merged , local ) ;
437- expect ( commandsProvider . executeCommand ) . toHaveBeenCalledWith ( manifest . REFRESH_COMMAND_ID ) ;
430+ expect ( mergeSessionCoordinator . startSession ) . toHaveBeenCalledWith ( {
431+ local,
432+ update,
433+ base,
434+ merged,
435+ mergedMTimeBefore : 1000 ,
436+ } ) ;
437+ expect ( mergeSessionCoordinator . onMergeProcessExit ) . toHaveBeenCalledWith ( 0 ) ;
438438 } ) ;
439439 } ) ;
440440} ) ;
0 commit comments