text: 'use strict'
  
  const os = require('os')
  const { join } = require('path')
  const { once } = require('events')
  const { readFile, symlink, unlink } = require('fs').promises
  const { test } = require('tap')
  const { isWin, isYarnPnp, watchFileCreated } = require('./helper')
  const pino = require('../')
  const url = require('url')
  const strip = require('strip-ansi')
  const execa = require('execa')
  const writer = require('flush-write-stream')
  
  const { pid } = process
  const hostname = os.hostname()
  
  async function installTransportModule () {
    if (isYarnPnp) {
      return
    }
    try {
      await uninstallTransportModule()
    } catch {}
    await symlink(
      join(__dirname, 'fixtures', 'transport'),
      join(__dirname, '..', 'node_modules', 'transport')
    )
  }
  
  async function uninstallTransportModule () {
    if (isYarnPnp) {
      return
    }
    await unlink(join(__dirname, '..', 'node_modules', 'transport'))
  }
  
  test('pino.transport with file', async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: join(__dirname, 'fixtures', 'to-file-transport.js'),
      options: { destination }
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with file (no options + error handling)', async ({ equal }) => {
    const transport = pino.transport({
      target: join(__dirname, 'fixtures', 'to-file-transport.js')
    })
    const [err] = await once(transport, 'error')
    equal(err.message, 'kaboom')
  })
  
  // TODO make this test pass on Windows
  test('pino.transport with package', { skip: isWin }, async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
  
    await installTransportModule()
  
    const transport = pino.transport({
      target: 'transport',
      options: { destination }
    })
    teardown(async () => {
      await uninstallTransportModule()
      transport.end()
    })
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with file URL', async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: url.pathToFileURL(join(__dirname, 'fixtures', 'to-file-transport.js')).href,
      options: { destination }
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport errors if file does not exists', ({ plan, pass }) => {
    plan(1)
    const instance = pino.transport({
      target: join(__dirname, 'fixtures', 'non-existent-file'),
      worker: {
        stdin: true,
        stdout: true,
        stderr: true
      }
    })
    instance.on('error', function () {
      pass('error received')
    })
  })
  
  test('pino.transport with esm', async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: join(__dirname, 'fixtures', 'to-file-transport.mjs'),
      options: { destination }
    })
    const instance = pino(transport)
    teardown(transport.end.bind(transport))
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with two files', async ({ same, teardown }) => {
    const dest1 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const dest2 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      targets: [{
        level: 'info',
        target: join(__dirname, 'fixtures', 'to-file-transport.js'),
        options: { destination: dest1 }
      }, {
        level: 'info',
        target: join(__dirname, 'fixtures', 'to-file-transport.js'),
        options: { destination: dest2 }
      }]
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
    const result1 = JSON.parse(await readFile(dest1))
    delete result1.time
    same(result1, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
    const result2 = JSON.parse(await readFile(dest2))
    delete result2.time
    same(result2, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with an array including a pino-pretty destination', async ({ same, match, teardown }) => {
    const dest1 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const dest2 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      targets: [{
        level: 'info',
        target: 'pino/file',
        options: {
          destination: dest1
        }
      }, {
        level: 'info',
        target: 'pino-pretty',
        options: {
          destination: dest2
        }
      }]
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
    const result1 = JSON.parse(await readFile(dest1))
    delete result1.time
    same(result1, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
    const actual = (await readFile(dest2)).toString()
    match(strip(actual), /\[.*\] INFO.*hello/)
  })
  
  test('no transport.end()', async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: join(__dirname, 'fixtures', 'to-file-transport.js'),
      options: { destination }
    })
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('autoEnd = false', async ({ equal, same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const count = process.listenerCount('exit')
    const transport = pino.transport({
      target: join(__dirname, 'fixtures', 'to-file-transport.js'),
      options: { destination },
      worker: { autoEnd: false }
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
  
    equal(count, process.listenerCount('exit'))
  
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with target and targets', async ({ fail, equal }) => {
    try {
      pino.transport({
        target: '/a/file',
        targets: [{
          target: '/a/file'
        }]
      })
      fail('must throw')
    } catch (err) {
      equal(err.message, 'only one of target or targets can be specified')
    }
  })
  
  // TODO make this test pass on Windows
  test('pino.transport with package as a target', { skip: isWin }, async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
  
    await installTransportModule()
  
    const transport = pino.transport({
      targets: [{
        target: 'transport',
        options: { destination }
      }]
    })
    teardown(async () => {
      await uninstallTransportModule()
      transport.end()
    })
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with target pino/file', async ({ same, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: 'pino/file',
      options: { destination }
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'hello'
    })
  })
  
  test('pino.transport with target pino-pretty', async ({ match, teardown }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const transport = pino.transport({
      target: 'pino-pretty',
      options: { destination }
    })
    teardown(transport.end.bind(transport))
    const instance = pino(transport)
    instance.info('hello')
    await watchFileCreated(destination)
    const actual = await readFile(destination, 'utf8')
    match(strip(actual), /\[.*\] INFO.*hello/)
  })
  
  test('stdout in worker', async ({ not }) => {
    let actual = ''
    const child = execa(process.argv[0], [join(__dirname, 'fixtures', 'transport-main.js')])
  
    child.stdout.pipe(writer((s, enc, cb) => {
      actual += s
      cb()
    }))
    await once(child, 'close')
    not(strip(actual).match(/Hello/), null)
  })
  
  test('pino transport options with target', async ({ teardown, same }) => {
    const destination = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const instance = pino({
      transport: {
        target: 'pino/file',
        options: { destination }
      }
    })
    const transportStream = instance[pino.symbols.streamSym]
    teardown(transportStream.end.bind(transportStream))
    instance.info('transport option test')
    await watchFileCreated(destination)
    const result = JSON.parse(await readFile(destination))
    delete result.time
    same(result, {
      pid,
      hostname,
      level: 30,
      msg: 'transport option test'
    })
  })
  
  test('pino transport options with targets', async ({ teardown, same }) => {
    const dest1 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const dest2 = join(
      os.tmpdir(),
      '_' + Math.random().toString(36).substr(2, 9)
    )
    const instance = pino({
      transport: {
        targets: [
          { target: 'pino/file', options: { destination: dest1 } },
          { target: 'pino/file', options: { destination: dest2 } }
        ]
      }
    })
    const transportStream = instance[pino.symbols.streamSym]
    teardown(transportStream.end.bind(transportStream))
    instance.info('transport option test')
  
    await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
    const result1 = JSON.parse(await readFile(dest1))
    delete result1.time
    same(result1, {
      pid,
      hostname,
      level: 30,
      msg: 'transport option test'
    })
    const result2 = JSON.parse(await readFile(dest2))
    delete result2.time
    same(result2, {
      pid,
      hostname,
      level: 30,
      msg: 'transport option test'
    })
  })
  
  test('transport options with target and targets', async ({ fail, equal }) => {
    try {
      pino({
        transport: {
          target: {},
          targets: {}
        }
      })
      fail('must throw')
    } catch (err) {
      equal(err.message, 'only one of target or targets can be specified')
    }
  })
  
  test('transport options with target and stream', async ({ fail, equal }) => {
    try {
      pino({
        transport: {
          target: {}
        }
      }, '/log/null')
      fail('must throw')
    } catch (err) {
      equal(err.message, 'only one of option.transport or stream can be specified')
    }
  })
  