text: const test     = require('tape')
      , through2 = require('../')
      , crypto   = require('crypto')
      , bl       = require('bl')
      , spigot   = require('stream-spigot')
  
  test('plain through', function (t) {
    var th2 = through2(function (chunk, enc, callback) {
      if (!this._i)
        this._i = 97 // 'a'
      else
        this._i++
      var b = new Buffer(chunk.length)
      for (var i = 0; i < chunk.length; i++)
        b[i] = this._i
      this.push(b)
      callback()
    })
  
    th2.pipe(bl(function (err, b) {
      var s = b.toString('ascii')
      t.equal('aaaaaaaaaabbbbbcccccccccc', s, 'got transformed string')
      t.end()
    }))
  
    th2.write(crypto.randomBytes(10))
    th2.write(crypto.randomBytes(5))
    th2.write(crypto.randomBytes(10))
    th2.end()
  })
  
  test('pipeable through', function (t) {
    var th2 = through2(function (chunk, enc, callback) {
      if (!this._i)
        this._i = 97 // 'a'
      else
        this._i++
      var b = new Buffer(chunk.length)
      for (var i = 0; i < chunk.length; i++)
        b[i] = this._i
      this.push(b)
      callback()
    })
  
    th2.pipe(bl(function (err, b) {
      var s = b.toString('ascii')
      // bl() acts like a proper streams2 stream and passes as much as it's
      // asked for, so we really only get one write with such a small amount
      // of data
      t.equal(s, 'aaaaaaaaaaaaaaaaaaaaaaaaa', 'got transformed string')
      t.end()
    }))
  
    var bufs = bl()
    bufs.append(crypto.randomBytes(10))
    bufs.append(crypto.randomBytes(5))
    bufs.append(crypto.randomBytes(10))
    bufs.pipe(th2)
  })
  
  test('object through', function (t) {
    t.plan(3)
  
    var th2 = through2({ objectMode: true}, function (chunk, enc, callback) {
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('object through with through2.obj', function (t) {
    t.plan(3)
  
    var th2 = through2.obj(function (chunk, enc, callback) {
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('flushing through', function (t) {
    var th2 = through2(function (chunk, enc, callback) {
      if (!this._i)
        this._i = 97 // 'a'
      else
        this._i++
      var b = new Buffer(chunk.length)
      for (var i = 0; i < chunk.length; i++)
        b[i] = this._i
      this.push(b)
      callback()
    }, function (callback) {
      this.push(new Buffer([ 101, 110, 100 ]))
      callback()
    })
  
    th2.pipe(bl(function (err, b) {
      var s = b.toString('ascii')
      t.equal(s, 'aaaaaaaaaabbbbbccccccccccend', 'got transformed string')
      t.end()
    }))
  
    th2.write(crypto.randomBytes(10))
    th2.write(crypto.randomBytes(5))
    th2.write(crypto.randomBytes(10))
    th2.end()
  })
  
  test('plain through ctor', function (t) {
    var Th2 = through2.ctor(function (chunk, enc, callback) {
      if (!this._i)
        this._i = 97 // 'a'
      else
        this._i++
      var b = new Buffer(chunk.length)
      for (var i = 0; i < chunk.length; i++)
        b[i] = this._i
      this.push(b)
      callback()
    })
  
    var th2 = new Th2()
  
    th2.pipe(bl(function (err, b) {
      var s = b.toString('ascii')
      t.equal('aaaaaaaaaabbbbbcccccccccc', s, 'got transformed string')
      t.end()
    }))
  
    th2.write(crypto.randomBytes(10))
    th2.write(crypto.randomBytes(5))
    th2.write(crypto.randomBytes(10))
    th2.end()
  })
  
  test('reuse through ctor', function (t) {
    t.plan(4)
  
    var Th2 = through2.ctor(function (chunk, enc, callback) {
      if (!this._i) {
        t.ok(1, 'did not contain previous instance data (this._i)')
        this._i = 97 // 'a'
      } else
        this._i++
      var b = new Buffer(chunk.length)
      for (var i = 0; i < chunk.length; i++)
        b[i] = this._i
      this.push(b)
      callback()
    })
  
    var th2 = Th2()
  
    th2.pipe(bl(function (err, b) {
      var s = b.toString('ascii')
      t.equal('aaaaaaaaaabbbbbcccccccccc', s, 'got transformed string')
  
      var newInstance = Th2()
      newInstance.pipe(bl(function (err, b) {
        var s = b.toString('ascii')
        t.equal('aaaaaaabbbbccccccc', s, 'got transformed string')
      }))
  
      newInstance.write(crypto.randomBytes(7))
      newInstance.write(crypto.randomBytes(4))
      newInstance.write(crypto.randomBytes(7))
      newInstance.end()
    }))
  
    th2.write(crypto.randomBytes(10))
    th2.write(crypto.randomBytes(5))
    th2.write(crypto.randomBytes(10))
    th2.end()
  })
  
  test('object through ctor', function (t) {
    t.plan(3)
  
    var Th2 = through2.ctor({ objectMode: true}, function (chunk, enc, callback) {
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var th2 = new Th2()
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('pipeable object through ctor', function (t) {
    t.plan(4)
  
    var Th2 = through2.ctor({ objectMode: true}, function (record, enc, callback) {
      if (record.temp != null && record.unit == 'F') {
        record.temp = ( ( record.temp - 32 ) * 5 ) / 9
        record.unit = 'C'
      }
      this.push(record)
      callback()
    })
  
    var th2 = Th2()
  
    var expect = [-19, -40, 100, 22]
    th2.on('data', function (o) {
      t.deepEqual(o, { temp: expect.shift(), unit: 'C' }, 'got transformed object')
    })
  
    spigot({objectMode: true}, [
      {temp: -2.2, unit: 'F'},
      {temp: -40, unit: 'F'},
      {temp: 212, unit: 'F'},
      {temp: 22, unit: 'C'}
    ]).pipe(th2)
  })
  
  test('object through ctor override', function (t) {
    t.plan(3)
  
    var Th2 = through2.ctor(function (chunk, enc, callback) {
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var th2 = Th2({objectMode: true})
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('object settings available in transform', function (t) {
    t.plan(6)
  
    var Th2 = through2.ctor({objectMode: true, peek: true}, function (chunk, enc, callback) {
      t.ok(this.options.peek, "reading options from inside _transform")
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var th2 = Th2()
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('object settings available in transform override', function (t) {
    t.plan(6)
  
    var Th2 = through2.ctor(function (chunk, enc, callback) {
      t.ok(this.options.peek, "reading options from inside _transform")
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var th2 = Th2({objectMode: true, peek: true})
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('object override extends options', function (t) {
    t.plan(6)
  
    var Th2 = through2.ctor({objectMode: true}, function (chunk, enc, callback) {
      t.ok(this.options.peek, "reading options from inside _transform")
      this.push({ out: chunk.in + 1 })
      callback()
    })
  
    var th2 = Th2({peek: true})
  
    var e = 0
    th2.on('data', function (o) {
      t.deepEqual(o, { out: e === 0 ? 102 : e == 1 ? 203 : -99 }, 'got transformed object')
      e++
    })
  
    th2.write({ in: 101 })
    th2.write({ in: 202 })
    th2.write({ in: -100 })
    th2.end()
  })
  
  test('can be destroyed', function(t) {
    t.plan(1)
  
    var th = through2()
  
    th.on('close', function() {
      t.ok(true, 'shoud emit close')
      t.end()
    })
  
    th.destroy()
  })
  
  test('can be destroyed twice', function(t) {
    t.plan(1)
  
    var th = through2()
  
    th.on('close', function() {
      t.ok(true, 'shoud emit close')
      t.end()
    })
  
    th.destroy()
    th.destroy()
  })