<commit_before>var sys = require('sys');
var logger = require('./logger');
var Util = require('./util');

/**
 * This class manages the block chain and block chain downloads.
 */
var BlockChainManager = exports.BlockChainManager = function (blockChain, peerManager) {
  events.EventEmitter.call(this);

  this.blockChain = blockChain;
  this.peerManager = peerManager;
  this.enabled = false;
  this.timer = null;

  this.lastSeenTop = new Buffer(0);

  // Cache for the single inv other nodes send as a "tickle" to indicate
  // there are more blocks to be downloaded.
  this.tickle = null;

  // Move these to the Node's settings object
  this.checkInterval = 5000;
  this.downloadTimeout = 25000;

  this.peerManager.on('connect', this.handleConnect.bind(this));
  this.blockChain.on('blockSave', this.handleBlockSave.bind(this));
  this.blockChain.on('queueDone', this.handleQueueDone.bind(this));
};

sys.inherits(BlockChainManager, events.EventEmitter);

BlockChainManager.prototype.enable = function ()
{
  this.enabled = true;

  if (!this.timer) {
    this.pingStatus();
  }
};

BlockChainManager.prototype.disable = function ()
{
  this.enabled = false;
};

BlockChainManager.prototype.pingStatus = function ()
{
  if (!this.enabled) {
    return;
  }

  var time = new Date().getTime();
  if (this.currentDownload &&
    this.currentDownload.lastPing < (time - this.downloadTimeout)) {
    this.currentDownload.handleTimeout();
  }

  this.timer = setTimeout(this.pingStatus.bind(this), this.checkInterval);
};

BlockChainManager.prototype.handleConnect = function ()
{
  if (this.enabled &&
      this.currentDownload == null) {
     this.startDownload();
  }
};

BlockChainManager.prototype.handleBlockSave = function handleBlockSave(e)
{
  var curTop = this.blockChain.getTopBlock().getHash();
  if (this.lastSeenTop.compare(curTop) != 0) {
    if (this.currentDownload) {
      this.currentDownload.resetTimeout();
    }
    this.lastSeenTop = curTop;
  }
};

BlockChainManager.prototype.handleQueueDone = function handleQueueDone(e)
{
  if (Buffer.isBuffer(this.tickle)) {
    this.startDownload(this.tickle);
    this.tickle = null;
  } else if (!this.currentDownload) {
    this.startDownload();
  }
};

BlockChainManager.prototype.startDownload = function (toHash, fromHash, conn)
{
  var self = this;

  // If we don't get a specific block to download towards, we use a zero hash
  // to indicate we want as many blocks as possible.
  if (!toHash) {
    toHash = Util.NULL_HASH;
  }

  // We won't actively solicit more blocks while we're still busy processing
  // other ones.
  if (this.blockChain.getQueueCount() !== 0) {
    // But in that case we want the download to automatically start once the
    // current processing is done. See handleQueueDone.
    this.tickle = toHash;
    return;
  }

  if (!fromHash) {
    var topBlock = this.blockChain.getTopBlock();
    if (topBlock) {
      fromHash = topBlock.getHash();
    } else {
      throw new Error("BlockChainManager.startDownload(): Block chain is not"
                      + " yet initialized");
    }
  }

  try {
    this.currentDownload = new BlockChainDownload(this, this.blockChain,
                                                  toHash, fromHash, conn);

    // A block chain download is considered successful when the remote node
    // sends the single hash inv to prompt us to start the next batch.
    this.currentDownload.on('success', function handleDownloadSuccess(e) {
      // Start another download for the next batch of blocks
      this.startDownload(e.invs[0].hash);
    }.bind(this));

    // Handle block chain download timeout
    this.currentDownload.on('timeout', function handleTimeout(e) {
      // We need to nextTick this, because there will be a "close" event
      // after this one that needs to be processed first.
      process.nextTick(function () {
        this.startDownload();
      }.bind(this));
    }.bind(this));

    this.currentDownload.on('close', function handleDownloadEnd() {
      this.currentDownload = null;
    }.bind(this));

    this.currentDownload.start();
  } catch (err) {
    logger.error('Error while initiating block chain download: ', err);
    return;
  }
};

BlockChainManager.prototype.getConnection = function ()
{
  var conn = this.peerManager.getActiveConnection();
  if (!conn) {
    throw new Error("BlockChainManager().getConnection(): No suitable "+
                    "connection available for block chain download");
  }
  return conn;
};

var BlockChainDownload = exports.BlockChainDownload =
  function BlockChainDownload(bcm, blockChain, toHash, fromHash, conn)
{
  events.EventEmitter.call(this);

  this.bcm = bcm;
  this.conn = conn || null;
  this.locator = null;
  this.blockChain = blockChain;
  this.toHash = toHash;
  this.fromHash = fromHash;

  this.timer = null;

  this.closed = false;

  // Number of milliseconds after which we consider the download timed
  // out. Should be moved to network settings.
  this.maxDuration = 30000;

  // Bind event handlers - we do this here instead of inline so that we can
  // later reference them when we want to remove them.
  this.handleInv = this.handleInv.bind(this);
  this.handleBlock = this.handleBlock.bind(this);
  this.handleDisconnect = this.handleDisconnect.bind(this);
};

sys.inherits(BlockChainDownload, events.EventEmitter);

BlockChainDownload.prototype.start = function start()
{
  if (this.closed) {
    throw new Error("BlockChainDownload.start(): BlockChainDownload " +
                    "instances cannot be re-used.");
  }

  var genesisBlock = this.blockChain.getGenesisBlock();
  var topBlock = this.blockChain.getTopBlock();

  this.blockChain.getBlockLocator((function (err, locator) {
    if (err) {
      logger.error('Error while creating block locator: ', err);
      return;
    }

    this.locator = locator;
    // TODO: Figure out a way to spread load across peers
    if (!this.conn) {
      this.conn = this.bcm.getConnection();
    }

    locator.push(genesisBlock.hash);

    if (this.fromHash && this.fromHash.compare(locator[0]) !== 0) {
      locator.unshift(this.fromHash);
    }

    // Create some nicely formatted info about the chain height
    var heightInfo = '';
    if (topBlock.height < this.conn.bestHeight) {
      var curHeight = ""+topBlock.height;
      var maxHeight = ""+this.conn.bestHeight;
      while (curHeight.length < maxHeight.length) {
        curHeight = " "+curHeight;
      }
      heightInfo = ' '+curHeight+'/'+maxHeight;
    }

    var queueCount = this.blockChain.getQueueCount();

    logger.info('Downloading blocks'+heightInfo+
                ' (top: '+Util.formatHashAlt(locator[0])+
                ', queued: '+queueCount+
                ', peer: '+this.conn.peer+')');

    this.conn.sendGetBlocks(this.locator, this.toHash);

    // Event handlers are already bound, see constructor for more info
    this.conn.on('inv', this.handleInv);
    this.conn.on('block', this.handleBlock);
    this.conn.on('disconnect', this.handleDisconnect);

    this.lastPing = new Date().getTime();
  }).bind(this));
};

BlockChainDownload.prototype.handleInv = function handleInv(e) {
  var invs = e.message.invs;

  // The remote side will send an inv with a single block to signify the
  // download is complete.
  if (invs.length == 1 && invs[0].type == 2) {
    this.emit('success', {
      invs: invs
    });
    this.close();
  }
};

BlockChainDownload.prototype.handleBlock = function handleBlock(e) {
  // TODO: We should make sure the block actually makes it into the block
  //       chain, otherwise an evil peer could "string us along" forever.
  this.resetTimeout();
};

BlockChainDownload.prototype.handleDisconnect = function handleDisconnect() {
  this.close();
};

BlockChainDownload.prototype.handleTimeout = function handleTimeout() {
  logger.bchdbg('No new blocks received from '+this.conn.peer);

  this.emit('timeout');
  this.close();
};

BlockChainDownload.prototype.close = function close() {
  if (this.closed) return;

  if (this.timer) clearTimeout(this.timer);

  this.conn.removeListener('inv', this.handleInv);
  this.conn.removeListener('block', this.handleBlock);
  this.conn.removeListener('disconnect', this.handleDisconnect);

  this.emit('close');

  this.closed = true;
};

