watcher/test/index.js
2024-04-18 21:12:37 +02:00

2219 lines
95 KiB
JavaScript

/* IMPORT */
import {describe} from 'fava';
import {execSync} from 'node:child_process';
import {HAS_NATIVE_RECURSION} from '../dist/constants.js';
import {before, withContext} from './hooks.js';
/* MAIN */
describe ( 'Watcher', () => {
describe.before ( before );
describe ( 'watching files', it => {
it ( 'should watch a single non-existent file inside a directory', withContext ( async t => {
const file = 'home/a/file_missing' + Math.random ();
t.context.watch ( file, { debounce: 0 } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 1, 0 );
t.context.deepEqualResults ( [], [] );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlink'], [file] );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
t.context.tree.modify ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should watch a single non-existent file inside a non-existent directory', withContext ( async t => {
const dir = 'home/a/dir_missing' + Math.random ();
const file = dir + '/file_missing' + Math.random ();
t.context.watch ( file, { debounce: 0, pollingInterval: 100 } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( [], [] );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
t.context.tree.remove ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlink'], [file] );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
t.context.tree.modify ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should watch a single file', withContext ( async t => {
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watch ( file1, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.tree.modify ( file1 );
t.context.tree.modify ( file2 );
t.context.tree.modify ( file1, 100 );
t.context.tree.modify ( file2, 100 );
t.context.tree.modify ( file1, 200 );
t.context.tree.modify ( file2, 200 );
await t.context.wait.time ();
t.context.deepEqualChanges ( [file1, file1, file1] );
}));
it ( 'should watch multiple files', withContext ( async t => {
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watch ( [file1, file2], { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.modify ( 'home/a/file1' );
t.context.tree.modify ( 'home/a/file2', 100 );
await t.context.wait.time ();
t.context.deepEqualChanges ( [file1, file2] );
}));
it ( 'should watch all files inside a directory', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watch ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.modify ( 'home/a/file1' );
t.context.tree.modify ( 'home/a/file2', 100 );
await t.context.wait.time ();
t.context.deepEqualChanges ( [file1, file2] );
}));
it ( 'should watch new files inside a directory', withContext ( async t => {
const dir = 'home/a';
const newfile1 = 'home/a/newfile' + Math.random ();
const newfile2 = 'home/a/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newfile1, newfile2] );
}));
it ( 'should watch new files inside an initially empty directory', withContext ( async t => {
const dir = 'home/empty';
const newfile1 = 'home/empty/newfile' + Math.random ();
const newfile2 = 'home/empty/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newfile1, newfile2] );
}));
it ( 'should watch new files inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/newdir' + Math.random ();
const newfile1 = newdir + '/newfile' + Math.random ();
const newfile2 = newdir + '/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir, newfile1, newfile2] );
}));
it ( 'should watch all files inside a deep directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.modify ( 'home/a/file1' );
t.context.tree.modify ( 'home/a/file2', 100 );
await t.context.wait.time ();
t.context.deepEqualChanges ( [file1, file2] );
}));
it ( 'should watch new files inside a deep directory', withContext ( async t => {
const dir = 'home';
const newfile1 = 'home/a/newfile' + Math.random ();
const newfile2 = 'home/a/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newfile1, newfile2] );
}));
it ( 'should watch new files inside an initially empty deep directory', withContext ( async t => {
const dir = 'home';
const newfile1 = 'home/empty/newfile' + Math.random ();
const newfile2 = 'home/empty/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newfile1, newfile2] );
}));
it ( 'should watch (touched) new files inside an initially empty deep directory', withContext ( async t => {
const dir = 'home';
const newfile1 = 'home/empty/newfile' + Math.random ();
const newfile2 = 'home/empty/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
execSync ( `touch "${t.context.tree.path ( newfile1 )}"` );
execSync ( `touch "${t.context.tree.path ( newfile2 )}"` );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newfile1, newfile2] );
}));
it ( 'should watch new files inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir = 'home/a/newdir' + Math.random ();
const newfile1 = newdir + '/newfile' + Math.random ();
const newfile2 = newdir + '/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile1 );
t.context.tree.newFile ( newfile2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir, newfile1, newfile2] );
}));
it ( 'should deduplicate events', withContext ( async t => {
const file = 'home/a/file2';
t.context.watch ( file, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.modify ( file, 50 );
t.context.tree.modify ( file, 100 );
await t.context.wait.time ();
t.context.deepEqualChanges ( [file] );
}));
it ( 'should deduplicate events inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watch ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.modify ( file, 50 );
t.context.tree.modify ( file, 100 );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should deduplicate events inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watch ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.modify ( file, 50 );
t.context.tree.modify ( file, 100 );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
});
describe ( 'watching directories', it => {
it ( 'should watch a single non-existent directory inside a directory', withContext ( async t => {
const dir = 'home/a/dir_missing' + Math.random ();
t.context.watch ( dir, { debounce: 0 } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 1, 0 );
t.context.deepEqualResults ( [], [] );
t.context.tree.newDir ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
t.context.tree.remove ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
t.context.tree.newDir ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should watch a single non-existent directory inside a non-existent directory', withContext ( async t => {
const pdir = 'home/a/dir_missing' + Math.random ();
const dir = pdir + '/dir_missing' + Math.random ();
t.context.watch ( dir, { debounce: 0, pollingInterval: 100 } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( [], [] );
t.context.tree.newDir ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
t.context.tree.remove ( pdir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
t.context.tree.newDir ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should watch new directories inside a directory', withContext ( async t => {
const dir = 'home/a';
const newdir1 = 'home/a/dir1' + Math.random ();
const newdir2 = 'home/a/dir2' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualUnorderedChanges ( [newdir1, newdir2] );
}));
it ( 'should watch new directories inside an initially empty directory', withContext ( async t => {
const dir = 'home/empty';
const newdir1 = 'home/empty/dir1' + Math.random ();
const newdir2 = 'home/empty/dir2' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualUnorderedChanges ( [newdir1, newdir2] );
}));
it ( 'should watch new directories inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir0 = 'home/a/newdir' + Math.random ();
const newdir1 = newdir0 + '/newdir' + Math.random ();
const newdir2 = newdir0 + '/newdir' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir0, newdir1, newdir2] );
}));
it ( 'should watch new directories inside a deep directory', withContext ( async t => {
const dir = 'home';
const newdir1 = 'home/a/dir1' + Math.random ();
const newdir2 = 'home/a/dir2' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir1, newdir2] );
}));
it ( 'should watch new directories inside an initially empty deep directory', withContext ( async t => {
const dir = 'home';
const newdir1 = 'home/empty/dir1' + Math.random ();
const newdir2 = 'home/empty/dir2' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir1, newdir2] );
}));
it ( 'should watch new directories inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir0 = 'home/a/newdir' + Math.random ();
const newdir1 = newdir0 + '/newdir' + Math.random ();
const newdir2 = newdir0 + '/newdir' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [newdir0, newdir1, newdir2] );
}));
it ( 'should deduplicate events inside a directory', withContext ( async t => {
const dir = 'home/a';
const newdir1 = 'home/a/newdir1' + Math.random ();
const newdir2 = 'home/a/newdir2' + Math.random ();
t.context.watch ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
t.context.tree.remove ( newdir1, 50 );
t.context.tree.remove ( newdir2, 50 );
t.context.tree.newDir ( newdir1, 100 );
t.context.tree.newDir ( newdir2, 100 );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should deduplicate events inside a deep directory', withContext ( async t => {
const dir = 'home';
const newdir1 = 'home/a/newdir1' + Math.random ();
const newdir2 = 'home/a/newdir2' + Math.random ();
t.context.watch ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir1 );
t.context.tree.newDir ( newdir2 );
t.context.tree.remove ( newdir1, 50 );
t.context.tree.remove ( newdir2, 50 );
t.context.tree.newDir ( newdir1, 100 );
t.context.tree.newDir ( newdir2, 100 );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should keep watching after removal of sub directory', withContext ( async t => {
const home = 'home';
const dir = t.context.tree.path ( 'home/e/sub' );
const file1 = t.context.tree.path ( 'home/e/file1' );
const file2 = t.context.tree.path ( 'home/e/file2' );
const subfile = t.context.tree.path ( 'home/e/sub/file1' );
const changes = [];
t.context.watch ( home, { debounce: 0, ignoreInitial: true, recursive: true } );
t.context.watcher.on ( 'all', ( event, name ) => {
if ( name === dir || name === file1 || name === file2 ) {
changes.push ( name );
}
});
await t.context.wait.ready ();
t.context.tree.remove ( 'home/e/sub', 50 );
t.context.tree.modify ( 'home/e/file1', 100 );
t.context.tree.modify ( 'home/e/file2', 150 );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlink', 'unlinkDir', 'change', 'change'], [subfile, dir, file1, file2] );
}));
it ( 'should close all eventual additional watchers added for recursiong when no longer needed', withContext ( async t => {
const home = 'home/a';
const dir1 = 'home/a/sub1';
const dir2 = dir1 + '/sub2';
t.context.watch ( home, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( [], [] );
t.context.tree.newDir ( dir2 );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, HAS_NATIVE_RECURSION ? 3 : 5 );
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir1, dir2] );
t.context.tree.remove ( dir2 );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, HAS_NATIVE_RECURSION ? 3 : 4 );
t.context.deepEqualResults ( ['unlinkDir'], [dir2] );
t.context.tree.remove ( dir1);
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['unlinkDir'], [dir1] );
}));
});
describe.todo ( 'watching symlinks' );
describe ( 'file events', it => {
it ( 'should detect initial "add" for a single file', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect initial "add" for multiple files', withContext ( async t => {
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( [file1, file2], { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['add', 'add'], [file1, file2] );
}));
it ( 'should detect initial "add" for all files inside a directory', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( dir, { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['add', 'add'], [file1, file2] );
}));
it ( 'should detect initial "add" for all files inside a deep directory', withContext ( async t => {
const dir = 'home/e';
const file1 = 'home/e/file1';
const file2 = 'home/e/file2';
const filesub1 = 'home/e/sub/file1';
t.context.watchForFiles ( dir, { debounce: 0, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['add', 'add', 'add'], [file1, file2, filesub1] );
}));
it ( 'should detect "add" when creating a new file inside a directory', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when creating a new file inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/newdir' + Math.random ();
const newfile = newdir + '/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when creating a new file inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir = 'home/a/newdir' + Math.random ();
const newfile = newdir + '/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when copying a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const copyfile = file + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.copy ( file, copyfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
const copyfile = file + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.copy ( file, copyfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a parent directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
const copyfile = copydir + '/file1';
t.context.watchForFiles ( home, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a deep parent directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
const copyfile = copydir + '/file1';
t.context.watchForFiles ( home, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "change" when modifying a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "change" when modifying a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "change" when renaming a non-empty file and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const filealt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.rename ( file, filealt );
t.context.tree.rename ( filealt, file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "unlink" when removing a single file', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" and "add" when removing a single file and much later recreating it', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlink'], [file] );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect "unlink" when removing a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" when removing a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" when removing a parent directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlink', 'unlink'], [file1, file2] );
}));
it ( 'should detect "unlink" when removing a parent directory of the watcher', withContext ( async t => {
const dir = 'home/e/sub';
const file = 'home/e/sub/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 )
t.context.tree.remove ( 'home/e' );
await t.context.wait.time ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" and "add" when renaming a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const file1alt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, file1alt );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlink', 'add'], [file1, file1alt] );
}));
it ( 'should detect "unlink" and "add" when renaming a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file1alt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, file1alt );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlink', 'add'], [file1, file1alt] );
}));
it ( 'should detect "unlink" and "add" when renaming a parent directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file1alt = 'home/a_alt/file1';
const file2 = 'home/a/file2';
const file2alt = 'home/a_alt/file2';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.rename ( 'home/a', 'home/a_alt' );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlink', 'add', 'unlink', 'add'], [file1, file1alt, file2, file2alt] );
}));
it ( 'should detect a single "add" when creating a new file and modifying it', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
t.context.tree.modify ( newfile );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect a single "change" when removing a file and creating it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect a single "unlink" when modifying a file and removing it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.remove ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect nothing when creating a new file and removing it', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
t.context.tree.remove ( newfile );
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming an empty file and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const filealt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file, filealt );
t.context.tree.rename ( filealt, file );
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const diralt = 'home/a_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir, diralt );
t.context.tree.rename ( diralt, dir );
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect "unlink" when removing a file and creating a directory of the same name', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newDir ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "add" when removing a directory and creating a file of the same name', withContext ( async t => {
const dir = 'home';
const file = 'home/a';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect "change" when replacing a parent directory with another one of the same name', withContext ( async t => {
const dir = 'home';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
t.context.tree.copy ( 'home/b', 'home/a' );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['change', 'change'], ['home/a/file1', 'home/a/file2'] );
}));
it ( 'should be able to handle many "unlink" events', withContext ( async t => {
const dir = 'home/a';
const files = t.context.tree.newFiles ( dir, 100 );
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ()
files.forEach ( file => t.context.tree.remove ( file ) );
await t.context.wait.longtime ()
t.is ( t.context.events.length, 100 );
}));
});
describe ( 'file events (with renames)', it => {
it ( 'should detect initial "add" for a single file', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect initial "add" for multiple files', withContext ( async t => {
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( [file1, file2], { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['add', 'add'], [file1, file2] );
}));
it ( 'should detect initial "add" for all files inside a directory', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( dir, { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['add', 'add'], [file1, file2] );
}));
it ( 'should detect initial "add" for all files inside a deep directory', withContext ( async t => {
const dir = 'home/e';
const file1 = 'home/e/file1';
const file2 = 'home/e/file2';
const filesub1 = 'home/e/sub/file1';
t.context.watchForFiles ( dir, { debounce: 0, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['add', 'add', 'add'], [file1, file2, filesub1] );
}));
it ( 'should detect "add" when creating a new file inside a directory', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when creating a new file inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/newdir' + Math.random ();
const newfile = newdir + '/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when creating a new file inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir = 'home/a/newdir' + Math.random ();
const newfile = newdir + '/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect "add" when copying a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const copyfile = file + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( file, copyfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
const copyfile = file + Math.random ();
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( file, copyfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a parent directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
const copyfile = copydir + '/file1';
t.context.watchForFiles ( home, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "add" when copying a deep parent directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
const copyfile = copydir + '/file1';
t.context.watchForFiles ( home, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [copyfile] );
}));
it ( 'should detect "change" when modifying a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "change" when modifying a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "change" when renaming a non-empty file and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const filealt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.rename ( file, filealt );
t.context.tree.rename ( filealt, file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect "unlink" when removing a single file', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.tree.remove ( file );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" and "add" when removing a single file and much later recreating it', withContext ( async t => {
const file = 'home/a/file1';
t.context.watchForFiles ( file, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.tree.remove ( file );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlink'], [file] );
t.context.tree.newFile ( file );
await t.context.wait.longlongtime ();
t.context.hasWatchObjects ( 0, 0, 2 );
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect "unlink" when removing a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" when removing a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "unlink" when removing a parent directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['unlink', 'unlink'], [file1, file2] );
}));
it ( 'should detect "unlink" when removing a parent directory of the watcher', withContext ( async t => {
const dir = 'home/e/sub';
const file = 'home/e/sub/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 )
t.context.tree.remove ( 'home/e' );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "rename" when renaming a file inside a directory', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const file1alt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, file1alt );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['rename'], [[file1, file1alt]] );
}));
it ( 'should detect "rename" when renaming a file inside a deep directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file1alt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, file1alt );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['rename'], [[file1, file1alt]] );
}));
it ( 'should detect "rename" when renaming a parent directory', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file1alt = 'home/a_alt/file1';
const file2 = 'home/a/file2';
const file2alt = 'home/a_alt/file2';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( 'home/a', 'home/a_alt' );
await t.context.wait.longlongtime ();
t.context.deepEqualUnorderedResults ( ['rename', 'rename'], [[file1, file1alt], [file2, file2alt]] );
}));
it ( 'should detect "rename" when renaming a file inside a directory case-sensitively', withContext ( async t => {
const dir = 'home/a';
const file1 = 'home/a/file1';
const File1 = 'home/a/File1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, File1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['rename'], [[file1, File1]] );
}));
it ( 'should detect "rename" when renaming a file inside a deep directory case-sensitively', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const File1 = 'home/a/File1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file1, File1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['rename'], [[file1, File1]] );
}));
it ( 'should detect "rename" when renaming a parent directory case-sensitively', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const File1 = 'home/A/file1';
const file2 = 'home/a/file2';
const File2 = 'home/A/file2';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( 'home/a', 'home/A' );
await t.context.wait.longlongtime ();
t.context.deepEqualUnorderedResults ( ['rename', 'rename'], [[file1, File1], [file2, File2]] );
}));
it ( 'should detect a single "add" when creating a new file and modifying it', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
t.context.tree.modify ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [newfile] );
}));
it ( 'should detect a single "change" when removing a file and creating it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should detect a single "unlink" when modifying a file and removing it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.remove ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect nothing when renaming an empty file and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const filealt = 'home/a/file1_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file, filealt );
t.context.tree.rename ( filealt, file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming an empty file case-sensitively and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const File = 'home/a/File1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( file, File );
t.context.tree.rename ( File, file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when creating a new file and removing it', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file1' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
t.context.tree.remove ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when creating a new file and removing it after a delay', withContext ( async t => {
const dir = 'home/a';
const newfile = 'home/a/file' + Math.random ();
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newFile ( newfile );
await t.context.wait.time ();
t.context.tree.remove ( newfile );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const diralt = 'home/a_alt';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir, diralt );
t.context.tree.rename ( diralt, dir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory case-sensitively and rerenaming it', withContext ( async t => {
const dir = 'home/a';
const Dir = 'home/A';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir, Dir );
t.context.tree.rename ( Dir, dir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect "unlink" when removing a file and creating a directory of the same name', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newDir ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlink'], [file] );
}));
it ( 'should detect "add" when removing a directory and creating a file of the same name', withContext ( async t => {
const dir = 'home';
const file = 'home/a';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['add'], [file] );
}));
it ( 'should detect "change" when replacing a parent directory with another one of the same name', withContext ( async t => {
const dir = 'home';
t.context.watchForFiles ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
t.context.tree.copy ( 'home/b', 'home/a' );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['change', 'change'], ['home/a/file1', 'home/a/file2'] );
}));
it ( 'should be able to handle many "unlink" events', withContext ( async t => {
const dir = 'home/a';
const files = t.context.tree.newFiles ( dir, 100 );
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ()
files.forEach ( file => t.context.tree.remove ( file ) );
await t.context.wait.longtime ()
t.is ( t.context.events.length, 100 );
}));
});
describe ( 'directory events', it => {
it ( 'should detect initial "addDir" for a single directory', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should detect initial "addDir" for multiple directories', withContext ( async t => {
const dir1 = 'home/a';
const dir2 = 'home/b';
t.context.watchForDirs ( [dir1, dir2], { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir1, dir2] );
}));
it ( 'should detect initial "addDir" for directories inside a directory', withContext ( async t => {
const dir = 'home/e';
t.context.watchForDirs ( dir, { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir, 'home/e/sub'] );
}));
it ( 'should detect initial "addDir" for directories inside a deep directory', withContext ( async t => {
const dir = 'home/shallow';
t.context.watchForDirs ( dir, { debounce: 0, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir', 'addDir'], [dir, 'home/shallow/1', 'home/shallow/1/2'] );
}));
it ( 'should detect "addDir" when creating a new directory inside a directory', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [newdir] );
}));
it ( 'should detect "addDir" when creating a new directory inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir1 = 'home/a/dir' + Math.random ();
const newdir2 = newdir1 + '/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should detect "addDir" when creating a new directory inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir1 = 'home/a/dir' + Math.random ();
const newdir2 = newdir1 + '/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir2 );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should detect "addDir" when copying a directory inside a directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a directory inside a deep directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a parent directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a deep parent directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e';
const copydir = dir + Math.random ();
const copysubdir = copydir + '/sub';
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [copydir, copysubdir] );
}));
it ( 'should detect "unlinkDir" when removing a single directory', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
}));
it ( 'should detect "unlinkDir" and "addDir" when removing a single directory and much later recreating it', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, pollingInterval: 100 } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
t.context.tree.newDir ( dir );
await t.context.wait.time ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should detect "unlinkDir" when removing a directory inside a directory', withContext ( async t => {
const dir = 'home/e';
const subdir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( subdir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlinkDir'], [subdir] );
}));
it ( 'should detect "unlinkDir" when removing a directory inside a deep directory', withContext ( async t => {
const dir = 'home';
const subdir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( subdir );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlinkDir'], [subdir] );
}));
it ( 'should detect "unlinkDir" when removing a parent directory', withContext ( async t => {
const dir = 'home';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/e' );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlinkDir', 'unlinkDir'], ['home/e/sub', 'home/e'] );
}));
it ( 'should detect "unlinkDir" when removing a parent directory of the watcher', withContext ( async t => {
const dir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( 'home/e' );
await t.context.wait.time ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
}));
it ( 'should detect "unlinkDir" and "addDir" when renaming a directory inside a directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const dir1alt = 'home/a_alt';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlinkDir', 'addDir'], [dir1, dir1alt] );
}));
it ( 'should detect "unlinkDir" and "addDir" when renaming a directory inside a deep directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e/sub';
const dir1alt = 'home/e/sub_alt';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlinkDir', 'addDir'], [dir1, dir1alt] );
}));
it ( 'should detect "unlinkDir" and "addDir" when renaming a parent directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e';
const dir1alt = 'home/e_alt';
const subdir1 = 'home/e/sub';
const subdir1alt = 'home/e_alt/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['unlinkDir', 'addDir', 'unlinkDir', 'addDir'], [dir1, dir1alt, subdir1, subdir1alt] );
}));
it ( 'should detect nothing when creating a new directory and removing it', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir );
t.context.tree.remove ( newdir );
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory and rerenaming it', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const dir1alt = 'home/a_alt';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
t.context.tree.rename ( dir1alt, dir1 );
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect "addDir" when removing a file and creating a directory of the same name', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newDir ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['addDir'], [file] );
}));
it ( 'should detect "unlinkDir" when removing a directory and creating a file of the same name', withContext ( async t => {
const dir = 'home';
const file = 'home/a';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlinkDir'], [file] );
}));
it ( 'should detect "unlinkDir" and "addDir" when replacing a parent directory with another one of the same name', withContext ( async t => {
const dir = 'home';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
t.context.tree.copy ( 'home/b', 'home/a' );
await t.context.wait.time ();
t.context.deepEqualResults ( ['unlinkDir', 'addDir'], ['home/a', 'home/a'] );
}));
it ( 'should be able to handle many "unlinkDir" events', withContext ( async t => {
const dir = 'home/a';
const dirs = t.context.tree.newDirs ( dir, 100 );
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ()
dirs.forEach ( dir => t.context.tree.remove ( dir ) );
await t.context.wait.longtime ()
t.is ( t.context.events.length, 100 );
}));
});
describe ( 'directory events (with renames)', it => {
it ( 'should detect initial "addDir" for a single directory', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should detect initial "addDir" for multiple directories', withContext ( async t => {
const dir1 = 'home/a';
const dir2 = 'home/b';
t.context.watchForDirs ( [dir1, dir2], { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir1, dir2] );
}));
it ( 'should detect initial "addDir" for directories inside a directory', withContext ( async t => {
const dir = 'home/e';
t.context.watchForDirs ( dir, { debounce: 0, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir, 'home/e/sub'] );
}));
it ( 'should detect initial "addDir" for directories inside a deep directory', withContext ( async t => {
const dir = 'home/shallow';
t.context.watchForDirs ( dir, { debounce: 0, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir', 'addDir'], [dir, 'home/shallow/1', 'home/shallow/1/2'] );
}));
it ( 'should detect "addDir" when creating a new directory inside a directory', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [newdir] );
}));
it ( 'should detect "addDir" when creating a new directory inside a new directory', withContext ( async t => {
const dir = 'home/a';
const newdir1 = 'home/a/dir' + Math.random ();
const newdir2 = newdir1 + '/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir2 );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should detect "addDir" when creating a new directory inside a new deep directory', withContext ( async t => {
const dir = 'home';
const newdir1 = 'home/a/dir' + Math.random ();
const newdir2 = newdir1 + '/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir2 );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [newdir1, newdir2] );
}));
it ( 'should detect "addDir" when copying a directory inside a directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a directory inside a deep directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a parent directory', withContext ( async t => {
const home = 'home/e';
const dir = 'home/e/sub';
const copydir = dir + Math.random ();
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [copydir] );
}));
it ( 'should detect "addDir" when copying a deep parent directory', withContext ( async t => {
const home = 'home';
const dir = 'home/e';
const copydir = dir + Math.random ();
const copysubdir = copydir + '/sub';
t.context.watchForDirs ( home, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.copy ( dir, copydir );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [copydir, copysubdir] );
}));
it ( 'should detect "unlinkDir" when removing a single directory', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( dir );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
}));
it ( 'should detect "unlinkDir" and "addDir" when removing a single directory and much later recreating it', withContext ( async t => {
const dir = 'home/a';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, pollingInterval: 100, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( dir );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 0, 1, 1 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
t.context.tree.newDir ( dir );
await t.context.wait.longlongtime ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.deepEqualResults ( ['addDir'], [dir] );
}));
it ( 'should detect "unlinkDir" when removing a directory inside a directory', withContext ( async t => {
const dir = 'home/e';
const subdir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( subdir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlinkDir'], [subdir] );
}));
it ( 'should detect "unlinkDir" when removing a directory inside a deep directory', withContext ( async t => {
const dir = 'home';
const subdir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( subdir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlinkDir'], [subdir] );
}));
it ( 'should detect "unlinkDir" when removing a parent directory', withContext ( async t => {
const dir = 'home';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/e' );
await t.context.wait.longtime ();
t.context.deepEqualUnorderedResults ( ['unlinkDir', 'unlinkDir'], ['home/e/sub', 'home/e'] );
}));
it ( 'should detect "unlinkDir" when removing a parent directory of the watcher', withContext ( async t => {
const dir = 'home/e/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.tree.remove ( 'home/e' );
await t.context.wait.longtime ();
t.context.hasWatchObjects ( 1, 0, 0 );
t.context.deepEqualResults ( ['unlinkDir'], [dir] );
}));
it ( 'should detect "renameDir" when renaming a directory inside a directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const dir1alt = 'home/a_alt';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['renameDir'], [[dir1, dir1alt]] );
}));
it ( 'should detect "renameDir" when renaming a directory inside a deep directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e/sub';
const dir1alt = 'home/e/sub_alt';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['renameDir'], [[dir1, dir1alt]] );
}));
it ( 'should detect "renameDir" when renaming a parent directory', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e';
const dir1alt = 'home/e_alt';
const subdir1 = 'home/e/sub';
const subdir1alt = 'home/e_alt/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
await t.context.wait.longlongtime ();
t.context.deepEqualUnorderedResults ( ['renameDir', 'renameDir'], [[dir1, dir1alt], [subdir1, subdir1alt]] );
}));
it ( 'should detect "renameDir" when renaming a directory inside a directory case-sensitively', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const Dir1 = 'home/A';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, Dir1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['renameDir'], [[dir1, Dir1]] );
}));
it ( 'should detect "renameDir" when renaming a directory inside a deep directory case-sensitively', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e/sub';
const Dir1 = 'home/e/Sub';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, Dir1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['renameDir'], [[dir1, Dir1]] );
}));
it ( 'should detect "renameDir" when renaming a parent directory case-sensitively', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/e';
const Dir1 = 'home/E';
const subdir1 = 'home/e/sub';
const Subdir1 = 'home/E/sub';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, Dir1 );
await t.context.wait.longlongtime ();
t.context.deepEqualUnorderedResults ( ['renameDir', 'renameDir'], [[dir1, Dir1], [subdir1, Subdir1]] );
}));
it ( 'should detect nothing when creating a new directory and removing it', withContext ( async t => {
const dir = 'home/a';
const newdir = 'home/a/dir' + Math.random ();
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.newDir ( newdir );
t.context.tree.remove ( newdir );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory and rerenaming it', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const dir1alt = 'home/a_alt';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, dir1alt );
t.context.tree.rename ( dir1alt, dir1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect nothing when renaming a parent directory case-sensitively and rerenaming it', withContext ( async t => {
const dir = 'home';
const dir1 = 'home/a';
const Dir1 = 'home/A';
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.rename ( dir1, Dir1 );
t.context.tree.rename ( Dir1, dir1 );
await t.context.wait.longtime ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should detect "addDir" when removing a file and creating a directory of the same name', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newDir ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['addDir'], [file] );
}));
it ( 'should detect "unlinkDir" when removing a directory and creating a file of the same name', withContext ( async t => {
const dir = 'home';
const file = 'home/a';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( file );
t.context.tree.newFile ( file );
await t.context.wait.longtime ();
t.context.deepEqualResults ( ['unlinkDir'], [file] );
}));
it ( 'should detect "unlinkDir" and "addDir" when replacing a parent directory with another one of the same name', withContext ( async t => {
const dir = 'home';
t.context.watchForDirs ( dir, { debounce: 300, ignoreInitial: true, recursive: true, renameDetection: true } );
await t.context.wait.ready ();
t.context.tree.remove ( 'home/a' );
t.context.tree.copy ( 'home/b', 'home/a' );
await t.context.wait.longlongtime ();
t.context.deepEqualResults ( ['unlinkDir', 'addDir'], ['home/a', 'home/a'] );
}));
it ( 'should be able to handle many "unlinkDir" events', withContext ( async t => {
const dir = 'home/a';
const dirs = t.context.tree.newDirs ( dir, 100 );
t.context.watchForDirs ( dir, { debounce: 0, ignoreInitial: true, renameDetection: true } );
await t.context.wait.ready ();
await t.context.wait.longtime ()
dirs.forEach ( dir => t.context.tree.remove ( dir ) );
await t.context.wait.longtime ()
t.is ( t.context.events.length, 100 );
}));
});
describe ( 'watcher events', it => {
it ( 'should emit "all" alongside specific target events', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const newdir = 'home/a/newdir' + Math.random ();
const newfile = newdir + '/newfile' + Math.random ();
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
const adds = [];
t.context.watcher.on ( 'add', targetPath => adds.push ( targetPath ) );
const addDirs = [];
t.context.watcher.on ( 'addDir', targetPath => addDirs.push ( targetPath ) );
const changes = [];
t.context.watcher.on ( 'change', targetPath => changes.push ( targetPath ) );
const unlinks = [];
t.context.watcher.on ( 'unlink', targetPath => unlinks.push ( targetPath ) );
const unlinkDirs = [];
t.context.watcher.on ( 'unlinkDir', targetPath => unlinkDirs.push ( targetPath ) );
await t.context.wait.ready ();
t.context.tree.modify ( file );
t.context.tree.newFile ( newfile );
await t.context.wait.time ();
await t.context.deepEqualUnorderedResults ( ['change', 'addDir', 'add'], [file, newdir, newfile] );
t.deepEqual ( adds, t.context.normalizePaths ( [newfile] ) );
t.deepEqual ( addDirs, t.context.normalizePaths ( [newdir] ) );
t.deepEqual ( changes, t.context.normalizePaths ( [file] ) );
t.deepEqual ( unlinks, t.context.normalizePaths ( [] ) );
t.deepEqual ( unlinkDirs, t.context.normalizePaths ( [] ) );
t.context.tree.remove ( file );
t.context.tree.remove ( newdir );
await t.context.wait.time ();
await t.context.deepEqualUnorderedResults ( ['unlink', 'unlinkDir', 'unlink'], [file, newdir, newfile] );
t.deepEqual ( adds, t.context.normalizePaths ( [newfile] ) );
t.deepEqual ( addDirs, t.context.normalizePaths ( [newdir] ) );
t.deepEqual ( changes, t.context.normalizePaths ( [file] ) );
t.context.deepEqualUnordered ( unlinks, t.context.normalizePaths ( [file, newfile] ) );
t.deepEqual ( unlinkDirs, t.context.normalizePaths ( [newdir] ) );
}));
it ( 'should emit "change" only after "ready"', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
const _ready = t.context.watcher.ready.bind ( t.context.watcher );
t.context.watcher.ready = () => {
t.context.tree.modify ( file );
setTimeout ( _ready, 300 );
};
await t.context.wait.ready ();
await t.context.wait.time ();
t.true ( t.context.watcher.isReady () );
t.context.deepEqualResults ( ['change'], [file] );
}));
it ( 'should emit "close" when closing', withContext ( async t => {
const file = 'home/a/file1';
t.context.watch ( file );
t.context.watcher.close ();
await t.context.wait.close ();
t.pass ();
}));
it ( 'should emit "ready" when watching nothing', withContext ( async t => {
t.context.watch ( [] );
await t.context.wait.ready ();
t.pass ();
}));
it ( 'should emit "ready" when watching a file', withContext ( async t => {
const file = 'home/a/file1';
t.context.watch ( file );
await t.context.wait.ready ();
t.pass ();
}));
it ( 'should emit "ready" when watching a directory', withContext ( async t => {
const dir = 'home';
t.context.watch ( dir );
await t.context.wait.ready ();
t.pass ();
}));
it ( 'should emit "ready" when watching a directory recursively', withContext ( async t => {
const dir = 'home';
t.context.watch ( dir, { recursive: true } );
await t.context.wait.ready ();
t.pass ();
}));
it ( 'should emit "ready" when watching multiple paths recursively', withContext ( async t => {
const file = 'home/b/file1';
const dir1 = 'home/a';
const dir2 = 'home/b';
const dir3 = 'home';
t.context.watch ( [file, dir1, dir2, dir3], { recursive: true } );
await t.context.wait.ready ();
t.pass ();
}));
it ( 'should not emit "error" when watching a non-existent file', withContext ( async t => {
const file = 'home/missing/file1';
t.context.watch ( file );
t.context.watcher.on ( 'error', t.fail );
await t.context.wait.ready ();
await t.context.wait.time ();
t.pass ();
}));
it ( 'should not emit "error" when watching a non-existent directory', withContext ( async t => {
const dir = 'home/missing';
t.context.watch ( dir );
t.context.watcher.on ( 'error', t.fail );
await t.context.wait.ready ();
await t.context.wait.time ();
t.pass ();
}));
it ( 'should not emit "error" when watching at least one non-existent path', withContext ( async t => {
const file1 = 'home/b/file1';
const file2 = 'home/missing/file1';
const dir = 'home';
t.context.watch ( [file1, file2, dir], { recursive: true } );
t.context.watcher.on ( 'error', t.fail );
await t.context.wait.ready ();
await t.context.wait.time ();
t.pass ();
}));
});
describe ( 'watcher instance', it => {
describe ( 'close', it => {
it ( 'should close all watchers and stop emissions', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
t.context.watch ( dir, { debounce: 0 } );
t.context.watcher.on ( 'all', t.fail );
await t.context.wait.ready ();
t.context.hasWatchObjects ( 0, 0, 3 );
t.context.watcher.close ();
t.context.tree.modify ( file );
t.context.tree.modify ( file, 50 );
t.context.tree.modify ( file, 100 );
await t.context.wait.time ();
t.true ( t.context.watcher.isClosed () );
t.context.hasWatchObjects ( 0, 0, 0 );
}));
});
});
describe ( 'watcher options', it => {
describe ( 'debounce', it => {
it ( 'should cause delayed emissions when set to >= 0, when "ignoreInitial" is not used', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const start = Date.now ();
t.context.watch ( dir, { debounce: 300 }, it => {
if ( ( Date.now () - start ) < 300 ) {
t.fail ();
}
});
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.time ();
t.pass ();
}));
it ( 'should cause delayed emissions when set to >= 0, when "ignoreInitial" is used', withContext ( async t => {
const dir = 'home/a';
const file = 'home/a/file1';
const start = Date.now ();
t.context.watch ( dir, { debounce: 300, ignoreInitial: true }, it => {
if ( ( Date.now () - start ) < 300 ) {
t.fail ();
}
});
await t.context.wait.ready ();
t.context.tree.modify ( file );
await t.context.wait.time ();
t.pass ();
}));
});
describe ( 'depth', it => {
it ( 'should not find any children when set to 0', withContext ( async t => {
const dir = 'home/deep';
t.context.watch ( dir, { debounce: 0, depth: 0, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualChanges ( [dir] );
}));
if ( HAS_NATIVE_RECURSION ) { //FIXME: These should work also when native recursion is unavailable
it ( 'should only find immediate children when set to 1', withContext ( async t => {
const dir = 'home/deep';
const file = 'home/deep/1';
t.context.watch ( dir, { debounce: 0, depth: 1, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [dir, file] );
}));
it ( 'should only find up-to-depth-20 children when not set', withContext ( async t => {
const dir = 'home/deep';
t.context.watch ( dir, { debounce: 0, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.is ( t.context.events.length, 21 );
}));
}
});
describe ( 'ignore', it => {
it ( 'should ignore files', withContext ( async t => {
const dir = 'home';
const file1 = 'home/a/file1';
const file2 = 'home/a/file2';;
t.context.watch ( dir, {
debounce: 0,
ignoreInitial: true,
recursive: true,
ignore: name => /file1/.test ( name )
});
await t.context.wait.ready ();
t.context.tree.modify ( file1 );
t.context.tree.modify ( file2, 50 );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file2] );
}));
it ( 'should ignore directories', withContext ( async t => {
const dir = 'home';
const file1 = 'home/e/file1';
const file2 = 'home/e/sub/file1';
t.context.watch ( dir, {
debounce: 0,
ignoreInitial: true,
recursive: true,
ignore: name => /sub/.test ( name )
});
await t.context.wait.ready ();
t.context.tree.modify ( file1 );
t.context.tree.modify ( file2 );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file1] );
}));
it ( 'should ignore initial events from ignored files', withContext ( async t => {
const dir = 'home/shallow';
t.context.watch ( dir, {
debounce: 0,
recursive: true,
ignore: name => /1\/2|1\\2/.test ( name )
});
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'addDir'], [dir, 'home/shallow/1'] );
}));
});
describe ( 'ignoreInitial', it => {
it ( 'should not emit "add" and "addDir" events when set to "true"', withContext ( async t => {
const dir = 'home/a';
const file = 'home/b/file1';
t.context.watch ( [dir, file], { debounce: 0, ignoreInitial: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualResults ( [], [] );
}));
it ( 'should emit "add" and "addDir" events when set to "false"', withContext ( async t => {
const dir = 'home/a';
const file = 'home/b/file1';
t.context.watch ( [dir, file], { debounce: 0, ignoreInitial: false } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'add', 'add', 'add'], [dir, 'home/a/file1', 'home/a/file2', file] );
}));
it ( 'should emit "add" and "addDir" events when not set', withContext ( async t => {
const dir = 'home/a';
const file = 'home/b/file1';
t.context.watch ( [dir, file], { debounce: 0 } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedResults ( ['addDir', 'add', 'add', 'add'], [dir, 'home/a/file1', 'home/a/file2', file] );
}));
});
describe ( 'native', it => {
it ( 'should only find immediate children with "depth" set to 1, when set to "false"', withContext ( async t => {
const dir = 'home/deep';
const file = 'home/deep/1';
t.context.watch ( dir, { debounce: 0, depth: 1, native: false, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.context.deepEqualUnorderedChanges ( [dir, file] );
}));
it ( 'should only find up-to-depth-20 children with "depth" not set, when set to "false"', withContext ( async t => {
const dir = 'home/deep';
t.context.watch ( dir, { debounce: 0, native: false, recursive: true } );
await t.context.wait.ready ();
await t.context.wait.time ();
t.is ( t.context.events.length, 21 );
}));
});
describe ( 'recursive', it => {
it ( 'should not watch recursively when not set', withContext ( async t => {
const dir = 'home';
t.context.watch ( dir, { debounce: 0, ignoreInitial: true }, t.fail );
await t.context.wait.ready ();
t.context.tree.modify ( 'home/a/file1' );
await t.context.wait.time ();
t.pass ();
}));
it ( 'should not watch recursively when set to "false"', withContext ( async t => {
const dir = 'home';
t.context.watch ( dir, { debounce: 0, ignoreInitial: true, recursive: false }, t.fail );
await t.context.wait.ready ();
t.context.tree.modify ( 'home/a/file1' );
await t.context.wait.time ();
t.pass ();
}));
it ( 'should watch recursively when set to "true"', withContext ( async t => {
const dir = 'home';
const file = 'home/a/file1';
t.context.watchForFiles ( dir, { debounce: 0, ignoreInitial: true, recursive: true } );
await t.context.wait.ready ();
t.context.tree.modify ( 'home/a/file1' );
await t.context.wait.time ();
t.context.deepEqualResults ( ['change'], [file] );
}));
});
});
});