/
githubmirror
/
atom
Обзор
Документация
Войти
/
githubmirror
/
atom
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
spec/native-watcher-registry-spec.js
389 строк
11 KB
Rafael Oleza
Reformat all JS files using prettier
31 май 2019, 19:33
31 май 2019, 19:33
7f3f040
Код
Авторство
О чём код?
/** @babel */ import path from 'path'; import { Emitter } from 'event-kit'; import { NativeWatcherRegistry } from '../src/native-watcher-registry'; function findRootDirectory() { let current = process.cwd(); while (true) { let next = path.resolve(current, '..'); if (next === current) { return next; } else { current = next; } } } const ROOT = findRootDirectory(); function absolute(...parts) { const candidate = path.join(...parts); return path.isAbsolute(candidate) ? candidate : path.join(ROOT, candidate); } function parts(fullPath) { return fullPath.split(path.sep).filter(part => part.length > 0); } class MockWatcher { constructor(normalizedPath) { this.normalizedPath = normalizedPath; this.native = null; } getNormalizedPathPromise() { return Promise.resolve(this.normalizedPath); } attachToNative(native, nativePath) { if (this.normalizedPath.startsWith(nativePath)) { if (this.native) { this.native.attached = this.native.attached.filter( each => each !== this ); } this.native = native; this.native.attached.push(this); } } } class MockNative { constructor(name) { this.name = name; this.attached = []; this.disposed = false; this.stopped = false; this.emitter = new Emitter(); } reattachTo(newNative, nativePath) { for (const watcher of this.attached) { watcher.attachToNative(newNative, nativePath); } } onWillStop(callback) { return this.emitter.on('will-stop', callback); } dispose() { this.disposed = true; } stop() { this.stopped = true; this.emitter.emit('will-stop'); } } describe('NativeWatcherRegistry', function() { let createNative, registry; beforeEach(function() { registry = new NativeWatcherRegistry(normalizedPath => createNative(normalizedPath) ); }); it('attaches a Watcher to a newly created NativeWatcher for a new directory', async function() { const watcher = new MockWatcher(absolute('some', 'path')); const NATIVE = new MockNative('created'); createNative = () => NATIVE; await registry.attach(watcher); expect(watcher.native).toBe(NATIVE); }); it('reuses an existing NativeWatcher on the same directory', async function() { this.RETRY_FLAKY_TEST_AND_SLOW_DOWN_THE_BUILD(); const EXISTING = new MockNative('existing'); const existingPath = absolute('existing', 'path'); let firstTime = true; createNative = () => { if (firstTime) { firstTime = false; return EXISTING; } return new MockNative('nope'); }; await registry.attach(new MockWatcher(existingPath)); const watcher = new MockWatcher(existingPath); await registry.attach(watcher); expect(watcher.native).toBe(EXISTING); }); it('attaches to an existing NativeWatcher on a parent directory', async function() { const EXISTING = new MockNative('existing'); const parentDir = absolute('existing', 'path'); const subDir = path.join(parentDir, 'sub', 'directory'); let firstTime = true; createNative = () => { if (firstTime) { firstTime = false; return EXISTING; } return new MockNative('nope'); }; await registry.attach(new MockWatcher(parentDir)); const watcher = new MockWatcher(subDir); await registry.attach(watcher); expect(watcher.native).toBe(EXISTING); }); it('adopts Watchers from NativeWatchers on child directories', async function() { const parentDir = absolute('existing', 'path'); const childDir0 = path.join(parentDir, 'child', 'directory', 'zero'); const childDir1 = path.join(parentDir, 'child', 'directory', 'one'); const otherDir = absolute('another', 'path'); const CHILD0 = new MockNative('existing0'); const CHILD1 = new MockNative('existing1'); const OTHER = new MockNative('existing2'); const PARENT = new MockNative('parent'); createNative = dir => { if (dir === childDir0) { return CHILD0; } else if (dir === childDir1) { return CHILD1; } else if (dir === otherDir) { return OTHER; } else if (dir === parentDir) { return PARENT; } else { throw new Error(`Unexpected path: ${dir}`); } }; const watcher0 = new MockWatcher(childDir0); await registry.attach(watcher0); const watcher1 = new MockWatcher(childDir1); await registry.attach(watcher1); const watcher2 = new MockWatcher(otherDir); await registry.attach(watcher2); expect(watcher0.native).toBe(CHILD0); expect(watcher1.native).toBe(CHILD1); expect(watcher2.native).toBe(OTHER); // Consolidate all three watchers beneath the same native watcher on the parent directory const watcher = new MockWatcher(parentDir); await registry.attach(watcher); expect(watcher.native).toBe(PARENT); expect(watcher0.native).toBe(PARENT); expect(CHILD0.stopped).toBe(true); expect(CHILD0.disposed).toBe(true); expect(watcher1.native).toBe(PARENT); expect(CHILD1.stopped).toBe(true); expect(CHILD1.disposed).toBe(true); expect(watcher2.native).toBe(OTHER); expect(OTHER.stopped).toBe(false); expect(OTHER.disposed).toBe(false); }); describe('removing NativeWatchers', function() { it('happens when they stop', async function() { const STOPPED = new MockNative('stopped'); const RUNNING = new MockNative('running'); const stoppedPath = absolute('watcher', 'that', 'will', 'be', 'stopped'); const stoppedPathParts = stoppedPath .split(path.sep) .filter(part => part.length > 0); const runningPath = absolute( 'watcher', 'that', 'will', 'continue', 'to', 'exist' ); const runningPathParts = runningPath .split(path.sep) .filter(part => part.length > 0); createNative = dir => { if (dir === stoppedPath) { return STOPPED; } else if (dir === runningPath) { return RUNNING; } else { throw new Error(`Unexpected path: ${dir}`); } }; const stoppedWatcher = new MockWatcher(stoppedPath); await registry.attach(stoppedWatcher); const runningWatcher = new MockWatcher(runningPath); await registry.attach(runningWatcher); STOPPED.stop(); const runningNode = registry.tree.root.lookup(runningPathParts).when({ parent: node => node, missing: () => false, children: () => false }); expect(runningNode).toBeTruthy(); expect(runningNode.getNativeWatcher()).toBe(RUNNING); const stoppedNode = registry.tree.root.lookup(stoppedPathParts).when({ parent: () => false, missing: () => true, children: () => false }); expect(stoppedNode).toBe(true); }); it('reassigns new child watchers when a parent watcher is stopped', async function() { const CHILD0 = new MockNative('child0'); const CHILD1 = new MockNative('child1'); const PARENT = new MockNative('parent'); const parentDir = absolute('parent'); const childDir0 = path.join(parentDir, 'child0'); const childDir1 = path.join(parentDir, 'child1'); createNative = dir => { if (dir === parentDir) { return PARENT; } else if (dir === childDir0) { return CHILD0; } else if (dir === childDir1) { return CHILD1; } else { throw new Error(`Unexpected directory ${dir}`); } }; const parentWatcher = new MockWatcher(parentDir); const childWatcher0 = new MockWatcher(childDir0); const childWatcher1 = new MockWatcher(childDir1); await registry.attach(parentWatcher); await Promise.all([ registry.attach(childWatcher0), registry.attach(childWatcher1) ]); // All three watchers should share the parent watcher's native watcher. expect(parentWatcher.native).toBe(PARENT); expect(childWatcher0.native).toBe(PARENT); expect(childWatcher1.native).toBe(PARENT); // Stopping the parent should detach and recreate the child watchers. PARENT.stop(); expect(childWatcher0.native).toBe(CHILD0); expect(childWatcher1.native).toBe(CHILD1); expect( registry.tree.root.lookup(parts(parentDir)).when({ parent: () => false, missing: () => false, children: () => true }) ).toBe(true); expect( registry.tree.root.lookup(parts(childDir0)).when({ parent: () => true, missing: () => false, children: () => false }) ).toBe(true); expect( registry.tree.root.lookup(parts(childDir1)).when({ parent: () => true, missing: () => false, children: () => false }) ).toBe(true); }); it('consolidates children when splitting a parent watcher', async function() { const CHILD0 = new MockNative('child0'); const PARENT = new MockNative('parent'); const parentDir = absolute('parent'); const childDir0 = path.join(parentDir, 'child0'); const childDir1 = path.join(parentDir, 'child0', 'child1'); createNative = dir => { if (dir === parentDir) { return PARENT; } else if (dir === childDir0) { return CHILD0; } else { throw new Error(`Unexpected directory ${dir}`); } }; const parentWatcher = new MockWatcher(parentDir); const childWatcher0 = new MockWatcher(childDir0); const childWatcher1 = new MockWatcher(childDir1); await registry.attach(parentWatcher); await Promise.all([ registry.attach(childWatcher0), registry.attach(childWatcher1) ]); // All three watchers should share the parent watcher's native watcher. expect(parentWatcher.native).toBe(PARENT); expect(childWatcher0.native).toBe(PARENT); expect(childWatcher1.native).toBe(PARENT); // Stopping the parent should detach and create the child watchers. Both child watchers should // share the same native watcher. PARENT.stop(); expect(childWatcher0.native).toBe(CHILD0); expect(childWatcher1.native).toBe(CHILD0); expect( registry.tree.root.lookup(parts(parentDir)).when({ parent: () => false, missing: () => false, children: () => true }) ).toBe(true); expect( registry.tree.root.lookup(parts(childDir0)).when({ parent: () => true, missing: () => false, children: () => false }) ).toBe(true); expect( registry.tree.root.lookup(parts(childDir1)).when({ parent: () => true, missing: () => false, children: () => false }) ).toBe(true); }); }); });