/** @babel */

import NativeWatcherRegistry from '../src/native-watcher-registry'

class MockWatcher {
  constructor () {
    this.native = null
  }

  attachToNative (native) {
    this.native = native
    this.native.attached.push(this)
  }
}

class MockNative {
  constructor (name) {
    this.name = name
    this.attached = []
    this.disposed = false
    this.stopped = false
  }

  reattachTo (newNative) {
    for (const watcher of this.attached) {
      watcher.attachToNative(newNative)
    }

    this.attached = []
  }

  dispose () {
    this.disposed = true
  }

  stop () {
    this.stopped = true
  }
}

describe('NativeWatcherRegistry', function () {
  let registry, watcher

  beforeEach(function () {
    registry = new NativeWatcherRegistry()
    watcher = new MockWatcher()
  })

  it('attaches a Watcher to a newly created NativeWatcher for a new directory', function () {
    const NATIVE = new MockNative('created')
    registry.attach('/some/path', watcher, () => NATIVE)

    expect(watcher.native).toBe(NATIVE)
  })

  it('reuses an existing NativeWatcher on the same directory', function () {
    const EXISTING = new MockNative('existing')
    registry.attach('/existing/path', new MockWatcher(), () => EXISTING)

    registry.attach('/existing/path', watcher, () => new MockNative('no'))

    expect(watcher.native).toBe(EXISTING)
  })

  it('attaches to an existing NativeWatcher on a parent directory', function () {
    const EXISTING = new MockNative('existing')
    registry.attach('/existing/path', new MockWatcher(), () => EXISTING)

    registry.attach('/existing/path/sub/directory/', watcher, () => new MockNative('no'))

    expect(watcher.native).toBe(EXISTING)
  })

  it('adopts Watchers from NativeWatchers on child directories', function () {
    const EXISTING0 = new MockNative('existing0')
    const watcher0 = new MockWatcher()
    registry.attach('/existing/path/child/directory/zero', watcher0, () => EXISTING0)

    const EXISTING1 = new MockNative('existing1')
    const watcher1 = new MockWatcher()
    registry.attach('/existing/path/child/directory/one', watcher1, () => EXISTING1)

    const EXISTING2 = new MockNative('existing2')
    const watcher2 = new MockWatcher()
    registry.attach('/another/path', watcher2, () => EXISTING2)

    expect(watcher0.native).toBe(EXISTING0)
    expect(watcher1.native).toBe(EXISTING1)
    expect(watcher2.native).toBe(EXISTING2)

    // Consolidate all three watchers beneath the same native watcher on the parent directory
    const CREATED = new MockNative('created')
    registry.attach('/existing/path/', watcher, () => CREATED)

    expect(watcher.native).toBe(CREATED)

    expect(watcher0.native).toBe(CREATED)
    expect(EXISTING0.stopped).toBe(true)
    expect(EXISTING0.disposed).toBe(true)

    expect(watcher1.native).toBe(CREATED)
    expect(EXISTING1.stopped).toBe(true)
    expect(EXISTING1.disposed).toBe(true)

    expect(watcher2.native).toBe(EXISTING2)
    expect(EXISTING2.stopped).toBe(false)
    expect(EXISTING2.disposed).toBe(false)
  })

  it('removes NativeWatchers when all Watchers have been disposed')
})

@@ -8,16 +8,75 @@
 bel */%0A%0A
+import path from 'path'%0Aimport %7BEmitter%7D from 'event-kit'%0A%0A
 import N
@@ -434,16 +434,50 @@
  = false
+%0A%0A    this.emitter = new Emitter()
 %0A  %7D%0A%0A  
@@ -619,16 +619,95 @@
 %5B%5D%0A  %7D%0A%0A
+  onDidStop (callback) %7B%0A    return this.emitter.on('did-stop', callback)%0A  %7D%0A%0A
   dispos
@@ -775,24 +775,58 @@
 pped = true%0A
+    this.emitter.emit('did-stop')%0A
   %7D%0A%7D%0A%0Adescr
@@ -3266,72 +3266,1235 @@
 %0A%0A  
-it('removes NativeWatchers when all Watchers have been disposed'
+describe('removing NativeWatchers', function () %7B%0A    it('happens when they stop', function () %7B%0A      const STOPPED = new MockNative('stopped')%0A      const stoppedWatcher = new MockWatcher()%0A      const stoppedPath = %5B'watcher', 'that', 'will', 'be', 'stopped'%5D%0A      registry.attach(path.join(...stoppedPath), stoppedWatcher, () =%3E STOPPED)%0A%0A      const RUNNING = new MockNative('running')%0A      const runningWatcher = new MockWatcher()%0A      const runningPath = %5B'watcher', 'that', 'will', 'continue', 'to', 'exist'%5D%0A      registry.attach(path.join(...runningPath), runningWatcher, () =%3E RUNNING)%0A%0A      STOPPED.stop()%0A%0A      const runningNode = registry.tree.lookup(runningPath).when(%7B%0A        parent: node =%3E node,%0A        missing: () =%3E false,%0A        children: () =%3E false%0A      %7D)%0A      expect(runningNode).toBeTruthy()%0A      expect(runningNode.getNativeWatcher()).toBe(RUNNING)%0A%0A      const stoppedNode = registry.tree.lookup(stoppedPath).when(%7B%0A        parent: () =%3E false,%0A        missing: () =%3E true,%0A        children: () =%3E false%0A      %7D)%0A      expect(stoppedNode).toBe(true)%0A    %7D)%0A%0A    it(%22keeps a parent watcher that's still running%22)%0A%0A    it('reassigns new child watchers when a parent watcher is stopped')%0A  %7D
 )%0A%7D)

Test NativeWatcher removal