BlockChainDownload.prototype.resetTimeout = function ()
{
  this.lastPing = new Date().getTime();
};
<commit_msg>Possible fix for "multiple block downloads started at once" bug. See #33.<commit_after>var sys = require('sys');
var logger = require('./logger');
var Util = require('./util');

/**
 * This class manages the block chain and block chain downloads.
 */
var BlockChainManager = exports.BlockChainManager = function (blockChain, peerManager) {
  events.EventEmitter.call(this);

  this.blockChain = blockChain;
  this.peerManager = peerManager;
  this.enabled = false;
  this.timer = null;

  this.lastSeenTop = new Buffer(0);

  // Cache for the single inv other nodes send as a "tickle" to indicate
  // there are more blocks to be downloaded.
  this.tickle = null;

  // Move these to the Node's settings object
  this.checkInterval = 5000;
  this.downloadTimeout = 25000;

  this.peerManager.on('connect', this.handleConnect.bind(this));
  this.blockChain.on('blockSave', this.handleBlockSave.bind(this));
  this.blockChain.on('queueDone', this.handleQueueDone.bind(this));
};

sys.inherits(BlockChainManager, events.EventEmitter);

BlockChainManager.prototype.enable = function ()
{
  this.enabled = true;

  if (!this.timer) {
    this.pingStatus();
  }
};

BlockChainManager.prototype.disable = function ()
{
  this.enabled = false;
};

BlockChainManager.prototype.pingStatus = function ()
{
  if (!this.enabled) {
    return;
  }

  var time = new Date().getTime();
  if (this.currentDownload &&
    this.currentDownload.lastPing < (time - this.downloadTimeout)) {
    this.currentDownload.handleTimeout();
  }

  this.timer = setTimeout(this.pingStatus.bind(this), this.checkInterval);
};

BlockChainManager.prototype.handleConnect = function ()
{
  if (this.enabled &&
      this.currentDownload == null) {
     this.startDownload();
  }
};

BlockChainManager.prototype.handleBlockSave = function handleBlockSave(e)
{
  var curTop = this.blockChain.getTopBlock().getHash();
  if (this.lastSeenTop.compare(curTop) != 0) {
    if (this.currentDownload) {
      this.currentDownload.resetTimeout();
    }
    this.lastSeenTop = curTop;
  }
};

BlockChainManager.prototype.handleQueueDone = function handleQueueDone(e)
{
  if (Buffer.isBuffer(this.tickle)) {
    this.startDownload(this.tickle);
    this.tickle = null;
  } else if (!this.currentDownload) {
    this.startDownload();
  }
};

BlockChainManager.prototype.startDownload = function (toHash, fromHash, conn)
{
  var self = this;

  // If we don't get a specific block to download towards, we use a zero hash
  // to indicate we want as many blocks as possible.
  if (!toHash) {
    toHash = Util.NULL_HASH;
  }

  // We won't actively solicit more blocks while we're still busy processing
  // other ones.
  if (this.blockChain.getQueueCount() !== 0) {
    // But in that case we want the download to automatically start once the
    // current processing is done. See handleQueueDone.
    this.tickle = toHash;
    return;
  }

  if (!fromHash) {
    var topBlock = this.blockChain.getTopBlock();
    if (topBlock) {
      fromHash = topBlock.getHash();
    } else {
      throw new Error("BlockChainManager.startDownload(): Block chain is not"
                      + " yet initialized");
    }
  }

  try {
    this.currentDownload = new BlockChainDownload(this, this.blockChain,
                                                  toHash, fromHash, conn);

    // A block chain download is considered successful when the remote node
    // sends the single hash inv to prompt us to start the next batch.
    this.currentDownload.on('success', function handleDownloadSuccess(e) {
      // Start another download for the next batch of blocks
      this.startDownload(e.invs[0].hash, null, e.conn);
    }.bind(this));

    // Handle block chain download timeout
    this.currentDownload.on('timeout', function handleTimeout(e) {
      // We need to nextTick this, because there will be a "close" event
      // after this one that needs to be processed first.
      process.nextTick(function () {
        this.startDownload();
      }.bind(this));
    }.bind(this));

    this.currentDownload.on('close', function handleDownloadEnd() {
      this.currentDownload = null;
    }.bind(this));

    this.currentDownload.start();
  } catch (err) {
    logger.error('Error while initiating block chain download: ', err);
    return;
  }
};

BlockChainManager.prototype.getConnection = function ()
{
  var conn = this.peerManager.getActiveConnection();
  if (!conn) {
    throw new Error("BlockChainManager().getConnection(): No suitable "+
                    "connection available for block chain download");
  }
  return conn;
};

var BlockChainDownload = exports.BlockChainDownload =
  function BlockChainDownload(bcm, blockChain, toHash, fromHash, conn)
{
  events.EventEmitter.call(this);

  this.bcm = bcm;
  this.conn = conn || null;
  this.locator = null;
  this.blockChain = blockChain;
  this.toHash = toHash;
  this.fromHash = fromHash;

  this.timer = null;

  this.closed = false;

  // Number of milliseconds after which we consider the download timed
  // out. Should be moved to network settings.
  this.maxDuration = 30000;

  // Bind event handlers - we do this here instead of inline so that we can
  // later reference them when we want to remove them.
  this.handleInv = this.handleInv.bind(this);
  this.handleBlock = this.handleBlock.bind(this);
  this.handleDisconnect = this.handleDisconnect.bind(this);
};

sys.inherits(BlockChainDownload, events.EventEmitter);

BlockChainDownload.prototype.start = function start()
{
  if (this.closed) {
    throw new Error("BlockChainDownload.start(): BlockChainDownload " +
                    "instances cannot be re-used.");
  }

  var genesisBlock = this.blockChain.getGenesisBlock();
  var topBlock = this.blockChain.getTopBlock();

  this.blockChain.getBlockLocator((function (err, locator) {
    if (err) {
      logger.error('Error while creating block locator: ', err);
      return;
    }

    this.locator = locator;
    // TODO: Figure out a way to spread load across peers
    if (!this.conn) {
      this.conn = this.bcm.getConnection();
    }

    locator.push(genesisBlock.hash);

    if (this.fromHash && this.fromHash.compare(locator[0]) !== 0) {
      locator.unshift(this.fromHash);
    }

    // Create some nicely formatted info about the chain height
    var heightInfo = '';
    if (topBlock.height < this.conn.bestHeight) {
      var curHeight = ""+topBlock.height;
      var maxHeight = ""+this.conn.bestHeight;
      while (curHeight.length < maxHeight.length) {
        curHeight = " "+curHeight;
      }
      heightInfo = ' '+curHeight+'/'+maxHeight;
    }

    var queueCount = this.blockChain.getQueueCount();

    logger.info('Downloading blocks'+heightInfo+
                ' (top: '+Util.formatHashAlt(locator[0])+
                ', queued: '+queueCount+
                ', peer: '+this.conn.peer+')');

    this.conn.sendGetBlocks(this.locator, this.toHash);

    // Event handlers are already bound, see constructor for more info
    this.conn.on('inv', this.handleInv);
    this.conn.on('block', this.handleBlock);
    this.conn.on('disconnect', this.handleDisconnect);

    this.lastPing = new Date().getTime();
  }).bind(this));
};

BlockChainDownload.prototype.handleInv = function handleInv(e) {
  var invs = e.message.invs;

  // The remote side will send an inv with a single block to signify the
  // download is complete.
  if (invs.length == 1 && invs[0].type == 2) {
    this.emit('success', {
      invs: invs,
      conn: e.conn
    });
    this.close();
  }
};

BlockChainDownload.prototype.handleBlock = function handleBlock(e) {
  // TODO: We should make sure the block actually makes it into the block
  //       chain, otherwise an evil peer could "string us along" forever.
  this.resetTimeout();
};

BlockChainDownload.prototype.handleDisconnect = function handleDisconnect() {
  this.close();
};

BlockChainDownload.prototype.handleTimeout = function handleTimeout() {
  logger.bchdbg('No new blocks received from '+this.conn.peer);

  this.emit('timeout');
  this.close();
};

