<commit_before>/** @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 () {
    const EXISTING = new MockNative('existing')
    const existingPath = absolute('existing', 'path')
    let firstTime = true<commit_msg>Retry flaky native watcher test<commit_after>/** @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
{'fraction_non_alphanumeric': 0.12080402010050251, 'fraction_numerical': 0.0004020100502512563, 'mean_word_length': 3.1260364842454393, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '349585', 'n_tokens_mistral': 1566, 'n_tokens_neox': 1529, 'n_words': 352}