@@ -231,6 +231,39 @@ assert.equal(shell.error(), null); // crash test only
231231assert . ok ( ! result . stderr ) ;
232232assert . equal ( result . code , 0 ) ;
233233
234+ if ( process . platform !== 'win32' ) {
235+ // Recursive, everything exists, overwrite a real file with a link (if same name)
236+ // Because -R implies to not follow links!
237+ shell . rm ( '-rf' , 'tmp/*' ) ;
238+ shell . cp ( '-R' , 'resources/cp/*' , 'tmp' ) ;
239+ assert . ok ( fs . lstatSync ( 'tmp/links/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is a link
240+ assert . ok ( ! ( fs . lstatSync ( 'tmp/fakeLinks/sym.lnk' ) . isSymbolicLink ( ) ) ) ; // this one isn't
241+ assert . notEqual ( shell . cat ( 'tmp/links/sym.lnk' ) . toString ( ) , shell . cat ( 'tmp/fakeLinks/sym.lnk' ) . toString ( ) ) ;
242+ result = shell . cp ( '-R' , 'tmp/links/*' , 'tmp/fakeLinks' ) ;
243+ assert . equal ( shell . error ( ) , null ) ;
244+ assert . ok ( ! result . stderr ) ;
245+ assert . equal ( result . code , 0 ) ;
246+ assert . ok ( fs . lstatSync ( 'tmp/links/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is a link
247+ assert . ok ( fs . lstatSync ( 'tmp/fakeLinks/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is now a link
248+ assert . equal ( shell . cat ( 'tmp/links/sym.lnk' ) . toString ( ) , shell . cat ( 'tmp/fakeLinks/sym.lnk' ) . toString ( ) ) ;
249+
250+ // Recursive, everything exists, overwrite a real file *by following a link*
251+ // Because missing the -R implies -L.
252+ shell . rm ( '-rf' , 'tmp/*' ) ;
253+ shell . cp ( '-R' , 'resources/cp/*' , 'tmp' ) ;
254+ assert . ok ( fs . lstatSync ( 'tmp/links/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is a link
255+ assert . ok ( ! ( fs . lstatSync ( 'tmp/fakeLinks/sym.lnk' ) . isSymbolicLink ( ) ) ) ; // this one isn't
256+ assert . notEqual ( shell . cat ( 'tmp/links/sym.lnk' ) . toString ( ) , shell . cat ( 'tmp/fakeLinks/sym.lnk' ) . toString ( ) ) ;
257+ result = shell . cp ( 'tmp/links/*' , 'tmp/fakeLinks' ) ; // don't use -R
258+ assert . equal ( shell . error ( ) , null ) ;
259+ assert . ok ( ! result . stderr ) ;
260+ assert . equal ( result . code , 0 ) ;
261+ assert . ok ( fs . lstatSync ( 'tmp/links/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is a link
262+ assert . ok ( ! fs . lstatSync ( 'tmp/fakeLinks/sym.lnk' ) . isSymbolicLink ( ) ) ; // this one is still not a link
263+ // But it still follows the link
264+ assert . equal ( shell . cat ( 'tmp/links/sym.lnk' ) . toString ( ) , shell . cat ( 'tmp/fakeLinks/sym.lnk' ) . toString ( ) ) ;
265+ }
266+
234267//recursive, everything exists, with force flag
235268shell . rm ( '-rf' , 'tmp/*' ) ;
236269result = shell . cp ( '-R' , 'resources/cp' , 'tmp' ) ;
@@ -275,12 +308,12 @@ assert.equal(fs.existsSync('tmp/dest/z'), true);
275308
276309// On Windows, permission bits are quite different so skip those tests for now
277310if ( common . platform !== 'win' ) {
278- //preserve mode bits
279- shell . rm ( '-rf' , 'tmp/*' ) ;
280- var execBit = parseInt ( '001' , 8 ) ;
281- assert . equal ( fs . statSync ( 'resources/cp-mode-bits/executable' ) . mode & execBit , execBit ) ;
282- shell . cp ( 'resources/cp-mode-bits/executable' , 'tmp/executable' ) ;
283- assert . equal ( fs . statSync ( 'resources/cp-mode-bits/executable' ) . mode , fs . statSync ( 'tmp/executable' ) . mode ) ;
311+ //preserve mode bits
312+ shell . rm ( '-rf' , 'tmp/*' ) ;
313+ var execBit = parseInt ( '001' , 8 ) ;
314+ assert . equal ( fs . statSync ( 'resources/cp-mode-bits/executable' ) . mode & execBit , execBit ) ;
315+ shell . cp ( 'resources/cp-mode-bits/executable' , 'tmp/executable' ) ;
316+ assert . equal ( fs . statSync ( 'resources/cp-mode-bits/executable' ) . mode , fs . statSync ( 'tmp/executable' ) . mode ) ;
284317}
285318
286319// Make sure hidden files are copied recursively
@@ -304,7 +337,7 @@ assert.ok(fs.existsSync('tmp/file1.txt'));
304337shell . rm ( '-rf' , 'tmp/' ) ;
305338shell . mkdir ( 'tmp/' ) ;
306339result = shell . cp ( 'resources/file1.txt' , 'resources/file2.txt' , 'resources/cp' ,
307- 'resources/ls/' , 'tmp/' ) ;
340+ 'resources/ls/' , 'tmp/' ) ;
308341assert . ok ( shell . error ( ) ) ;
309342assert . ok ( ! fs . existsSync ( 'tmp/.hidden_file' ) ) ; // doesn't copy dir contents
310343assert . ok ( ! fs . existsSync ( 'tmp/ls' ) ) ; // doesn't copy dir itself
@@ -313,13 +346,67 @@ assert.ok(!fs.existsSync('tmp/cp')); // doesn't copy dir itself
313346assert . ok ( fs . existsSync ( 'tmp/file1.txt' ) ) ;
314347assert . ok ( fs . existsSync ( 'tmp/file2.txt' ) ) ;
315348
316- // Recursive, copies entire directory with no symlinks and -L option does not cause change in behavior.
349+ if ( process . platform !== 'win32' ) {
350+ // -R implies -P
351+ shell . rm ( '-rf' , 'tmp/*' ) ;
352+ shell . cp ( '-R' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
353+ assert . ok ( fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
354+
355+ // using -P explicitly works
356+ shell . rm ( '-rf' , 'tmp/*' ) ;
357+ shell . cp ( '-P' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
358+ assert . ok ( fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
359+
360+ // using -PR on a link to a folder does not follow the link
361+ shell . rm ( '-rf' , 'tmp/*' ) ;
362+ shell . cp ( '-PR' , 'resources/cp/symFolder' , 'tmp' ) ;
363+ assert . ok ( fs . lstatSync ( 'tmp/symFolder' ) . isSymbolicLink ( ) ) ;
364+
365+ // Recursive, copies entire directory with no symlinks and -L option does not cause change in behavior.
366+ shell . rm ( '-rf' , 'tmp/*' ) ;
367+ result = shell . cp ( '-rL' , 'resources/cp/dir_a' , 'tmp/dest' ) ;
368+ assert . equal ( shell . error ( ) , null ) ;
369+ assert . ok ( ! result . stderr ) ;
370+ assert . equal ( result . code , 0 ) ;
371+ assert . equal ( fs . existsSync ( 'tmp/dest/z' ) , true ) ;
372+ }
373+
374+ // using -R on a link to a folder *does* follow the link
317375shell . rm ( '-rf' , 'tmp/*' ) ;
318- result = shell . cp ( '-rL' , 'resources/cp/dir_a' , 'tmp/dest' ) ;
319- assert . equal ( shell . error ( ) , null ) ;
320- assert . ok ( ! result . stderr ) ;
321- assert . equal ( result . code , 0 ) ;
322- assert . equal ( fs . existsSync ( 'tmp/dest/z' ) , true ) ;
376+ shell . cp ( '-R' , 'resources/cp/symFolder' , 'tmp' ) ;
377+ assert . ok ( ! fs . lstatSync ( 'tmp/symFolder' ) . isSymbolicLink ( ) ) ;
378+
379+ // Without -R, -L is implied
380+ shell . rm ( '-rf' , 'tmp/*' ) ;
381+ shell . cp ( 'resources/cp/links/sym.lnk' , 'tmp' ) ;
382+ assert . ok ( ! fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
383+
384+ // -L explicitly works
385+ shell . rm ( '-rf' , 'tmp/*' ) ;
386+ shell . cp ( '-L' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
387+ assert . ok ( ! fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
388+
389+ // using -LR does not imply -P
390+ shell . rm ( '-rf' , 'tmp/*' ) ;
391+ shell . cp ( '-LR' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
392+ assert . ok ( ! fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
393+
394+ // using -LR also works recursively on directories containing links
395+ shell . rm ( '-rf' , 'tmp/*' ) ;
396+ shell . cp ( '-LR' , 'resources/cp/links' , 'tmp' ) ;
397+ assert . ok ( ! fs . lstatSync ( 'tmp/links/sym.lnk' ) . isSymbolicLink ( ) ) ;
398+
399+ // -L always overrides a -P
400+ shell . rm ( '-rf' , 'tmp/*' ) ;
401+ shell . cp ( '-LP' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
402+ assert . ok ( ! fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
403+ shell . rm ( '-rf' , 'tmp/*' ) ;
404+ shell . cp ( '-LPR' , 'resources/cp/links/sym.lnk' , 'tmp' ) ;
405+ assert . ok ( ! fs . lstatSync ( 'tmp/sym.lnk' ) . isSymbolicLink ( ) ) ;
406+ shell . rm ( '-rf' , 'tmp/*' ) ;
407+ shell . cp ( '-LPR' , 'resources/cp/symFolder' , 'tmp' ) ;
408+ assert . ok ( ! fs . lstatSync ( 'tmp/symFolder' ) . isSymbolicLink ( ) ) ;
409+ assert . ok ( ! fs . lstatSync ( 'tmp/symFolder/sym.lnk' ) . isSymbolicLink ( ) ) ;
323410
324411// Test max depth.
325412shell . rm ( '-rf' , 'tmp/' ) ;
0 commit comments