BlockChainDownload.prototype.close = function close() {
  if (this.closed) return;

  if (this.timer) clearTimeout(this.timer);

  this.conn.removeListener('inv', this.handleInv);
  this.conn.removeListener('block', this.handleBlock);
  this.conn.removeListener('disconnect', this.handleDisconnect);

  this.emit('close');

  this.closed = true;
};

BlockChainDownload.prototype.resetTimeout = function ()
{
  this.lastPing = new Date().getTime();
};
<|endoftext|>


<commit_before>/**
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author ebidel@ (Eric Bidelman)
 */

/**
 * Takes a screenshot of the latest tweet in a user's timeline and creates a
 * PDF of it. Shows how to use Puppeteer to:
 *
 *   1. screenshot a DOM element
 *   2. craft an HTML page on-th-fly.
 *   3. produce an image of the element and PDF of the page with the image embedded.
 *
 * Usage:
 *   node element-to-pdf.js
 *   USERNAME=ChromiumDev node element-to-pdf.js
 *
 * Output:
 *   tweet.png and tweet.pdf
 */
const puppeteer = require('puppeteer');

const username = process.env.USERNAME || 'ebidel';

(async() => {

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page.setViewport({width: 1200, height: 800, deviceScaleFactor: 2});
await page.goto(`https://twitter.com/${username}`);

// Can't use elementHandle.click() because it clicks the center of the element
// with the mouse. On tweets like https://twitter.com/ebidel/status/915996563234631680
// there is an embedded card link to another tweet that it clicks.
await page.$eval(`.tweet[data-screen-name="${username}"]`, tweet => tweet.click());
await page.waitForSelector('.tweet.permalink-tweet', {visible: true});

const overlay = await page.$('.tweet.permalink-tweet');
const screenshot = await overlay.screenshot({path: 'tweet.png'});

await page.setContent(`

`);

await page.emulateMedia('screen'); // technically unnecessary
await page.pdf({path: 'tweet.pdf', printBackground: true});

await browser.close();

})();
<commit_msg>Avoid quirks mode<commit_after>/**
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author ebidel@ (Eric Bidelman)
 */

/**
 * Takes a screenshot of the latest tweet in a user's timeline and creates a
 * PDF of it. Shows how to use Puppeteer to:
 *
 *   1. screenshot a DOM element
 *   2. craft an HTML page on-th-fly.
 *   3. produce an image of the element and PDF of the page with the image embedded.
 *
 * Usage:
 *   node element-to-pdf.js
 *   USERNAME=ChromiumDev node element-to-pdf.js
 *
 * Output:
 *   tweet.png and tweet.pdf
 */
const puppeteer = require('puppeteer');

const username = process.env.USERNAME || 'ebidel';

(async() => {

const browser = await puppeteer.launch();

const page = await browser.newPage();
await page.setViewport({width: 1200, height: 800, deviceScaleFactor: 2});
await page.goto(`https://twitter.com/${username}`);

// Can't use elementHandle.click() because it clicks the center of the element
// with the mouse. On tweets like https://twitter.com/ebidel/status/915996563234631680
// there is an embedded card link to another tweet that it clicks.
await page.$eval(`.tweet[data-screen-name="${username}"]`, tweet => tweet.click());
await page.waitForSelector('.tweet.permalink-tweet', {visible: true});

const overlay = await page.$('.tweet.permalink-tweet');
const screenshot = await overlay.screenshot({path: 'tweet.png'});

await page.setContent(`
  <!DOCTYPE html>

`);

await page.emulateMedia('screen'); // technically unnecessary
await page.pdf({path: 'tweet.pdf', printBackground: true});

await browser.close();

})();
<|endoftext|>


<commit_before>var SubLevel = require('level-sublevel')
var level    = require('level-test')()
var delay    = require('delay-stream')
var Model    = require('scuttlebutt/model')
var tape     = require('tape')

tape('test replication', function (t) {

var A, B

  function randomData(db, id, cb) {
    require('..')(db, id, {
      test: function () {
        return Model()
      }
    })

    db.scuttlebutt('test1', function (err, emitter) {
      var letters = "ABCDEFGHIJK"
      var l = 5

      while(l --> 0)
        emitter.set(letters[~~(Math.random()*letters.length)], 'Date: ' + new Date())

      setTimeout(cb, 1000)

    })
  }

  randomData(A = SubLevel(level('level-scuttlebutt-test-A')), 'A', next)
  randomData(B = SubLevel(level('level-scuttlebutt-test-B')), 'B', next)

  var z = 2

  function next() {
    if(--z) return
    var streamA = A.scuttlebutt.createReplicateStream({tail: false})
    var streamB = B.scuttlebutt.createReplicateStream({tail: false})

    streamA.pipe(delay(100)).pipe(streamB).pipe(delay(100)).pipe(streamA)

    streamA.pipe(process.stderr, {end: false})
    streamB.pipe(process.stderr, {end: false})

    var n = 2, vecA, vecB

    streamA.on('end', function () {
      A.scuttlebutt.vectorClock(function (err, vec) {
        console.log('streamA end')
        vecA = vec; next()
      })
    })

    streamB.on('end', function () {
      B.scuttlebutt.vectorClock(function (err, vec) {
        console.log('streamB end')
        vecB = vec; next()
      })
    })

    function next() {
      if(--n) return
      console.log(vecA, vecB)
      t.deepEqual(vecA, vecB)
      t.end()
    }
  }

})
<commit_msg>more debuggable<commit_after>var SubLevel = require('level-sublevel')
var level    = require('level-test')()
var delay    = require('delay-stream')
var Model    = require('scuttlebutt/model')
var tape     = require('tape')

tape('test replication', function (t) {

var A, B

  function randomData(db, id, cb) {
    require('..')(db, id, {
      test: function () {
        return Model()
      }
    })

    db.sublevel('sb')
      .post(function (op) {
        console.error(op)
        if(undefined === op.value && op.type !== 'del')
          throw new Error('value is undefined')
      })

    db.scuttlebutt('test1', function (err, emitter) {
      var letters = "ABCDEFGHIJK"
      var l = 5

      while(l --> 0)
        emitter.set(letters[~~(Math.random()*letters.length)], 'Date: ' + new Date())

      setTimeout(cb, 1000)

    })
  }

  randomData(A = SubLevel(level('level-scuttlebutt-test-A', {encoding: 'utf8'})), 'A', next)
  randomData(B = SubLevel(level('level-scuttlebutt-test-B'), {encoding: 'utf8'}), 'B', next)

  var z = 2

  function next() {
    if(--z) return
    var streamA = A.scuttlebutt.createReplicateStream({tail: false})
    var streamB = B.scuttlebutt.createReplicateStream({tail: false})

    streamA.pipe(delay(100)).pipe(streamB).pipe(delay(100)).pipe(streamA)

    streamA.pipe(process.stderr, {end: false})
    streamB.pipe(process.stderr, {end: false})

    var n = 2, vecA, vecB

    streamA.on('end', function () {
      A.scuttlebutt.vectorClock(function (err, vec) {
        console.log('streamA end')
        vecA = vec; next()
      })
    })

    streamB.on('end', function () {
      B.scuttlebutt.vectorClock(function (err, vec) {
        console.log('streamB end')
        vecB = vec; next()
      })
    })

    function next() {
      if(--n) return
      console.log(vecA, vecB)
      t.deepEqual(vecA, vecB)
      t.end()
    }
  }

})
<|endoftext|>


<commit_before>'use strict';

module.exports = function(){
  const Server = require('../lib/server'),
        test = new Server();

  test.on('connection', function(client){
    client.on('test', function(data){
      console.log(data);
    });

    client.error('invalid json', function(a){
      console.log(a);
    });
  });

  test.listen(8000);
};
<commit_msg>Update test for chaining<commit_after>'use strict';

module.exports = function(){
  const Server = require('../lib/server'),
        test = new Server();

  test.on('connection', function(client){
    client.on('test', function(data){
      console.log(data);
    }).error('invalid json', function(a){
      console.log(a);
    });
  });

  test.listen(8000);
};
<|endoftext|>


