@@ -322,6 +322,74 @@ describe('FilePatchController', function() {
322
322
}
323
323
}
324
324
325
+ it ( 'unstages added lines that don\'t require symlink change' , async function ( ) {
326
+ const workingDirPath = await cloneRepository ( 'symlinks' ) ;
327
+ const repository = await buildRepository ( workingDirPath ) ;
328
+
329
+ // correctly handle symlinks on Windows
330
+ repository . git . exec ( [ 'config' , 'core.symlinks' , 'true' ] ) ;
331
+
332
+ const deletedSymlinkAddedFilePath = 'symlink.txt' ;
333
+ fs . unlinkSync ( path . join ( workingDirPath , deletedSymlinkAddedFilePath ) ) ;
334
+ fs . writeFileSync ( path . join ( workingDirPath , deletedSymlinkAddedFilePath ) , 'qux\nfoo\nbar\nbaz\nzoo\n' , 'utf8' ) ;
335
+
336
+ // Stage whole file
337
+ await repository . stageFiles ( [ deletedSymlinkAddedFilePath ] ) ;
338
+
339
+ const component = createComponent ( repository , deletedSymlinkAddedFilePath ) ;
340
+ const wrapper = mount ( React . cloneElement ( component , { filePath : deletedSymlinkAddedFilePath , initialStagingStatus : 'staged' } ) ) ;
341
+
342
+ // index shows symlink deltion and added lines
343
+ assert . autocrlfEqual ( await repository . readFileFromIndex ( deletedSymlinkAddedFilePath ) , 'qux\nfoo\nbar\nbaz\nzoo\n' ) ;
344
+ assert . equal ( ( await indexModeAndOid ( repository , deletedSymlinkAddedFilePath ) ) . mode , '100644' ) ;
345
+
346
+ // Unstage a couple added lines, but not all
347
+ await assert . async . isTrue ( wrapper . find ( 'HunkView' ) . exists ( ) ) ;
348
+ const opPromise0 = switchboard . getFinishStageOperationPromise ( ) ;
349
+ const hunkView0 = wrapper . find ( 'HunkView' ) . at ( 0 ) ;
350
+ hunkView0 . find ( 'LineView' ) . at ( 1 ) . find ( '.github-HunkView-line' ) . simulate ( 'mousedown' , { button : 0 , detail : 1 } ) ;
351
+ hunkView0 . find ( 'LineView' ) . at ( 2 ) . find ( '.github-HunkView-line' ) . simulate ( 'mousemove' , { } ) ;
352
+ window . dispatchEvent ( new MouseEvent ( 'mouseup' ) ) ;
353
+ hunkView0 . find ( 'button.github-HunkView-stageButton' ) . simulate ( 'click' ) ;
354
+ await opPromise0 ;
355
+
356
+ repository . refresh ( ) ;
357
+ // index shows symlink deletions still staged, only a couple of lines have been unstaged
358
+ assert . equal ( ( await indexModeAndOid ( repository , deletedSymlinkAddedFilePath ) ) . mode , '100644' ) ;
359
+ assert . autocrlfEqual ( await repository . readFileFromIndex ( deletedSymlinkAddedFilePath ) , 'qux\nbaz\nzoo\n' ) ;
360
+ } ) ;
361
+
362
+ it ( 'stages deleted lines that don\'t require symlink change' , async function ( ) {
363
+ const workingDirPath = await cloneRepository ( 'symlinks' ) ;
364
+ const repository = await buildRepository ( workingDirPath ) ;
365
+
366
+ const deletedFileAddedSymlinkPath = 'a.txt' ;
367
+ fs . unlinkSync ( path . join ( workingDirPath , deletedFileAddedSymlinkPath ) ) ;
368
+ fs . symlinkSync ( path . join ( workingDirPath , 'regular-file.txt' ) , path . join ( workingDirPath , deletedFileAddedSymlinkPath ) ) ;
369
+
370
+ const component = createComponent ( repository , deletedFileAddedSymlinkPath ) ;
371
+ const wrapper = mount ( React . cloneElement ( component , { filePath : deletedFileAddedSymlinkPath , initialStagingStatus : 'unstaged' } ) ) ;
372
+
373
+ // index shows file is not a symlink, no deleted lines
374
+ assert . equal ( ( await indexModeAndOid ( repository , deletedFileAddedSymlinkPath ) ) . mode , '100644' ) ;
375
+ assert . autocrlfEqual ( await repository . readFileFromIndex ( deletedFileAddedSymlinkPath ) , 'foo\nbar\nbaz\n\n' ) ;
376
+
377
+ // stage a couple of lines, but not all
378
+ await assert . async . isTrue ( wrapper . find ( 'HunkView' ) . exists ( ) ) ;
379
+ const opPromise0 = switchboard . getFinishStageOperationPromise ( ) ;
380
+ const hunkView0 = wrapper . find ( 'HunkView' ) . at ( 0 ) ;
381
+ hunkView0 . find ( 'LineView' ) . at ( 1 ) . find ( '.github-HunkView-line' ) . simulate ( 'mousedown' , { button : 0 , detail : 1 } ) ;
382
+ hunkView0 . find ( 'LineView' ) . at ( 2 ) . find ( '.github-HunkView-line' ) . simulate ( 'mousemove' , { } ) ;
383
+ window . dispatchEvent ( new MouseEvent ( 'mouseup' ) ) ;
384
+ hunkView0 . find ( 'button.github-HunkView-stageButton' ) . simulate ( 'click' ) ;
385
+ await opPromise0 ;
386
+
387
+ repository . refresh ( ) ;
388
+ // index shows symlink change has not been staged, a couple of lines have been deleted
389
+ assert . equal ( ( await indexModeAndOid ( repository , deletedFileAddedSymlinkPath ) ) . mode , '100644' ) ;
390
+ assert . autocrlfEqual ( await repository . readFileFromIndex ( deletedFileAddedSymlinkPath ) , 'foo\n\n' ) ;
391
+ } ) ;
392
+
325
393
it ( 'stages symlink change when staging added lines that depend on change' , async function ( ) {
326
394
const workingDirPath = await cloneRepository ( 'symlinks' ) ;
327
395
const repository = await buildRepository ( workingDirPath ) ;
0 commit comments