@@ -38,6 +38,30 @@ function nextdir() {
3838 assertDirEquivalent ( src , dest ) ;
3939}
4040
41+ // It copies a nested folder structure with mode flags.
42+ // This test is based on fs.promises.copyFile() with `COPYFILE_FICLONE_FORCE`.
43+ ( ( ) => {
44+ const src = './test/fixtures/copy/kitchen-sink' ;
45+ const dest = nextdir ( ) ;
46+ try {
47+ cpSync ( src , dest , mustNotMutateObjectDeep ( {
48+ recursive : true ,
49+ mode : fs . constants . COPYFILE_FICLONE_FORCE ,
50+ } ) ) ;
51+ } catch ( err ) {
52+ // If the platform does not support `COPYFILE_FICLONE_FORCE` operation,
53+ // it should enter this path.
54+ assert . strictEqual ( err . syscall , 'copyfile' ) ;
55+ assert ( err . code === 'ENOTSUP' || err . code === 'ENOTTY' ||
56+ err . code === 'ENOSYS' || err . code === 'EXDEV' ) ;
57+ return ;
58+ }
59+
60+ // If the platform support `COPYFILE_FICLONE_FORCE` operation,
61+ // it should reach to here.
62+ assertDirEquivalent ( src , dest ) ;
63+ } ) ( ) ;
64+
4165// It does not throw errors when directory is copied over and force is false.
4266{
4367 const src = nextdir ( ) ;
@@ -107,6 +131,14 @@ function nextdir() {
107131 } ) ;
108132}
109133
134+ // It rejects if options.mode is invalid.
135+ {
136+ assert . throws (
137+ ( ) => cpSync ( 'a' , 'b' , { mode : - 1 } ) ,
138+ { code : 'ERR_OUT_OF_RANGE' }
139+ ) ;
140+ }
141+
110142
111143// It throws an error when both dereference and verbatimSymlinks are enabled.
112144{
@@ -425,6 +457,31 @@ if (!isWindows) {
425457 } ) ) ;
426458}
427459
460+ // It copies a nested folder structure with mode flags.
461+ // This test is based on fs.promises.copyFile() with `COPYFILE_FICLONE_FORCE`.
462+ {
463+ const src = './test/fixtures/copy/kitchen-sink' ;
464+ const dest = nextdir ( ) ;
465+ cp ( src , dest , mustNotMutateObjectDeep ( {
466+ recursive : true ,
467+ mode : fs . constants . COPYFILE_FICLONE_FORCE ,
468+ } ) , mustCall ( ( err ) => {
469+ if ( ! err ) {
470+ // If the platform support `COPYFILE_FICLONE_FORCE` operation,
471+ // it should reach to here.
472+ assert . strictEqual ( err , null ) ;
473+ assertDirEquivalent ( src , dest ) ;
474+ return ;
475+ }
476+
477+ // If the platform does not support `COPYFILE_FICLONE_FORCE` operation,
478+ // it should enter this path.
479+ assert . strictEqual ( err . syscall , 'copyfile' ) ;
480+ assert ( err . code === 'ENOTSUP' || err . code === 'ENOTTY' ||
481+ err . code === 'ENOSYS' || err . code === 'EXDEV' ) ;
482+ } ) ) ;
483+ }
484+
428485// It does not throw errors when directory is copied over and force is false.
429486{
430487 const src = nextdir ( ) ;
@@ -799,6 +856,14 @@ if (!isWindows) {
799856 ) ;
800857}
801858
859+ // It throws if options is not object.
860+ {
861+ assert . throws (
862+ ( ) => cp ( 'a' , 'b' , { mode : - 1 } , ( ) => { } ) ,
863+ { code : 'ERR_OUT_OF_RANGE' }
864+ ) ;
865+ }
866+
802867// Promises implementation of copy.
803868
804869// It copies a nested folder structure with files and folders.
@@ -810,6 +875,32 @@ if (!isWindows) {
810875 assertDirEquivalent ( src , dest ) ;
811876}
812877
878+ // It copies a nested folder structure with mode flags.
879+ // This test is based on fs.promises.copyFile() with `COPYFILE_FICLONE_FORCE`.
880+ await ( async ( ) => {
881+ const src = './test/fixtures/copy/kitchen-sink' ;
882+ const dest = nextdir ( ) ;
883+ let p = null ;
884+ try {
885+ p = await fs . promises . cp ( src , dest , mustNotMutateObjectDeep ( {
886+ recursive : true ,
887+ mode : fs . constants . COPYFILE_FICLONE_FORCE ,
888+ } ) ) ;
889+ } catch ( err ) {
890+ // If the platform does not support `COPYFILE_FICLONE_FORCE` operation,
891+ // it should enter this path.
892+ assert . strictEqual ( err . syscall , 'copyfile' ) ;
893+ assert ( err . code === 'ENOTSUP' || err . code === 'ENOTTY' ||
894+ err . code === 'ENOSYS' || err . code === 'EXDEV' ) ;
895+ return ;
896+ }
897+
898+ // If the platform support `COPYFILE_FICLONE_FORCE` operation,
899+ // it should reach to here.
900+ assert . strictEqual ( p , undefined ) ;
901+ assertDirEquivalent ( src , dest ) ;
902+ } ) ( ) ;
903+
813904// It accepts file URL as src and dest.
814905{
815906 const src = './test/fixtures/copy/kitchen-sink' ;
@@ -847,6 +938,16 @@ if (!isWindows) {
847938 ) ;
848939}
849940
941+ // It rejects if options.mode is invalid.
942+ {
943+ await assert . rejects (
944+ fs . promises . cp ( 'a' , 'b' , {
945+ mode : - 1 ,
946+ } ) ,
947+ { code : 'ERR_OUT_OF_RANGE' }
948+ ) ;
949+ }
950+
850951function assertDirEquivalent ( dir1 , dir2 ) {
851952 const dir1Entries = [ ] ;
852953 collectEntries ( dir1 , dir1Entries ) ;
0 commit comments