<commit_before>
/**
 * Tests dependencies.
 */

var parser = require('../lib/parser')
  , WebSocket = require('ws')

/**
 * Tests.
 */

describe('server', function () {

  describe('verification', function () {
    it('should disallow non-existent transports', function (done) {
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'tobi' }) // no tobi transport - outrageous
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });

    it('should disallow `constructor` as transports', function (done) {
      // make sure we check for actual properties - not those present on every {}
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'constructor' })
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });

    it('should disallow non-existent sids', function (done) {
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'polling', sid: 'test' })
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });
  });

  describe('handshake', function () {
    it('should register a new client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        expect(Object.keys(engine.clients)).to.have.length(0);
        expect(engine.clientsCount).to.be(0);

        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          expect(Object.keys(engine.clients)).to.have.length(1);
          expect(engine.clientsCount).to.be(1);
          done();
        });
      });
    });

    it('should exchange handshake data', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.sid).to.be.a('string');
          expect(obj.pingInterval).to.be.a('number');
          expect(obj.pingTimeout).to.be.a('number');
          expect(obj.upgrades).to.be.an('array');
          done();
        });
      });
    });

    it('should allow custom ping intervals', function (done) {
      var engine = listen({ allowUpgrades: false, pingInterval: 123 }, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.pingInterval).to.be(123);
          done();
        });
      });
    });

    it('should allow custom ping timeouts', function (done) {
      var engine = listen({ allowUpgrades: false, pingTimeout: 123 }, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.pingTimeout).to.be(123);
          done();
        });
      });
    });

    it('should trigger a connection event with a Socket', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (socket) {
          expect(socket).to.be.an(eio.Socket);
          done();
        });
      });
    });

    it('should open with polling by default', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (socket) {
          expect(socket.transport.name).to.be('polling');
          done();
        });
      });
    });

    it('should be able to open with ws directly', function (done) {
      var engine = listen({ transports: ['websocket'] }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        engine.on('connection', function (socket) {
          expect(socket.transport.name).to.be('websocket');
          done();
        });
      });
    });

    it('should not suggest any upgrades for websocket', function (done) {
      var engine = listen({ transports: ['websocket'] }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        socket.on('handshake', function (obj) {
          expect(obj.upgrades).to.have.length(0);
          done();
        });
      });
    });

    it('should allow arbitrary data through query string', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { query: { a: 'b' } });
        engine.on('connection', function (conn) {
          expect(conn.req.query).to.have.keys('transport', 'a');
          expect(conn.req.query.a).to.be('b');
          done();
        });
      });
    });
  });

  describe('close', function () {
    it('should trigger on server if the client does not pong', function (done) {
      var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 }
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.sendPacket = function (){};
        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('ping timeout');
            done();
          });
        });
      });
    });

    it('should trigger on client if server does not meet ping freq', function (done) {
      var opts = { allowUpgrades: false, pingInterval: 10 };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          // override onPacket to simulate an inactive server after handshake
          socket.onPacket = function(){};
          socket.on('close', function (reason, err) {
            expect(reason).to.be('ping timeout');
            done();
          });
        });
      });
    });

    it('should trigger on both ends upon ping timeout', function (done) {
      var opts = { allowUpgrades: false, pingTimeout: 10, pingInterval: 10 };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        function onClose (reason, err) {
          expect(reason).to.be('ping timeout');
          --total || done();
        }

        engine.on('connection', function (conn) {
          conn.on('close', onClose);
        });

        socket.on('open', function () {
          // override onPacket to simulate an inactive server after handshake
          socket.onPacket = socket.sendPacket = function(){};
          socket.on('close', onClose);
        });
      });
    });

    it('should trigger when server closes a client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });
          setTimeout(function () {
            conn.close();
          }, 10);
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });
      });
    });

    it('should trigger when server closes a client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });
          setTimeout(function () {
            conn.close();
          }, 10);
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });
      });
    });

    it('should trigger when client closes', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });

          setTimeout(function () {
            socket.close();
          }, 10);
        });
      });
    });

    it('should trigger when client closes (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });

          setTimeout(function () {
            socket.close();
          }, 10);
        });
      });
    });
  });

  describe('messages', function () {
    it('should arrive from server to client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (conn) {
          conn.send('a');
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be('a');
            done();
          });
        });
      });
    });

    it('should arrive from server to client (multiple)', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , expected = ['a', 'b', 'c']
          , i = 0

        engine.on('connection', function (conn) {
          conn.send('a');
          // we use set timeouts to ensure the messages are delivered as part
          // of different.
          setTimeout(function () {
            conn.send('b');

            setTimeout(function () {
              // here we make sure we buffer both the close packet and
              // a regular packet
              conn.send('c');
              conn.close();
            }, 50);
          }, 50);

          conn.on('close', function () {
            // since close fires right after the buffer is drained
            setTimeout(function () {
              expect(i).to.be(3);
              done();
            }, 50);
          });
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be(expected[i++]);
          });
        });
      });
    });

    it('should arrive from server to client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        engine.on('connection', function (conn) {
          conn.send('a');
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be('a');
            done();
          });
        });
      });
    });

    it('should arrive from server to client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , expected = ['a', 'b', 'c']
          , i = 0
        engine.on('connection', function (conn) {
          conn.send('a');
          setTimeout(function () {
            conn.send('b');
            setTimeout(function () {
              conn.send('c');
              conn.close();
            }, 50);
          }, 50);
          conn.on('close', function () {
            setTimeout(function () {
              expect(i).to.be(3);
              done();
            }, 50);
          });
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be(expected[i++]);
          });
        });
      });
    });
  });

  describe('upgrade', function () {
    it('should upgrade', function (done) {
      var engine = listen(function (port) {
        // it takes both to send 50 to verify
        var ready = 2, closed = 2;
        function finish () {
          setTimeout(function () {
            socket.close();
          }, 10);
        }

        // server
        engine.on('connection', function (conn) {
          var lastSent = 0, lastReceived = 0, upgraded = false;
          var interval = setInterval(function () {
            lastSent++;
            conn.send(lastSent);
            if (50 == lastSent) {
              clearInterval(interval);
              --ready || finish();
            }
          }, 2);

          conn.on('message', function (msg) {
            lastReceived++;
            expect(msg).to.eql(lastReceived);
          });

          conn.on('upgrade', function (to) {
            upgraded = true;
            expect(to.name).to.be('websocket');
          });

          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            expect(lastSent).to.be(50);
            expect(lastReceived).to.be(50);
            expect(upgraded).to.be(true);
            --closed || done();
          });
        });

        // client
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          var lastSent = 0, lastReceived = 0, upgrades = 0;
          var interval = setInterval(function () {
            lastSent++;
            socket.send(lastSent);
            if (50 == lastSent) {
              clearInterval(interval);
              --ready || finish();
            }
          }, 2);
          socket.on('upgrading', function (to) {
            // we want to make sure for the sake of this test that we have a buffer
            expect(to.name).to.equal('websocket');
            upgrades++;

            // force send a few packets to ensure we test buffer transfer
            lastSent++;
            socket.send(lastSent);
            lastSent++;
            socket.send(lastSent);

            expect(socket.writeBuffer).to.not.be.empty();
          });
          socket.on('upgrade', function (to) {
            expect(to.name).to.equal('websocket');
            upgrades++;
          });
          socket.on('message', function (msg) {
            lastReceived++;
            expect(lastReceived).to.eql(msg);
          });
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            expect(lastSent).to.be(50);
            expect(lastReceived).to.be(50);
            expect(upgrades).to.be(2);
            --closed || done();
          });
        });
      });
    });
  });

});
<commit_msg>Fixed ping tests.<commit_after>
/**
 * Tests dependencies.
 */

var parser = require('../lib/parser')
  , WebSocket = require('ws')

/**
 * Tests.
 */

describe('server', function () {

  describe('verification', function () {
    it('should disallow non-existent transports', function (done) {
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'tobi' }) // no tobi transport - outrageous
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });

    it('should disallow `constructor` as transports', function (done) {
      // make sure we check for actual properties - not those present on every {}
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'constructor' })
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });

    it('should disallow non-existent sids', function (done) {
      var engine = listen(function (port) {
        request.get('http://localhost:%d/engine.io'.s(port))
          .data({ transport: 'polling', sid: 'test' })
          .end(function (err, res) {
            expect(res.status).to.be(500);
            done();
          });
      });
    });
  });

  describe('handshake', function () {
    it('should register a new client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        expect(Object.keys(engine.clients)).to.have.length(0);
        expect(engine.clientsCount).to.be(0);

        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          expect(Object.keys(engine.clients)).to.have.length(1);
          expect(engine.clientsCount).to.be(1);
          done();
        });
      });
    });

    it('should exchange handshake data', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.sid).to.be.a('string');
          expect(obj.pingTimeout).to.be.a('number');
          expect(obj.upgrades).to.be.an('array');
          done();
        });
      });
    });

    it('should allow custom ping intervals', function (done) {
      var engine = listen({ allowUpgrades: false, pingInterval: 123 }, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.pingInterval).to.be(123);
          done();
        });
      });
    });

    it('should allow custom ping timeouts', function (done) {
      var engine = listen({ allowUpgrades: false, pingTimeout: 123 }, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.on('handshake', function (obj) {
          expect(obj.pingTimeout).to.be(123);
          done();
        });
      });
    });

    it('should trigger a connection event with a Socket', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (socket) {
          expect(socket).to.be.an(eio.Socket);
          done();
        });
      });
    });

    it('should open with polling by default', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (socket) {
          expect(socket.transport.name).to.be('polling');
          done();
        });
      });
    });

    it('should be able to open with ws directly', function (done) {
      var engine = listen({ transports: ['websocket'] }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        engine.on('connection', function (socket) {
          expect(socket.transport.name).to.be('websocket');
          done();
        });
      });
    });

    it('should not suggest any upgrades for websocket', function (done) {
      var engine = listen({ transports: ['websocket'] }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        socket.on('handshake', function (obj) {
          expect(obj.upgrades).to.have.length(0);
          done();
        });
      });
    });

    it('should allow arbitrary data through query string', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { query: { a: 'b' } });
        engine.on('connection', function (conn) {
          expect(conn.req.query).to.have.keys('transport', 'a');
          expect(conn.req.query.a).to.be('b');
          done();
        });
      });
    });
  });

  describe('close', function () {
    it('should trigger on server if the client does not pong', function (done) {
      var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 }
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('http://localhost:%d'.s(port));
        socket.sendPacket = function (){};
        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('ping timeout');
            done();
          });
        });
      });
    });

    it('should trigger on client if server does not meet ping timeout', function (done) {
      var opts = { allowUpgrades: false, pingTimeout: 10 };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          // override onPacket to simulate an inactive server after handshake
          socket.onPacket = function(){};
          socket.on('close', function (reason, err) {
            expect(reason).to.be('ping timeout');
            done();
          });
        });
      });
    });

    it('should trigger on both ends upon ping timeout', function (done) {
      var opts = { allowUpgrades: false, pingTimeout: 10, pingInterval: 10 };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        function onClose (reason, err) {
          expect(reason).to.be('ping timeout');
          --total || done();
        }

        engine.on('connection', function (conn) {
          conn.on('close', onClose);
        });

        socket.on('open', function () {
          // override onPacket to simulate an inactive server after handshake
          socket.onPacket = socket.sendPacket = function(){};
          socket.on('close', onClose);
        });
      });
    });

    it('should trigger when server closes a client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });
          setTimeout(function () {
            conn.close();
          }, 10);
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });
      });
    });

    it('should trigger when server closes a client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });
          setTimeout(function () {
            conn.close();
          }, 10);
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });
      });
    });

    it('should trigger when client closes', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });

          setTimeout(function () {
            socket.close();
          }, 10);
        });
      });
    });

    it('should trigger when client closes (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , total = 2

        engine.on('connection', function (conn) {
          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            --total || done();
          });
        });

        socket.on('open', function () {
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            --total || done();
          });

          setTimeout(function () {
            socket.close();
          }, 10);
        });
      });
    });
  });

  describe('messages', function () {
    it('should arrive from server to client', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        engine.on('connection', function (conn) {
          conn.send('a');
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be('a');
            done();
          });
        });
      });
    });

    it('should arrive from server to client (multiple)', function (done) {
      var engine = listen({ allowUpgrades: false }, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port))
          , expected = ['a', 'b', 'c']
          , i = 0

        engine.on('connection', function (conn) {
          conn.send('a');
          // we use set timeouts to ensure the messages are delivered as part
          // of different.
          setTimeout(function () {
            conn.send('b');

            setTimeout(function () {
              // here we make sure we buffer both the close packet and
              // a regular packet
              conn.send('c');
              conn.close();
            }, 50);
          }, 50);

          conn.on('close', function () {
            // since close fires right after the buffer is drained
            setTimeout(function () {
              expect(i).to.be(3);
              done();
            }, 50);
          });
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be(expected[i++]);
          });
        });
      });
    });

    it('should arrive from server to client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
        engine.on('connection', function (conn) {
          conn.send('a');
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be('a');
            done();
          });
        });
      });
    });

    it('should arrive from server to client (ws)', function (done) {
      var opts = { allowUpgrades: false, transports: ['websocket'] };
      var engine = listen(opts, function (port) {
        var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
          , expected = ['a', 'b', 'c']
          , i = 0
        engine.on('connection', function (conn) {
          conn.send('a');
          setTimeout(function () {
            conn.send('b');
            setTimeout(function () {
              conn.send('c');
              conn.close();
            }, 50);
          }, 50);
          conn.on('close', function () {
            setTimeout(function () {
              expect(i).to.be(3);
              done();
            }, 50);
          });
        });
        socket.on('open', function () {
          socket.on('message', function (msg) {
            expect(msg).to.be(expected[i++]);
          });
        });
      });
    });
  });

  describe('upgrade', function () {
    it('should upgrade', function (done) {
      var engine = listen(function (port) {
        // it takes both to send 50 to verify
        var ready = 2, closed = 2;
        function finish () {
          setTimeout(function () {
            socket.close();
          }, 10);
        }

        // server
        engine.on('connection', function (conn) {
          var lastSent = 0, lastReceived = 0, upgraded = false;
          var interval = setInterval(function () {
            lastSent++;
            conn.send(lastSent);
            if (50 == lastSent) {
              clearInterval(interval);
              --ready || finish();
            }
          }, 2);

          conn.on('message', function (msg) {
            lastReceived++;
            expect(msg).to.eql(lastReceived);
          });

          conn.on('upgrade', function (to) {
            upgraded = true;
            expect(to.name).to.be('websocket');
          });

          conn.on('close', function (reason) {
            expect(reason).to.be('transport close');
            expect(lastSent).to.be(50);
            expect(lastReceived).to.be(50);
            expect(upgraded).to.be(true);
            --closed || done();
          });
        });

        // client
        var socket = new eioc.Socket('ws://localhost:%d'.s(port));
        socket.on('open', function () {
          var lastSent = 0, lastReceived = 0, upgrades = 0;
          var interval = setInterval(function () {
            lastSent++;
            socket.send(lastSent);
            if (50 == lastSent) {
              clearInterval(interval);
              --ready || finish();
            }
          }, 2);
          socket.on('upgrading', function (to) {
            // we want to make sure for the sake of this test that we have a buffer
            expect(to.name).to.equal('websocket');
            upgrades++;

            // force send a few packets to ensure we test buffer transfer
            lastSent++;
            socket.send(lastSent);
            lastSent++;
            socket.send(lastSent);

            expect(socket.writeBuffer).to.not.be.empty();
          });
          socket.on('upgrade', function (to) {
            expect(to.name).to.equal('websocket');
            upgrades++;
          });
          socket.on('message', function (msg) {
            lastReceived++;
            expect(lastReceived).to.eql(msg);
          });
          socket.on('close', function (reason) {
            expect(reason).to.be('forced close');
            expect(lastSent).to.be(50);
            expect(lastReceived).to.be(50);
            expect(upgrades).to.be(2);
            --closed || done();
          });
        });
      });
    });
  });

});
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

if (!chai) {
  var chai = require('..');
}

var should = chai.should();

function err(fn, msg) {
  try {
    fn();
    chai.fail('expected an error');
  } catch (err) {
    should.equal(msg, err.message);
  }
}

suite('should', function() {

  test('.version', function(){
    chai.version.should.match(/^\d+\.\d+\.\d+$/);
  });

  test('double require', function(){
    //require('chai').should().should.equal(should);
  });

  test('assertion', function(){
    'test'.should.be.a('string');
    should.equal('foo', 'foo');
  });

  test('root exist', function () {
    var foo = 'foo'
      , bar = undefined;
    should.exist(foo);
    should.not.exist(bar);

    err(function () {
      should.exist(bar);
    }, "expected undefined to exist");

    err(function () {
      should.not.exist(foo);
    }, "expected 'foo' to not exist")
  });

  test('true', function(){
    true.should.be.true;
    false.should.not.be.true;
    (1).should.not.be.true;

    err(function(){
      'test'.should.be.true;
    }, "expected 'test' to be true")
  });

  test('ok', function(){
    true.should.be.ok;
    false.should.not.be.ok;
    (1).should.be.ok;
    (0).should.not.be.ok;

    err(function(){
      ''.should.be.ok;
    }, "expected '' to be truthy");

    err(function(){
      'test'.should.not.be.ok;
    }, "expected 'test' to be falsey");
  });

  test('false', function(){
    false.should.be.false;
    true.should.not.be.false;
    (0).should.not.be.false;

    err(function(){
      ''.should.be.false;
    }, "expected '' to be false")
  });

  test('arguments', function(){
    var args = (function(){ return arguments; })(1,2,3);
    args.should.be.arguments;
    [].should.not.be.arguments;
  });

  test('.equal()', function(){
    var foo;
    should.equal(undefined, foo);
  });

  test('typeof', function(){
    'test'.should.be.a('string');

    err(function(){
      'test'.should.not.be.a('string');
    }, "expected 'test' not to be a string");

    (5).should.be.a('number');

    err(function(){
      (5).should.not.be.a('number');
    }, "expected 5 not to be a number");
  });

  test('instanceof', function(){
    function Foo(){}
    new Foo().should.be.an.instanceof(Foo);

    err(function(){
      (3).should.an.instanceof(Foo);
    }, "expected 3 to be an instance of Foo");
  });

  test('within(start, finish)', function(){
    (5).should.be.within(5, 10);
    (5).should.be.within(3,6);
    (5).should.be.within(3,5);
    (5).should.not.be.within(1,3);

    err(function(){
      (5).should.not.be.within(4,6);
    }, "expected 5 to not be within 4..6");

    err(function(){
      (10).should.be.within(50,100);
    }, "expected 10 to be within 50..100");
  });

  test('above(n)', function(){
    (5).should.be.above(2);
    (5).should.be.greaterThan(2);
    (5).should.not.be.above(5);
    (5).should.not.be.above(6);

    err(function(){
      (5).should.be.above(6);
    }, "expected 5 to be above 6");

    err(function(){
      (10).should.not.be.above(6);
    }, "expected 10 to be below 6");
  });

  test('match(regexp)', function(){
    'foobar'.should.match(/^foo/)
    'foobar'.should.not.match(/^bar/)

    err(function(){
      'foobar'.should.match(/^bar/i)
    }, "expected 'foobar' to match /^bar/i");

    err(function(){
      'foobar'.should.not.match(/^foo/i)
    }, "expected 'foobar' not to match /^foo/i");
  });

  test('length(n)', function(){
    'test'.should.have.length(4);
    'test'.should.not.have.length(3);
    [1,2,3].should.have.length(3);

    err(function(){
      (4).should.have.length(3);
    }, 'expected 4 to have a property \'length\'');

    err(function(){
      'asd'.should.not.have.length(3);
    }, "expected 'asd' to not have a length of 3");
  });

  test('eql(val)', function(){
    'test'.should.eql('test');
    ({ foo: 'bar' }).should.eql({ foo: 'bar' });
    (1).should.eql(1);
    '4'.should.not.eql(4);

    err(function(){
      (4).should.eql(3);
    }, 'expected 4 to equal 3');
  });

  test('equal(val)', function(){
    'test'.should.equal('test');
    (1).should.equal(1);

    err(function(){
      (4).should.equal(3);
    }, 'expected 4 to equal 3');

    err(function(){
      '4'.should.equal(4);
    }, "expected '4' to equal 4");
  });

  test('empty', function(){
    ''.should.be.empty;
    [].should.be.empty;
    ({ length: 0 }).should.be.empty;

    err(function(){
      ({}).should.be.empty;
    }, 'expected {} to have a property \'length\'');

    err(function(){
      'asd'.should.be.empty;
    }, "expected 'asd' to be empty");

    err(function(){
      ''.should.not.be.empty;
    }, "expected '' not to be empty");
  });

  test('property(name)', function(){
    'test'.should.have.property('length');
    (4).should.not.have.property('length');

    err(function(){
      'asd'.should.have.property('foo');
    }, "expected 'asd' to have a property 'foo'");
  });

  test('property(name, val)', function(){
    'test'.should.have.property('length', 4);
    'asd'.should.have.property('constructor', String);

    err(function(){
      'asd'.should.have.property('length', 4);
    }, "expected 'asd' to have a property 'length' of 4, but got 3");

    err(function(){
      'asd'.should.not.have.property('length', 3);
    }, "expected 'asd' to not have a property 'length' of 3");

    err(function(){
      'asd'.should.not.have.property('foo', 3);
    }, "'asd' has no property 'foo'");

    err(function(){
      'asd'.should.have.property('constructor', Number);
    }, "expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
  });

  test('ownProperty(name)', function(){
    'test'.should.have.ownProperty('length');
    'test'.should.haveOwnProperty('length');
    ({ length: 12 }).should.have.ownProperty('length');

    err(function(){
      ({ length: 12 }).should.not.have.ownProperty('length');
    }, "expected { length: 12 } to not have own property 'length'");
  });

  test('string()', function(){
    'foobar'.should.contain.string('bar');
    'foobar'.should.contain.string('foo');
    'foobar'.should.not.contain.string('baz');

    err(function(){
      (3).should.contain.string('baz');
    }, "expected 3 to be a string");

    err(function(){
      'foobar'.should.contain.string('baz');
    }, "expected 'foobar' to contain 'baz'");

    err(function(){
      'foobar'.should.not.contain.string('bar');
    }, "expected 'foobar' to not contain 'bar'");
  });

  test('include()', function(){
    ['foo', 'bar'].should.include('foo');
    ['foo', 'bar'].should.include('foo');
    ['foo', 'bar'].should.include('bar');
    [1,2].should.include(1);
    ['foo', 'bar'].should.not.include('baz');
    ['foo', 'bar'].should.not.include(1);

    err(function(){
      ['foo'].should.include('bar');
    }, "expected [ 'foo' ] to include 'bar'");

    err(function(){
      ['bar', 'foo'].should.not.include('foo');
    }, "expected [ 'bar', 'foo' ] to not include 'foo'");
  });

  test('keys(array)', function(){
    ({ foo: 1 }).should.have.keys(['foo']);
    ({ foo: 1, bar: 2 }).should.have.keys(['foo', 'bar']);
    ({ foo: 1, bar: 2 }).should.have.keys('foo', 'bar');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('foo', 'bar');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('bar', 'foo');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('baz');

    ({ foo: 1, bar: 2 }).should.contain.keys('foo');
    ({ foo: 1, bar: 2 }).should.contain.keys('bar', 'foo');
    ({ foo: 1, bar: 2 }).should.contain.keys(['foo']);
    ({ foo: 1, bar: 2 }).should.contain.keys(['bar']);
    ({ foo: 1, bar: 2 }).should.contain.keys(['bar', 'foo']);

    ({ foo: 1, bar: 2 }).should.not.have.keys('baz');
    ({ foo: 1, bar: 2 }).should.not.have.keys('foo', 'baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('foo', 'baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('baz', 'foo');

    err(function(){
      ({ foo: 1 }).should.have.keys();
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.have.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.not.have.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.contain.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.have.keys(['bar']);
    }, "expected { foo: 1 } to have key 'bar'");

    err(function(){
      ({ foo: 1 }).should.have.keys(['bar', 'baz']);
    }, "expected { foo: 1 } to have keys 'bar', and 'baz'");

    err(function(){
      ({ foo: 1 }).should.have.keys(['foo', 'bar', 'baz']);
    }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'");

    err(function(){
      ({ foo: 1 }).should.not.have.keys(['foo']);
    }, "expected { foo: 1 } to not have key 'foo'");

    err(function(){
      ({ foo: 1 }).should.not.have.keys(['foo']);
    }, "expected { foo: 1 } to not have key 'foo'");

    err(function(){
      ({ foo: 1, bar: 2 }).should.not.have.keys(['foo', 'bar']);
    }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'");

    err(function(){
      ({ foo: 1 }).should.not.contain.keys(['foo']);
    }, "expected { foo: 1 } to not contain key 'foo'");

    err(function(){
      ({ foo: 1 }).should.contain.keys('foo', 'bar');
    }, "expected { foo: 1 } to contain keys 'foo', and 'bar'");
  });

  test('throw', function () {
    var goodFn = function () { 1==1; }
      , badFn = function () { throw new Error('testing'); }
      , refErrFn = function () { throw new ReferenceError(); };

    (goodFn).should.not.throw();
    (goodFn).should.not.throw(Error);
    (badFn).should.throw();
    (badFn).should.throw(Error);
    (badFn).should.not.throw(ReferenceError);
    (refErrFn).should.throw();
    (refErrFn).should.throw(ReferenceError);
    (refErrFn).should.not.throw(Error);
    (refErrFn).should.not.throw(TypeError);

    (badFn).should.throw(/testing/);
    (badFn).should.not.throw(/hello/);

    should.throw(badFn);
    should.throw(refErrFn, ReferenceError);
    should.not.throw(goodFn);
    should.not.throw(badFn, ReferenceError);

    err(function(){
      (goodFn).should.throw();
    }, "expected [Function] to throw an error");

    err(function(){
      (goodFn).should.throw(ReferenceError);
    }, "expected [Function] to throw ReferenceError");

    err(function(){
      (badFn).should.not.throw();
    }, "expected [Function] to not throw an error");

    err(function(){
      (badFn).should.throw(ReferenceError);
    }, "expected [Function] to throw ReferenceError but a Error was thrown");

    err(function(){
      (badFn).should.not.throw(Error);
    }, "expected [Function] to not throw Error");

    err(function(){
      (refErrFn).should.not.throw(ReferenceError);
    }, "expected [Function] to not throw ReferenceError");

    err(function(){
      (refErrFn).should.throw(Error);
    }, "expected [Function] to throw Error but a ReferenceError was thrown");

    err(function (){
      (badFn).should.not.throw(/testing/);
    }, "expected [Function] to throw error not matching /testing/");

    err(function () {
      (badFn).should.throw(/hello/);
    }, "expected [Function] to throw error matching /hello/ but got \'testing\'");
  });

  test('respondTo', function(){
    function Foo(){};
    Foo.prototype.bar = function(){};

    var bar = {};
    bar.foo = function(){};

    Foo.should.respondTo('bar');
    Foo.should.not.respondTo('foo');

    bar.should.respondTo('foo');

    err(function(){
      Foo.should.respondTo('baz');
    }, "expected [Function: Foo] to respond to \'baz\'");

    err(function(){
      bar.should.respondTo('baz');
    }, "expected { foo: [Function] } to respond to \'baz\'");
  });

  test('satisfy', function(){
    var matcher = function(num){
      return num === 1;
    };

    (1).should.satisfy(matcher);

    err(function(){
      (2).should.satisfy(matcher);
    }, "expected 2 to satisfy [Function]");
  });
});
<commit_msg>Add `.closeTo()` should test.<commit_after>/**
 * Module dependencies.
 */

if (!chai) {
  var chai = require('..');
}

var should = chai.should();

function err(fn, msg) {
  try {
    fn();
    chai.fail('expected an error');
  } catch (err) {
    should.equal(msg, err.message);
  }
}

suite('should', function() {

  test('.version', function(){
    chai.version.should.match(/^\d+\.\d+\.\d+$/);
  });

  test('double require', function(){
    //require('chai').should().should.equal(should);
  });

  test('assertion', function(){
    'test'.should.be.a('string');
    should.equal('foo', 'foo');
  });

  test('root exist', function () {
    var foo = 'foo'
      , bar = undefined;
    should.exist(foo);
    should.not.exist(bar);

    err(function () {
      should.exist(bar);
    }, "expected undefined to exist");

    err(function () {
      should.not.exist(foo);
    }, "expected 'foo' to not exist")
  });

  test('true', function(){
    true.should.be.true;
    false.should.not.be.true;
    (1).should.not.be.true;

    err(function(){
      'test'.should.be.true;
    }, "expected 'test' to be true")
  });

  test('ok', function(){
    true.should.be.ok;
    false.should.not.be.ok;
    (1).should.be.ok;
    (0).should.not.be.ok;

    err(function(){
      ''.should.be.ok;
    }, "expected '' to be truthy");

    err(function(){
      'test'.should.not.be.ok;
    }, "expected 'test' to be falsey");
  });

  test('false', function(){
    false.should.be.false;
    true.should.not.be.false;
    (0).should.not.be.false;

    err(function(){
      ''.should.be.false;
    }, "expected '' to be false")
  });

  test('arguments', function(){
    var args = (function(){ return arguments; })(1,2,3);
    args.should.be.arguments;
    [].should.not.be.arguments;
  });

  test('.equal()', function(){
    var foo;
    should.equal(undefined, foo);
  });

  test('typeof', function(){
    'test'.should.be.a('string');

    err(function(){
      'test'.should.not.be.a('string');
    }, "expected 'test' not to be a string");

    (5).should.be.a('number');

    err(function(){
      (5).should.not.be.a('number');
    }, "expected 5 not to be a number");
  });

  test('instanceof', function(){
    function Foo(){}
    new Foo().should.be.an.instanceof(Foo);

    err(function(){
      (3).should.an.instanceof(Foo);
    }, "expected 3 to be an instance of Foo");
  });

  test('within(start, finish)', function(){
    (5).should.be.within(5, 10);
    (5).should.be.within(3,6);
    (5).should.be.within(3,5);
    (5).should.not.be.within(1,3);

    err(function(){
      (5).should.not.be.within(4,6);
    }, "expected 5 to not be within 4..6");

    err(function(){
      (10).should.be.within(50,100);
    }, "expected 10 to be within 50..100");
  });

  test('above(n)', function(){
    (5).should.be.above(2);
    (5).should.be.greaterThan(2);
    (5).should.not.be.above(5);
    (5).should.not.be.above(6);

    err(function(){
      (5).should.be.above(6);
    }, "expected 5 to be above 6");

    err(function(){
      (10).should.not.be.above(6);
    }, "expected 10 to be below 6");
  });

  test('match(regexp)', function(){
    'foobar'.should.match(/^foo/)
    'foobar'.should.not.match(/^bar/)

    err(function(){
      'foobar'.should.match(/^bar/i)
    }, "expected 'foobar' to match /^bar/i");

    err(function(){
      'foobar'.should.not.match(/^foo/i)
    }, "expected 'foobar' not to match /^foo/i");
  });

  test('length(n)', function(){
    'test'.should.have.length(4);
    'test'.should.not.have.length(3);
    [1,2,3].should.have.length(3);

    err(function(){
      (4).should.have.length(3);
    }, 'expected 4 to have a property \'length\'');

    err(function(){
      'asd'.should.not.have.length(3);
    }, "expected 'asd' to not have a length of 3");
  });

  test('eql(val)', function(){
    'test'.should.eql('test');
    ({ foo: 'bar' }).should.eql({ foo: 'bar' });
    (1).should.eql(1);
    '4'.should.not.eql(4);

    err(function(){
      (4).should.eql(3);
    }, 'expected 4 to equal 3');
  });

  test('equal(val)', function(){
    'test'.should.equal('test');
    (1).should.equal(1);

    err(function(){
      (4).should.equal(3);
    }, 'expected 4 to equal 3');

    err(function(){
      '4'.should.equal(4);
    }, "expected '4' to equal 4");
  });

  test('empty', function(){
    ''.should.be.empty;
    [].should.be.empty;
    ({ length: 0 }).should.be.empty;

    err(function(){
      ({}).should.be.empty;
    }, 'expected {} to have a property \'length\'');

    err(function(){
      'asd'.should.be.empty;
    }, "expected 'asd' to be empty");

    err(function(){
      ''.should.not.be.empty;
    }, "expected '' not to be empty");
  });

  test('property(name)', function(){
    'test'.should.have.property('length');
    (4).should.not.have.property('length');

    err(function(){
      'asd'.should.have.property('foo');
    }, "expected 'asd' to have a property 'foo'");
  });

  test('property(name, val)', function(){
    'test'.should.have.property('length', 4);
    'asd'.should.have.property('constructor', String);

    err(function(){
      'asd'.should.have.property('length', 4);
    }, "expected 'asd' to have a property 'length' of 4, but got 3");

    err(function(){
      'asd'.should.not.have.property('length', 3);
    }, "expected 'asd' to not have a property 'length' of 3");

    err(function(){
      'asd'.should.not.have.property('foo', 3);
    }, "'asd' has no property 'foo'");

    err(function(){
      'asd'.should.have.property('constructor', Number);
    }, "expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
  });

  test('ownProperty(name)', function(){
    'test'.should.have.ownProperty('length');
    'test'.should.haveOwnProperty('length');
    ({ length: 12 }).should.have.ownProperty('length');

    err(function(){
      ({ length: 12 }).should.not.have.ownProperty('length');
    }, "expected { length: 12 } to not have own property 'length'");
  });

  test('string()', function(){
    'foobar'.should.contain.string('bar');
    'foobar'.should.contain.string('foo');
    'foobar'.should.not.contain.string('baz');

    err(function(){
      (3).should.contain.string('baz');
    }, "expected 3 to be a string");

    err(function(){
      'foobar'.should.contain.string('baz');
    }, "expected 'foobar' to contain 'baz'");

    err(function(){
      'foobar'.should.not.contain.string('bar');
    }, "expected 'foobar' to not contain 'bar'");
  });

  test('include()', function(){
    ['foo', 'bar'].should.include('foo');
    ['foo', 'bar'].should.include('foo');
    ['foo', 'bar'].should.include('bar');
    [1,2].should.include(1);
    ['foo', 'bar'].should.not.include('baz');
    ['foo', 'bar'].should.not.include(1);

    err(function(){
      ['foo'].should.include('bar');
    }, "expected [ 'foo' ] to include 'bar'");

    err(function(){
      ['bar', 'foo'].should.not.include('foo');
    }, "expected [ 'bar', 'foo' ] to not include 'foo'");
  });

  test('keys(array)', function(){
    ({ foo: 1 }).should.have.keys(['foo']);
    ({ foo: 1, bar: 2 }).should.have.keys(['foo', 'bar']);
    ({ foo: 1, bar: 2 }).should.have.keys('foo', 'bar');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('foo', 'bar');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('bar', 'foo');
    ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('baz');

    ({ foo: 1, bar: 2 }).should.contain.keys('foo');
    ({ foo: 1, bar: 2 }).should.contain.keys('bar', 'foo');
    ({ foo: 1, bar: 2 }).should.contain.keys(['foo']);
    ({ foo: 1, bar: 2 }).should.contain.keys(['bar']);
    ({ foo: 1, bar: 2 }).should.contain.keys(['bar', 'foo']);

    ({ foo: 1, bar: 2 }).should.not.have.keys('baz');
    ({ foo: 1, bar: 2 }).should.not.have.keys('foo', 'baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('foo', 'baz');
    ({ foo: 1, bar: 2 }).should.not.contain.keys('baz', 'foo');

    err(function(){
      ({ foo: 1 }).should.have.keys();
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.have.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.not.have.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.contain.keys([]);
    }, "keys required");

    err(function(){
      ({ foo: 1 }).should.have.keys(['bar']);
    }, "expected { foo: 1 } to have key 'bar'");

    err(function(){
      ({ foo: 1 }).should.have.keys(['bar', 'baz']);
    }, "expected { foo: 1 } to have keys 'bar', and 'baz'");

    err(function(){
      ({ foo: 1 }).should.have.keys(['foo', 'bar', 'baz']);
    }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'");

    err(function(){
      ({ foo: 1 }).should.not.have.keys(['foo']);
    }, "expected { foo: 1 } to not have key 'foo'");

    err(function(){
      ({ foo: 1 }).should.not.have.keys(['foo']);
    }, "expected { foo: 1 } to not have key 'foo'");

    err(function(){
      ({ foo: 1, bar: 2 }).should.not.have.keys(['foo', 'bar']);
    }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'");

    err(function(){
      ({ foo: 1 }).should.not.contain.keys(['foo']);
    }, "expected { foo: 1 } to not contain key 'foo'");

    err(function(){
      ({ foo: 1 }).should.contain.keys('foo', 'bar');
    }, "expected { foo: 1 } to contain keys 'foo', and 'bar'");
  });

  test('throw', function () {
    var goodFn = function () { 1==1; }
      , badFn = function () { throw new Error('testing'); }
      , refErrFn = function () { throw new ReferenceError(); };

    (goodFn).should.not.throw();
    (goodFn).should.not.throw(Error);
    (badFn).should.throw();
    (badFn).should.throw(Error);
    (badFn).should.not.throw(ReferenceError);
    (refErrFn).should.throw();
    (refErrFn).should.throw(ReferenceError);
    (refErrFn).should.not.throw(Error);
    (refErrFn).should.not.throw(TypeError);

    (badFn).should.throw(/testing/);
    (badFn).should.not.throw(/hello/);

    should.throw(badFn);
    should.throw(refErrFn, ReferenceError);
    should.not.throw(goodFn);
    should.not.throw(badFn, ReferenceError);

    err(function(){
      (goodFn).should.throw();
    }, "expected [Function] to throw an error");

    err(function(){
      (goodFn).should.throw(ReferenceError);
    }, "expected [Function] to throw ReferenceError");

    err(function(){
      (badFn).should.not.throw();
    }, "expected [Function] to not throw an error");

    err(function(){
      (badFn).should.throw(ReferenceError);
    }, "expected [Function] to throw ReferenceError but a Error was thrown");

    err(function(){
      (badFn).should.not.throw(Error);
    }, "expected [Function] to not throw Error");

    err(function(){
      (refErrFn).should.not.throw(ReferenceError);
    }, "expected [Function] to not throw ReferenceError");

    err(function(){
      (refErrFn).should.throw(Error);
    }, "expected [Function] to throw Error but a ReferenceError was thrown");

    err(function (){
      (badFn).should.not.throw(/testing/);
    }, "expected [Function] to throw error not matching /testing/");

    err(function () {
      (badFn).should.throw(/hello/);
    }, "expected [Function] to throw error matching /hello/ but got \'testing\'");
  });

  test('respondTo', function(){
    function Foo(){};
    Foo.prototype.bar = function(){};

    var bar = {};
    bar.foo = function(){};

    Foo.should.respondTo('bar');
    Foo.should.not.respondTo('foo');

    bar.should.respondTo('foo');

    err(function(){
      Foo.should.respondTo('baz');
    }, "expected [Function: Foo] to respond to \'baz\'");

    err(function(){
      bar.should.respondTo('baz');
    }, "expected { foo: [Function] } to respond to \'baz\'");
  });

  test('satisfy', function(){
    var matcher = function(num){
      return num === 1;
    };

    (1).should.satisfy(matcher);

    err(function(){
      (2).should.satisfy(matcher);
    }, "expected 2 to satisfy [Function]");
  });

  test('closeTo', function(){
    (1.5).should.be.closeTo(1.0, 0.5);

    err(function(){
      (2).should.be.closeTo(1.0, 0.5);
    }, "expected 2 to be close to 1 +/- 0.5");
  });
});
<|endoftext|>