<commit_before>var assert = require('assert');
var helper = require('./lib/helper');
var fs     = require('fs-extra');

var Queue = require('../lib/queue');
var MemoryStore = require('../lib/stores/memory');
var SQLiteStore = require('../lib/stores/sqlite');

describe('Complex Queue', function() {
  afterEach(helper.destroyQueues);

  it('should run in batch mode', function (done) {
    var q = new Queue({
      batchSize: 3,
      process: function (batch, cb) {
        assert.equal(batch.length, 3);
        var total = 0;
        batch.forEach(function (task) {
          total += task;
        })
        cb(null, total);
      },
    })
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 3) {
        q.resume();
      }
    })
    q.pause();
    q.push(1, function (err, total) {
      assert.equal(total, 6);
    })
    q.push(2, function (err, total) {
      assert.equal(total, 6);
    })
    q.push(3, function (err, total) {
      assert.equal(total, 6);
      done();
    })
    this.q = q;
  })

  it('should store properly', function (done) {
    var self = this;
    var s = new MemoryStore();
    var finished = 0;
    var queued = 0;
    var q1 = new Queue(function (n, cb) { throw new Error('failed') }, { store: s })
    q1.on('task_queued', function () {
      queued++;
      if (queued >= 3) {
        var q2 = new Queue(function (n, cb) {
          finished++;
          cb();
          if (finished === 3) {
            done();
          }
        }, { store: s });
        self.q2 = q2;
      }
    })
    q1.pause();
    q1.push(1);
    q1.push(2);
    q1.push(3);
    this.q1 = q1;
  })

  it('should retry', function (done) {
    var tries = 0;
    var q = new Queue(function (n, cb) {
      tries++;
      if (tries === 3) {
        cb();
        done();
      } else {
        cb('fail');
      }
    }, { maxRetries: 3 });
    q.push(1);
    this.q = q;
  })

  it('should fail retry', function (done) {
    var tries = 0;
    var q = new Queue(function (n, cb) {
      tries++;
      if (tries === 3) {
        cb();
      } else {
        cb('fail');
      }
    }, { maxRetries: 2, autoResume: true })
    q.on('task_failed', function () {
      done();
    });
    q.push(1);
    this.q = q;
  })

  it('should respect afterProcessDelay', function (done) {
    var delay = 100;
    var finished = 0;
    var startTime;
    var q = new Queue(function (task, cb) {
      finished++;
      cb();
      if (finished === 1) {
        startTime = +(new Date());
      } else if (finished === 2) {
        var endTime = +(new Date());
        var elapsedTime = endTime - startTime;
        assert(elapsedTime >= delay);
        done();
      }
    },  { batchSize: 1, afterProcessDelay: delay });
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 2) {
        q.resume();
      }
    })
    q.pause();
    q.push(1);
    q.push(2);
    this.q = q;
  })

  it('should max timeout', function (done) {
    var q = new Queue(function (tasks, cb) {}, { maxTimeout: 1 })
    q.on('task_failed', function (taskId, msg) {
      assert.equal(msg, 'task_timeout');
      done();
    });
    q.push(1, function (err, r) {
      assert.equal(err, 'task_timeout');
    });
    this.q = q;
  })

  it('should merge tasks', function (done) {
    var q = new Queue(function (o, cb) {
      if (o.id === 1) {
        assert.equal(o.x, 3);
        cb();
      } else {
        cb();
      }
    }, {
      id: 'id',
      merge: function (a, b, cb) {
        a.x += b.x;
        cb(null, a);
      }
    })
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 2) {
        q.resume();
      }
    })
    q.on('task_finish', function (taskId, r) {
      if (taskId === '1') {
        done();
      }
    })
    q.pause()
    q.push({ id: '0', x: 4 });
    q.push({ id: '1', x: 1 }, function (err, r) {
      assert.ok(!err)
    });
    q.push({ id: '1', x: 2 }, function (err, r) {
      assert.ok(!err);
    });
    this.q = q;
  })

  it('should respect id property (string)', function (done) {
    var q = new Queue(function (o, cb) {
      if (o.name === 'john') {
        assert.equal(o.x, 4);
        cb();
      }
      if (o.name === 'mary') {
        assert.equal(o.x, 5);
        cb();
      }
      if (o.name === 'jim') {
        assert.equal(o.x, 2);
        cb();
      }
    }, {
      id: 'name',
      merge: function (a, b, cb) {
        a.x += b.x;
        cb(null, a);
      }
    })
    var finished = 0;
    var queued = 0;
    q.on('task_finish', function (taskId, r) {
      finished++;
      if (finished >= 3) done();
    })
    q.on('task_queued', function (taskId, r) {
      queued++;
      if (queued >= 3) {
        q.resume();
      }
    })
    q.pause();
    q.push({ name: 'john', x: 4 });
    q.push({ name: 'mary', x: 3 });
    q.push({ name: 'jim', x: 1 });
    q.push({ name: 'jim', x: 1 });
    q.push({ name: 'mary', x: 2 });
    this.q = q;
  })

  it('should respect id property (function)', function (done) {
    var finished = 0;
    var q = new Queue(function (n, cb) {
      cb(null, n)
    }, {
      batchDelay: 3,
      id: function (n, cb) {
        cb(null, n % 2 === 0 ? 'even' : 'odd');
      },
      merge: function (a, b, cb) {
        cb(null, a+b);
      }
    })
    var finished = 0;
    var queued = 0;
    q.on('task_queued', function (taskId, r) {
    })
    q.on('task_finish', function (taskId, r) {
      finished++;
      if (taskId === 'odd') {
        assert.equal(r, 9);
      }
      if (taskId === 'even') {
        assert.equal(r, 6);
      }
      if (finished >= 2) {
        done();
      }
    })
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    q.push(5);
    this.q = q;
  })

  it('should cancel if running', function (done) {
    var ran = 0;
    var cancelled = false;
    var q = new Queue(function (n, cb) {
      ran++;
      if (ran >= 2) {
        cb();
      }
      if (ran === 3) {
        assert.ok(cancelled);
        done();
      }
      return {
        cancel: function () {
          cancelled = true;
        }
      }
    }, { id: 'id', cancelIfRunning: true })
    q.push({ id: 1 })
      .on('started', function () {
        q.push({ id: 2 });
        setTimeout(function () {
          q.push({ id: 1 });
        }, 1)
      });
    this.q = q;
  })

  it('should release lock after running (sqlite)', function (done) {
    var s = new SQLiteStore();
    var q = new Queue(function (n, cb) {
      cb();
      setTimeout(function () {
        s.getRunningTasks(function (err, tasks) {
          assert.ok(!Object.keys(tasks).length)
          done();
        })
      }, 1)
    }, { store: s, autoResume: true })
    q.push(1);
    this.q = q;
  })

  it('should resume running task (sqlite)', function (done) {
    var self = this;
    var s = new SQLiteStore();
    var q1 = new Queue(function () {
      var q2 = new Queue(function () {
        done();
      }, { store: s })
      self.q2 = q2;
    }, { store: s })
    q1.push(1);
    this.q1 = q1;
  })

  it('failed task should not stack overflow', function (done) {
    var count = 0;
    var q = new Queue(function (n, cb) {
      count++
      if (count > 100) {
        cb();
        done();
      } else {
        cb('fail');
      }
    }, {
      maxRetries: Infinity
    })
    q.push(1);
    this.q = q;
  })

  it('drain should still work with persistent queues', function (done) {
    var initialQueue = new Queue(function (n, cb) {
      setTimeout(cb, 1);
    }, {
      store: {
        type: 'sql',
        dialect: 'sqlite',
        path: 'testqueue.sql'
      }
    })
    var drained = false;
    initialQueue.on('drain', function () {
      drained = true;
    });
    initialQueue.push(1);

    setTimeout(function () {
      initialQueue.destroy();

      assert.ok(drained);
      done();
    }, 20)
  })

  it('drain should still work when there are persisted items at load time', function (done) {
    var initialQueue = new Queue(function (n, cb) {
      setTimeout(cb, 100);
    }, {
      store: {
        type: 'sql',
        dialect: 'sqlite',
        path: 'testqueue.sql'
      }
    });
    initialQueue.push('' + 1);
    initialQueue.push('' + 2);
    setTimeout(function () {
      // This effectively captures the queue in a state where there were unprocessed items
      fs.copySync('testqueue.sql', 'testqueue2.sql');
      initialQueue.destroy();
      var persistedQueue = new Queue(function (n, cb) {
        setTimeout(cb, 1);
      }, {
        store: {
          type: 'sql',
          dialect: 'sqlite',
          path: 'testqueue2.sql'
        }
      })
      var drained = false;
      persistedQueue.on('drain', function () {
        drained = true;
      });
      persistedQueue.push(2);
      setTimeout(function () {
        persistedQueue.destroy();

        assert.ok(drained);
        done();
      }, 140)
    }, 40)
  })
})
<commit_msg>Not sure why travis is complaining...<commit_after>var assert = require('assert');
var helper = require('./lib/helper');
var fs     = require('fs-extra');

var Queue = require('../lib/queue');
var MemoryStore = require('../lib/stores/memory');
var SQLiteStore = require('../lib/stores/sqlite');

describe('Complex Queue', function() {
  afterEach(helper.destroyQueues);

  it('should run in batch mode', function (done) {
    var q = new Queue({
      batchSize: 3,
      process: function (batch, cb) {
        assert.equal(batch.length, 3);
        var total = 0;
        batch.forEach(function (task) {
          total += task;
        })
        cb(null, total);
      },
    })
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 3) {
        q.resume();
      }
    })
    q.pause();
    q.push(1, function (err, total) {
      assert.equal(total, 6);
    })
    q.push(2, function (err, total) {
      assert.equal(total, 6);
    })
    q.push(3, function (err, total) {
      assert.equal(total, 6);
      done();
    })
    this.q = q;
  })

  it('should store properly', function (done) {
    var self = this;
    var s = new MemoryStore();
    var finished = 0;
    var queued = 0;
    var q1 = new Queue(function (n, cb) { throw new Error('failed') }, { store: s })
    q1.on('task_queued', function () {
      queued++;
      if (queued >= 3) {
        var q2 = new Queue(function (n, cb) {
          finished++;
          cb();
          if (finished === 3) {
            done();
          }
        }, { store: s });
        self.q2 = q2;
      }
    })
    q1.pause();
    q1.push(1);
    q1.push(2);
    q1.push(3);
    this.q1 = q1;
  })

  it('should retry', function (done) {
    var tries = 0;
    var q = new Queue(function (n, cb) {
      tries++;
      if (tries === 3) {
        cb();
        done();
      } else {
        cb('fail');
      }
    }, { maxRetries: 3 });
    q.push(1);
    this.q = q;
  })

  it('should fail retry', function (done) {
    var tries = 0;
    var q = new Queue(function (n, cb) {
      tries++;
      if (tries === 3) {
        cb();
      } else {
        cb('fail');
      }
    }, { maxRetries: 2, autoResume: true })
    q.on('task_failed', function () {
      done();
    });
    q.push(1);
    this.q = q;
  })

  it('should respect afterProcessDelay', function (done) {
    var delay = 100;
    var finished = 0;
    var startTime;
    var q = new Queue(function (task, cb) {
      finished++;
      cb();
      if (finished === 1) {
        startTime = +(new Date());
      } else if (finished === 2) {
        var endTime = +(new Date());
        var elapsedTime = endTime - startTime;
        assert(elapsedTime >= delay);
        done();
      }
    },  { batchSize: 1, afterProcessDelay: delay });
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 2) {
        q.resume();
      }
    })
    q.pause();
    q.push(1);
    q.push(2);
    this.q = q;
  })

  it('should max timeout', function (done) {
    var q = new Queue(function (tasks, cb) {}, { maxTimeout: 1 })
    q.on('task_failed', function (taskId, msg) {
      assert.equal(msg, 'task_timeout');
      done();
    });
    q.push(1, function (err, r) {
      assert.equal(err, 'task_timeout');
    });
    this.q = q;
  })

  it('should merge tasks', function (done) {
    var q = new Queue(function (o, cb) {
      if (o.id === 1) {
        assert.equal(o.x, 3);
        cb();
      } else {
        cb();
      }
    }, {
      id: 'id',
      merge: function (a, b, cb) {
        a.x += b.x;
        cb(null, a);
      }
    })
    var queued = 0;
    q.on('task_queued', function () {
      queued++;
      if (queued >= 2) {
        q.resume();
      }
    })
    q.on('task_finish', function (taskId, r) {
      if (taskId === '1') {
        done();
      }
    })
    q.pause()
    q.push({ id: '0', x: 4 });
    q.push({ id: '1', x: 1 }, function (err, r) {
      assert.ok(!err)
    });
    q.push({ id: '1', x: 2 }, function (err, r) {
      assert.ok(!err);
    });
    this.q = q;
  })

  it('should respect id property (string)', function (done) {
    var q = new Queue(function (o, cb) {
      if (o.name === 'john') {
        assert.equal(o.x, 4);
        cb();
      }
      if (o.name === 'mary') {
        assert.equal(o.x, 5);
        cb();
      }
      if (o.name === 'jim') {
        assert.equal(o.x, 2);
        cb();
      }
    }, {
      id: 'name',
      merge: function (a, b, cb) {
        a.x += b.x;
        cb(null, a);
      }
    })
    var finished = 0;
    var queued = 0;
    q.on('task_finish', function (taskId, r) {
      finished++;
      if (finished >= 3) done();
    })
    q.on('task_queued', function (taskId, r) {
      queued++;
      if (queued >= 3) {
        q.resume();
      }
    })
    q.pause();
    q.push({ name: 'john', x: 4 });
    q.push({ name: 'mary', x: 3 });
    q.push({ name: 'jim', x: 1 });
    q.push({ name: 'jim', x: 1 });
    q.push({ name: 'mary', x: 2 });
    this.q = q;
  })

  it('should respect id property (function)', function (done) {
    var finished = 0;
    var q = new Queue(function (n, cb) {
      cb(null, n)
    }, {
      batchDelay: 3,
      id: function (n, cb) {
        cb(null, n % 2 === 0 ? 'even' : 'odd');
      },
      merge: function (a, b, cb) {
        cb(null, a+b);
      }
    })
    var finished = 0;
    var queued = 0;
    q.on('task_queued', function (taskId, r) {
    })
    q.on('task_finish', function (taskId, r) {
      finished++;
      if (taskId === 'odd') {
        assert.equal(r, 9);
      }
      if (taskId === 'even') {
        assert.equal(r, 6);
      }
      if (finished >= 2) {
        done();
      }
    })
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    q.push(5);
    this.q = q;
  })

  it('should cancel if running', function (done) {
    var ran = 0;
    var cancelled = false;
    var q = new Queue(function (n, cb) {
      ran++;
      if (ran >= 2) {
        cb();
      }
      if (ran === 3) {
        assert.ok(cancelled);
        done();
      }
      return {
        cancel: function () {
          cancelled = true;
        }
      }
    }, { id: 'id', cancelIfRunning: true })
    q.push({ id: 1 })
      .on('started', function () {
        q.push({ id: 2 });
        setTimeout(function () {
          q.push({ id: 1 });
        }, 1)
      });
    this.q = q;
  })

  it('should release lock after running (sqlite)', function (done) {
    var s = new SQLiteStore();
    var q = new Queue(function (n, cb) {
      cb();
      setTimeout(function () {
        s.getRunningTasks(function (err, tasks) {
          assert.ok(!Object.keys(tasks).length)
          done();
        })
      }, 1)
    }, { store: s, autoResume: true })
    q.push(1);
    this.q = q;
  })

  it('should resume running task (sqlite)', function (done) {
    var self = this;
    var s = new SQLiteStore();
    var q1 = new Queue(function () {
      var q2 = new Queue(function () {
        done();
      }, { store: s })
      self.q2 = q2;
    }, { store: s })
    q1.push(1);
    this.q1 = q1;
  })

  it('failed task should not stack overflow', function (done) {
    var count = 0;
    var q = new Queue(function (n, cb) {
      count++
      if (count > 100) {
        cb();
        done();
      } else {
        cb('fail');
      }
    }, {
      maxRetries: Infinity
    })
    q.push(1);
    this.q = q;
  })

  it('drain should still work with persistent queues', function (done) {
    var q = new Queue(function (n, cb) {
      setTimeout(cb, 1);
    }, {
      store: {
        type: 'sql',
        dialect: 'sqlite',
        path: 'testqueue.sql'
      }
    })
    var drained = false;
    q.on('drain', function () {
      drained = true;
      done();
    });
    q.push(1);
    this.q = q;
  })

  it('drain should still work when there are persisted items at load time', function (done) {
    var initialQueue = new Queue(function (n, cb) {
      setTimeout(cb, 100);
    }, {
      store: {
        type: 'sql',
        dialect: 'sqlite',
        path: 'testqueue.sql'
      }
    });
    initialQueue.push('' + 1);
    initialQueue.push('' + 2);
    setTimeout(function () {
      // This effectively captures the queue in a state where there were unprocessed items
      fs.copySync('testqueue.sql', 'testqueue2.sql');
      initialQueue.destroy();
      var persistedQueue = new Queue(function (n, cb) {
        setTimeout(cb, 1);
      }, {
        store: {
          type: 'sql',
          dialect: 'sqlite',
          path: 'testqueue2.sql'
        }
      })
      var drained = false;
      persistedQueue.on('drain', function () {
        drained = true;
      });
      persistedQueue.push(2);
      setTimeout(function () {
        persistedQueue.destroy();

        assert.ok(drained);
        done();
      }, 140)
    }, 40)
  })
})
<|endoftext|>


<commit_before>'use strict'
const test = require('tape')
const Hub = require('../')
const vstamp = require('vigour-stamp')

test('context', function (t) {
  const subs = {
    $any: { val: true },
    clients: { $any: { val: true } }
  }

  const server = new Hub({
    id: 'server',
    port: 6000,
    clients: { sort: 'key' }
  })

  const client = new Hub({
    id: 'client1',
    context: false,
    url: 'ws://localhost:6000',
    x: true
  })

  client.subscribe(subs)

  const client2 = new Hub({
    id: 'client2',
    context: false,
    url: 'ws://localhost:6000'
  })

  client2.subscribe(subs)

  const client3 = new Hub({
    id: 'client3',
    context: false,
    url: 'ws://localhost:6000'
  })

  client3.subscribe(subs)

  const client4 = new Hub({
    id: 'client4',
    context: false,
    url: 'ws://localhost:6000'
  })

  client4.subscribe(subs)

  server.get('x', false).is(true).then(() => {
    client.set({ context: 'someuser', hello: true })
    server.on(function context (val, stamp) {
      if (val.context) {
        t.equal(this.context.compute(), 'someuser', 'server received context')
        t.equal(server.instances.length, 1, 'server has an extra instance')
        const instance = server.instances[0]
        t.ok(instance.clients !== server.clients, 'created new clients object for instance')
        t.same(instance.clients.keys(), [ 'client1' ], 'instance has client1')
        t.same(server.clients.keys(), [ 'client2', 'client3', 'client4' ], 'client1 removed from server clients')
        vstamp.done(stamp, () => this.off(context))
        t.ok(!('hello' in client2), 'does not recieve hello in client2')
        client2.set({ context: 'someuser' })
        client2.get('hello', false).is(true).then(() => {
          t.ok('received context on client2 after switching to someuser')
          t.ok(!('hello' in client3), 'does not recieve hello in client3')
          client3.set({ originfield: true })
          Promise.all([
            client2.get('originfield', false).is(true),
            client.get('originfield', false).is(true)
          ]).then(() => {
            t.ok(true, 'got orgiin field on context clients')
          })
          // then somefield should not be recived by anything else when setting hello
        })
        // t.end()
      }
    })

    // need to receive these 2 clients as well

    // client2.clients.on(function (val, stamp) {
    //   vstamp.done(stamp, () => {
    //     // console.log('client2 --->', this.keys())
    //   })
    // })
    // client.clients.on(function (val, stamp) {
    //   vstamp.done(stamp, () => {
    //     // console.log('client1 --->', this.keys())
    //   })
    // })
  })
})
<commit_msg>more clients in tests<commit_after>'use strict'
const test = require('tape')
const Hub = require('../')
const vstamp = require('vigour-stamp')

test('context', function (t) {
  const subs = {
    $any: { val: true },
    clients: { $any: { val: true } }
  }

  const server = new Hub({
    id: 'server',
    port: 6000,
    clients: { sort: 'key' }
  })

  const client = new Hub({
    id: 'client1',
    context: false,
    url: 'ws://localhost:6000',
    x: true
  })

  client.subscribe(subs)

  const client2 = new Hub({
    id: 'client2',
    context: false,
    url: 'ws://localhost:6000'
  })

  client2.subscribe(subs)

  const client3 = new Hub({
    id: 'client3',
    context: false,
    url: 'ws://localhost:6000'
  })

  client3.subscribe(subs)

  const client4 = new Hub({
    id: 'client4',
    context: false,
    url: 'ws://localhost:6000'
  })

  client4.subscribe(subs)

  server.get('x', false).is(true).then(() => {
    client.set({ context: 'someuser', hello: true })
    server.on(function context (val, stamp) {
      if (val.context) {
        t.equal(this.context.compute(), 'someuser', 'server received context')
        t.equal(server.instances.length, 1, 'server has an extra instance')
        const instance = server.instances[0]
        t.ok(instance.clients !== server.clients, 'created new clients object for instance')
        t.same(instance.clients.keys(), [ 'client1' ], 'instance has client1')
        t.same(server.clients.keys(), [ 'client2', 'client3', 'client4' ], 'client1 removed from server clients')
        vstamp.done(stamp, () => this.off(context))
        t.ok(!('hello' in client2), 'does not recieve hello in client2')
        client2.set({ context: 'someuser' })
        client2.get('hello', false).is(true).then(() => {
          t.ok('received context on client2 after switching to someuser')
          t.ok(!('hello' in client3), 'does not recieve hello in client3')
          client3.set({ originfield: true })
          Promise.all([
            client2.get('originfield', false).is(true),
            client.get('originfield', false).is(true)
          ]).then(() => {
            t.ok(true, 'got orgiin field on context clients')
            client3.set({ hello: 'bye' })
            client4.get('hello', false).is('bye').then(() => {
              t.ok(true, 'client4 recieves update from client3')
              process.nextTick(() => {
                t.ok(client.hello.compute(), 'client does not get update for hello')
                t.ok(client2.hello.compute(), 'client2 does not get update for hello')
              })
            })
          })
          // then somefield should not be recived by anything else when setting hello
        })
        // t.end()
      }
    })

    // need to receive these 2 clients as well

    // client2.clients.on(function (val, stamp) {
    //   vstamp.done(stamp, () => {
    //     // console.log('client2 --->', this.keys())
    //   })
    // })
    // client.clients.on(function (val, stamp) {
    //   vstamp.done(stamp, () => {
    //     // console.log('client1 --->', this.keys())
    //   })
    // })
  })
})
<|endoftext|>


<commit_before>var test = require('tap').test;
var http = require('http');
var net = require('net');
var bouncy = require('../');

test('bounce', function (t) {
    var p0 = Math.floor(Math.random() * (Math.pow(2,16) - 1e4) + 1e4);
    var s0 = http.createServer(function (req, res) {
        res.setHeader('content-type', 'text/plain');
        res.write('beep boop');
        res.end();
    });
    s0.listen(p0, connect);

    var p1 = Math.floor(Math.random() * (Math.pow(2,16) - 1e4) + 1e4);
    var s1 = bouncy(function (req, bounce) {
        setTimeout(function () {
            bounce(net.connect(p0));
        }, 100);
    });
    s1.listen(p1, connect);

    var connected = 0;
    function connect () {
        if (++connected !== 2) return;
        var opts = {
            method : 'GET',
            host : 'localhost',
            port : p1,
            path : '/beep',
            headers : { connection : 'close' }
        };
        var req = http.request(opts, function (res) {
            t.equal(res.statusCode, 200)
            t.equal(res.headers['content-type'], 'text/plain');

            var data = '';
            res.on('data', function (buf) {
                data += buf.toString();
            });

            res.on('end', function () {
                t.equal(data, 'beep boop');
                s0.close();
                s1.close();
                t.end();
            });
        });
        req.end();
    }
});
<commit_msg>more delays, delay test still passes<commit_after>var test = require('tap').test;
var http = require('http');
var net = require('net');
var bouncy = require('../');

test('bounce', function (t) {
    var p0 = Math.floor(Math.random() * (Math.pow(2,16) - 1e4) + 1e4);
    var s0 = http.createServer(function (req, res) {
        res.setHeader('content-type', 'text/plain');
        res.write('beep ');
        setTimeout(function () {
            res.write('boop');
            res.end();
        }, 100);
    });
    s0.listen(p0, connect);

    var p1 = Math.floor(Math.random() * (Math.pow(2,16) - 1e4) + 1e4);
    var s1 = bouncy(function (req, bounce) {
        setTimeout(function () {
            bounce(net.connect(p0));
        }, 100);
    });
    s1.listen(p1, connect);

    var connected = 0;
    function connect () {
        if (++connected !== 2) return;
        var opts = {
            method : 'GET',
            host : 'localhost',
            port : p1,
            path : '/beep',
            headers : { connection : 'close' }
        };
        var req = http.request(opts, function (res) {
            t.equal(res.statusCode, 200)
            t.equal(res.headers['content-type'], 'text/plain');

            var data = '';
            res.on('data', function (buf) {
                data += buf.toString();
            });

            res.on('end', function () {
                t.equal(data, 'beep boop');
                s0.close();
                s1.close();
                t.end();
            });
        });
        req.end();
    }
});
<|endoftext|>


<commit_before>/*jshint undef:false */
var RSVP = require('rsvp'),
    chaiAsPromised = require('chai-as-promised'),
    chai = require('chai');

chai.should();
expect = chai.expect;
chai.use(chaiAsPromised);

var devicesResult = [
    {
        id: '240000',
        clientDeviceId: '14',
        name: '##Everything',
        state: 0,
        statevalue: null,
        methods: 0,
        type: 'group',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1,
        devices: '240001, 240001'
    },
    {
        id: '240001',
        clientDeviceId: '7',
        name: 'Livingroom-light',
        state: 0,
        statevalue: '0',
        methods: 0,
        type: 'device',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1
    },
    {
        id: '240002',
        clientDeviceId: '7',
        name: 'Livingroom-light',
        state: 0,
        statevalue: '0',
        methods: 0,
        type: 'device',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1
    }];

describe('devices', function () {
    describe('#getDevices()', function () {
        describe('success', function () {
            it('returns an array of sensors - if everything works fine', function (done) {
                var api = {
                        get: function invoke () {
                            return new RSVP.Promise(function (resolve) {
                                resolve(devicesResult);
                            });
                        }
                    },
                    devices = require('../lib').Devices(api);
                devices.getDevices().should.eventually.equal(devicesResult).notify(done);
            });
        });
        describe('failure', function () {
            it('rejects with an Error', function (done) {
                var api = {
                        get: function invoke () {
                            return new RSVP.Promise(function (resolve, reject) {
                                reject(new Error('failure'));
                            });
                        }
                    },
                    devices = require('../lib').Devices(api);
                devices.getDevices().should.be.rejectedWith(Error).notify(done);
            });
        });
    });
});
<commit_msg>Refactor<commit_after>/*jshint undef:false */
var RSVP = require('rsvp'),
    chaiAsPromised = require('chai-as-promised'),
    chai = require('chai');

chai.should();
expect = chai.expect;
chai.use(chaiAsPromised);

var devicesResult = [
    {
        id: '240000',
        clientDeviceId: '14',
        name: '##Everything',
        state: 0,
        statevalue: null,
        methods: 0,
        type: 'group',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1,
        devices: '240001, 240001'
    },
    {
        id: '240001',
        clientDeviceId: '7',
        name: 'Livingroom-light',
        state: 0,
        statevalue: '0',
        methods: 0,
        type: 'device',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1
    },
    {
        id: '240002',
        clientDeviceId: '7',
        name: 'Livingroom-light',
        state: 0,
        statevalue: '0',
        methods: 0,
        type: 'device',
        client: '10000',
        clientName: 'home',
        online: '1',
        editable: 1
    }];

describe('devices', function () {
    describe('#getDevices()', function () {
        describe('success', function () {
            it('returns an array of sensors - if everything works fine', function (done) {
                var api = {
                        get: function invoke () {
                            return new RSVP.Promise(function (resolve) {
                                resolve(devicesResult);
                            });
                        }
                    },
                    devices = require('../lib').Devices(api);
                devices.getDevices().should.eventually.equal(devicesResult).notify(done);
            });
        });
        describe('failure', function () {
            it('rejects with an Error', function (done) {
                var api = {
                        get: function invoke () {
                            return new RSVP.Promise(function (resolve, reject) {
                                reject(new Error('failure'));
                            });
                        }
                    },
                    devices = require('../lib').Devices(api);
                devices.getDevices().should.be.rejectedWith(Error).notify(done);
            });
        });
    });
    describe('#turnOn', function () {
        var success = {status: 'success'};
        it('fuu', function (done) {
            var api = {
                    request: function invoke () {
                        return new RSVP.Promise(function (resolve) {
                            resolve(success);
                        });
                    }
                },
                devices = require('../lib').Devices(api);
            devices.turnOn({id: 'anId'}).should.eventually.equal(success).notify(done);
        });
    });
});
<|endoftext|>


<commit_before>
var Emitter = require('..');

describe('Emitter', function(){
  describe('.on(event, fn)', function(){
    it('should add listeners', function(){
      var emitter = new Emitter;
      var calls = [];

      emitter.on('foo', function(val){
        calls.push('one', val);
      });

      emitter.on('foo', function(val){
        calls.push('two', val);
      });

      emitter.emit('foo', 1);
      emitter.emit('bar', 1);
      emitter.emit('foo', 2);

      calls.should.eql([ 'one', 1, 'two', 1, 'one', 2, 'two', 2 ]);
    })
  })

  describe('.once(event, fn)', function(){
    it('should add a single-shot listener', function(){
      var emitter = new Emitter;
      var calls = [];

      emitter.once('foo', function(val){
        calls.push('one', val);
      });

      emitter.emit('foo', 1);
      emitter.emit('foo', 2);
      emitter.emit('foo', 3);
      emitter.emit('bar', 1);

      calls.should.eql([ 'one', 1 ]);
    })
  })

  describe('.off(event, fn)', function(){
    it('should remove a listener', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }
      function two() { calls.push('two'); }

      emitter.on('foo', one);
      emitter.on('foo', two);
      emitter.off('foo', two);

      emitter.emit('foo');

      calls.should.eql([ 'one' ]);
    })

    it('should work with .once()', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }

      emitter.once('foo', one);
      emitter.off('foo', one);

      emitter.emit('foo');

      calls.should.eql([]);
    })
  })

  describe('.off(event)', function(){
    it('should remove all listeners for an event', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }
      function two() { calls.push('two'); }

      emitter.on('foo', one);
      emitter.on('foo', two);
      emitter.off('foo');

      emitter.emit('foo');
      emitter.emit('foo');

      calls.should.eql([]);
    })
  })

  describe('.has(event)', function(){
    describe('when handlers are present', function(){
      it('should return true', function(){
        var emitter = new Emitter;
        emitter.on('foo', function(){});
        emitter.has('foo').should.be.true;
      })
    })

    describe('when no handlers are present', function(){
      it('should return false', function(){
        var emitter = new Emitter;
        emitter.has('foo').should.be.false;
      })
    })
  })
})<commit_msg>Added failing test<commit_after>
var Emitter = require('..');

describe('Emitter', function(){
  describe('.on(event, fn)', function(){
    it('should add listeners', function(){
      var emitter = new Emitter;
      var calls = [];

      emitter.on('foo', function(val){
        calls.push('one', val);
      });

      emitter.on('foo', function(val){
        calls.push('two', val);
      });

      emitter.emit('foo', 1);
      emitter.emit('bar', 1);
      emitter.emit('foo', 2);

      calls.should.eql([ 'one', 1, 'two', 1, 'one', 2, 'two', 2 ]);
    })
  })

  describe('.once(event, fn)', function(){
    it('should add a single-shot listener', function(){
      var emitter = new Emitter;
      var calls = [];

      emitter.once('foo', function(val){
        calls.push('one', val);
      });

      emitter.emit('foo', 1);
      emitter.emit('foo', 2);
      emitter.emit('foo', 3);
      emitter.emit('bar', 1);

      calls.should.eql([ 'one', 1 ]);
    })
  })

  describe('.off(event, fn)', function(){
    it('should remove a listener', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }
      function two() { calls.push('two'); }

      emitter.on('foo', one);
      emitter.on('foo', two);
      emitter.off('foo', two);

      emitter.emit('foo');

      calls.should.eql([ 'one' ]);
    })

    it('should work with .once()', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }

      emitter.once('foo', one);
      emitter.off('foo', one);

      emitter.emit('foo');

      calls.should.eql([]);
    })

    it('should work when called from an event', function(){
      var emitter = new Emitter
        , called
      function b () {
        called = true;
      }
      emitter.on('tobi', function () {
        emitter.off('tobi', b);
      });
      emitter.on('tobi', b);
      emitter.emit('tobi');
      called.should.be.true;
      called = false;
      emitter.emit('tobi');
      called.should.be.false;
    });
  })

  describe('.off(event)', function(){
    it('should remove all listeners for an event', function(){
      var emitter = new Emitter;
      var calls = [];

      function one() { calls.push('one'); }
      function two() { calls.push('two'); }

      emitter.on('foo', one);
      emitter.on('foo', two);
      emitter.off('foo');

      emitter.emit('foo');
      emitter.emit('foo');

      calls.should.eql([]);
    })
  })

  describe('.has(event)', function(){
    describe('when handlers are present', function(){
      it('should return true', function(){
        var emitter = new Emitter;
        emitter.on('foo', function(){});
        emitter.has('foo').should.be.true;
      })
    })

    describe('when no handlers are present', function(){
      it('should return false', function(){
        var emitter = new Emitter;
        emitter.has('foo').should.be.false;
      })
    })
  })
})
<|endoftext|>


<commit_before>var assert = require( 'assert' )
var DKIM = require( '..' )

describe( 'DKIM', function() {

  describe( '.getKey()', function() {

    context( 'when key record exists', function() {

      specify( 'parse & return the key', function( done ) {
        DKIM.getKey( 'gmail.com', '20120113', function( error, key ) {
          assert.ifError( error )
          assert.equal( key instanceof DKIM.Key, true )
          assert.equal( key.type, 'rsa' )
          done()
        })
      })

    })

    context( 'when key record does not exist', function() {

      specify( 'PERMFAIL if domain has no record', function( done ) {
        DKIM.getKey( 'aa', function( error, key ) {
          assert.equal( key, null )
          assert.equal( error instanceof Error, true )
          assert.equal( error.code, DKIM.PERMFAIL )
          done()
        })
      })

      specify( 'PERMFAIL if TXT record is not a valid key', function( done ) {
        DKIM.getKey( 'gmail.com', function( error, key ) {
          assert.ok( key, 'key instance not present' )
          assert.ok( key.key == null, 'key is not null' )
          assert.equal( error instanceof Error, true, 'error not an instance of Error Class' )
          assert.equal( error.code, DKIM.PERMFAIL, 'Error code is not PERMFAIL' )
          done()
        })
      })

      specify( 'TEMPFAIL if query fails to respond' )

    })

  })

})
<commit_msg>test: Improve error messages<commit_after>var assert = require( 'assert' )
var DKIM = require( '..' )

describe( 'DKIM', function() {

  describe( '.getKey()', function() {

    context( 'when key record exists', function() {

      specify( 'parse & return the key', function( done ) {
        DKIM.getKey( 'gmail.com', '20120113', function( error, key ) {
          assert.ok( key instanceof DKIM.Key, 'Key instance not present' )
          assert.equal( key.type, 'rsa', 'Invalid key type' )
          done( error )
        })
      })

    })

    context( 'when key record does not exist', function() {

      specify( 'PERMFAIL if domain has no record', function( done ) {
        DKIM.getKey( 'aa', function( error, key ) {
          assert.equal( key, null )
          assert.ok( error instanceof Error, 'Missing expected error' )
          assert.equal( error.code, DKIM.PERMFAIL, 'Error code is not PERMFAIL' )
          done()
        })
      })

      specify( 'PERMFAIL if TXT record is not a valid key', function( done ) {
        DKIM.getKey( 'gmail.com', function( error, key ) {
          assert.ok( key instanceof DKIM.Key, 'Key instance not present' )
          assert.ok( key.key == null, 'Key is not null' )
          assert.ok( error instanceof Error, 'Error value not an instance of Error' )
          assert.equal( error.code, DKIM.PERMFAIL, 'Error code is not PERMFAIL' )
          done()
        })
      })

      specify( 'TEMPFAIL if query fails to respond' )

    })

  })

})
<|endoftext|>


<commit_before>/** @babel */

import fs from 'fs-extra'
import path from 'path'
import temp from 'temp'
import {Directory} from 'atom'
import Git from 'nodegit'
import GitShellOutStrategy from '../lib/git-shell-out-strategy'

import Repository from '../lib/models/repository'

export async function cloneRepository (repoName = 'three-files') {
  const workingDirPath = temp.mkdirSync('git-fixture-')
  const git = new GitShellOutStrategy(workingDirPath)
  await git.clone(path.join(__dirname, 'fixtures', `repo-${repoName}`, 'dot-git'))
  return fs.realpathSync(workingDirPath)
}

export async function createLocalAndRemoteRepositories (repoName = 'multiple-commits') {
  const baseRepoPath = await cloneRepository(repoName)
  const baseGit = new GitShellOutStrategy(baseRepoPath)

  // create remote bare repo with all commits
  const remoteRepoPath = temp.mkdirSync('git-remote-fixture-')
  const remoteGit = new GitShellOutStrategy(remoteRepoPath)
  await remoteGit.clone(baseRepoPath, {bare: true})

  // create local repo with one fewer commit
  await baseGit.exec(['reset', 'head~'])
  const localRepoPath = temp.mkdirSync('git-local-fixture-')
  const localGit = new GitShellOutStrategy(localRepoPath)
  await localGit.clone(baseRepoPath)
  await localGit.exec(['remote', 'set-url', 'origin', remoteRepoPath])
  return {baseRepoPath, remoteRepoPath, localRepoPath}
}

export function buildRepository (workingDirPath) {
  return Repository.open(new Directory(workingDirPath))
}

export function assertDeepPropertyVals (actual, expected) {
  function extractObjectSubset (actual, expected) {
    if (actual !== Object(actual)) return actual

    let actualSubset = Array.isArray(actual) ? [] : {}
    for (let key of Object.keys(expected)) {
      if (actual.hasOwnProperty(key)) {
        actualSubset[key] = extractObjectSubset(actual[key], expected[key])
      }
    }

    return actualSubset
  }

  assert.deepEqual(extractObjectSubset(actual, expected), expected)
}

export async function createEmptyCommit (repoPath, message) {
  const repo = await Git.Repository.open(repoPath)
  const head = await repo.getHeadCommit()
  const tree = await head.getTree()
  const parents = [head]
  const author = Git.Signature.default(repo)

  return repo.createCommit('HEAD', author, author, message, tree, parents)
}
<commit_msg>:fire: nodegit from test helpers<commit_after>/** @babel */

import fs from 'fs-extra'
import path from 'path'
import temp from 'temp'
import {Directory} from 'atom'
import GitShellOutStrategy from '../lib/git-shell-out-strategy'

import Repository from '../lib/models/repository'

export async function cloneRepository (repoName = 'three-files') {
  const workingDirPath = temp.mkdirSync('git-fixture-')
  const git = new GitShellOutStrategy(workingDirPath)
  await git.clone(path.join(__dirname, 'fixtures', `repo-${repoName}`, 'dot-git'))
  return fs.realpathSync(workingDirPath)
}

export async function createLocalAndRemoteRepositories (repoName = 'multiple-commits') {
  const baseRepoPath = await cloneRepository(repoName)
  const baseGit = new GitShellOutStrategy(baseRepoPath)

  // create remote bare repo with all commits
  const remoteRepoPath = temp.mkdirSync('git-remote-fixture-')
  const remoteGit = new GitShellOutStrategy(remoteRepoPath)
  await remoteGit.clone(baseRepoPath, {bare: true})

  // create local repo with one fewer commit
  await baseGit.exec(['reset', 'head~'])
  const localRepoPath = temp.mkdirSync('git-local-fixture-')
  const localGit = new GitShellOutStrategy(localRepoPath)
  await localGit.clone(baseRepoPath)
  await localGit.exec(['remote', 'set-url', 'origin', remoteRepoPath])
  return {baseRepoPath, remoteRepoPath, localRepoPath}
}

export function buildRepository (workingDirPath) {
  return Repository.open(new Directory(workingDirPath))
}

export function assertDeepPropertyVals (actual, expected) {
  function extractObjectSubset (actual, expected) {
    if (actual !== Object(actual)) return actual

    let actualSubset = Array.isArray(actual) ? [] : {}
    for (let key of Object.keys(expected)) {
      if (actual.hasOwnProperty(key)) {
        actualSubset[key] = extractObjectSubset(actual[key], expected[key])
      }
    }

    return actualSubset
  }

  assert.deepEqual(extractObjectSubset(actual, expected), expected)
}
<|endoftext|>


<commit_before>/*global it, describe, before, beforeEach */

var util = require('util');
var assert = require('assert');
var generators = require('..');
var helpers = require('../').test;

describe('yeoman.generators.test', function () {
  'use strict';
  var Unicorn;

  beforeEach(function () {
    var self = this;
    Unicorn = function (args, options) {
      self.args = args;
      self.options = options;
      generators.Base.apply(this, arguments);
    };

    util.inherits(Unicorn, generators.Base);

    });

  describe('helpers.createGenerator', function () {

    it('with args params', function () {
      helpers.createGenerator('unicorn:app', [
        [Unicorn, 'unicorn:app']
      ], ['temp']);
      // assert.ok();
      assert.deepEqual(this.args, ['temp']);
    });

    it('with options param', function () {
      helpers.createGenerator('unicorn:app', [
        [Unicorn, 'unicorn:app']
      ], ['temp'], {ui: 'tdd'});
      assert.equal(this.options.ui, 'tdd');
    });
  });
});
<commit_msg>Refactor and complement yeoman.test.createGenerator tests<commit_after>/*global it, describe, before, beforeEach */

var util = require('util');
var assert = require('assert');
var yeoman = require('..');
var helpers = yeoman.test;

describe('yeoman.test', function () {
  'use strict';

  beforeEach(function () {
    var self = this;
    this.StubGenerator = function (args, options) {
      self.args = args;
      self.options = options;
    };

    util.inherits(this.StubGenerator, yeoman.Base);
  });

  describe('#createGenerator', function () {

    it('create a new generator', function () {
      var generator = helpers.createGenerator('unicorn:app', [
        [this.StubGenerator, 'unicorn:app']
      ]);
      assert.ok(generator instanceof this.StubGenerator);
    });

    it('pass args params to the generator', function () {
      helpers.createGenerator('unicorn:app', [
        [this.StubGenerator, 'unicorn:app']
      ], ['temp']);
      assert.deepEqual(this.args, ['temp']);
    });

    it('pass options param to the generator', function () {
      helpers.createGenerator('unicorn:app', [
        [this.StubGenerator, 'unicorn:app']
      ], ['temp'], {ui: 'tdd'});
      assert.equal(this.options.ui, 'tdd');
    });
  });
});
<|endoftext|>


<commit_before>(function( $, window ) {
	if( location.hash !== "" ){
		throw "hash must be clear to start the tests";
	}

	// force the hash to test init
	location.hash = "#dialog-dialog";

	var $doc, instance, $instance, $nested, commonSetup, commonTeardown;

	commonSetup = function() {
		$instance = $( "#dialog" );
		$nested = $( "#nested-dialog" );

		if( $instance.data("dialog") ) {
			$instance.data( "dialog" ).destroy();
		}

		if( $nested.data("dialog") ) {
			$nested.data( "dialog" ).destroy();
		}

		$instance.dialog();
		$nested.dialog();
	};

	commonTeardown = function() {
		$instance.unbind( "dialog-closed" );
		$instance.unbind( "dialog-opened" );

		$instance.data( "dialog" ).destroy();
		$nested.data( "dialog" ).destroy();
	};

	// we have to give the browser the time to trigger a hashchange
	// so there's no mixup
	function closeInstance(){
		$instance.trigger( "dialog-close" );
		setTimeout(function(){
			start()
		}, 400);
	}

	var initOpened;

	$(window).bind("dialog-opened", function(event){
		initOpened = event.target;
	});

	asyncTest("should open on init if hash is correct", function(){
		ok(initOpened);
		start();
	});

	// NOTE this must come after the first test so that the init of the dialog
	// comes from the page's enhance event
	module( "init", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	// TODO move to `dialog.js` tests
	test("should prevent double init", function(){
		// the `isOpen` propery of the dialog object is set
		// to `false` at the end of init, we check that it never gets there
		$instance.data("dialog").isOpen = true;
		$instance.dialog();
		equal($instance.data("dialog").isOpen, true);
	})

	asyncTest("should append dialog name to hash for nested dialogs", function(){
		$instance.trigger( "dialog-open" );
		$instance.find( "#nested-dialog-anchor" ).trigger( "click" );
		equal("#dialog-dialog#nested-dialog-dialog", location.hash);
		start();
	});
})(jQuery, this);
<commit_msg>added back test for nested dialog<commit_after>(function( $, window ) {
	if( location.hash !== "" ){
		throw "hash must be clear to start the tests";
	}

	// force the hash to test init
	location.hash = "#dialog-dialog";

	var $doc, instance, $instance, $nested, commonSetup, commonTeardown;

	commonSetup = function() {
		$instance = $( "#dialog" );
		$nested = $( "#nested-dialog" );

		if( $instance.data("dialog") ) {
			$instance.data( "dialog" ).destroy();
		}

		if( $nested.data("dialog") ) {
			$nested.data( "dialog" ).destroy();
		}

		$instance.dialog();
		$nested.dialog();
	};

	commonTeardown = function() {
		$instance.unbind( "dialog-closed" );
		$instance.unbind( "dialog-opened" );
		$nested.unbind( "dialog-closed" );
		$nested.unbind( "dialog-opened" );

		$instance.data( "dialog" ).destroy();
		$nested.data( "dialog" ).destroy();
	};

	// we have to give the browser the time to trigger a hashchange
	// so there's no mixup
	function closeInstance(){
		$instance.trigger( "dialog-close" );
		setTimeout(function(){
			start()
		}, 400);
	}

	var initOpened;

	$(window).bind("dialog-opened", function(event){
		initOpened = event.target;
	});

	asyncTest("should open on init if hash is correct", function(){
		ok(initOpened);
		start();
	});

	// NOTE this must come after the first test so that the init of the dialog
	// comes from the page's enhance event
	module( "init", {
		setup: commonSetup,
		teardown: commonTeardown
	});

	// TODO move to `dialog.js` tests
	test("should prevent double init", function(){
		// the `isOpen` propery of the dialog object is set
		// to `false` at the end of init, we check that it never gets there
		$instance.data("dialog").isOpen = true;
		$instance.dialog();
		equal($instance.data("dialog").isOpen, true);
	})

	asyncTest("should append dialog name to hash for nested dialogs", function(){
		expect(2);
		$instance.trigger( "dialog-open" );
		$instance.find( "#nested-dialog-anchor" ).trigger( "click" );
		equal("#dialog-dialog#nested-dialog-dialog", location.hash);

		$nested.one("dialog-closed", function(){
			equal("#dialog-dialog", location.hash);
			start();
		});

		window.history.back();
	});
})(jQuery, this);
<|endoftext|>


<commit_before>
var assert = require('assert')
  , ref = require('ref')
  , Struct = require('ref-struct')
  , ffi = require('../')
  , Library = ffi.Library

describe('Library', function () {

  var charPtr = ref.refType(ref.types.char)

  afterEach(gc)

  it('should be a function', function () {
    assert(typeof Library === 'function');
  })

  it('should work with the `new` operator', function () {
    var l = new Library()
    assert(typeof l === 'object');
  })

  it('should accept `null` as a first argument', function () {
    var thisFuncs = new Library(null, {
      'printf': [ 'void', [ charPtr ] ]
    })
    assert(typeof thisFuncs.printf === 'function');
  })

  it('should accept a lib name as the first argument', function () {
    var lib = process.platform == 'win32' ? 'msvcrt' : 'libm'
    var libm = new Library(lib, {
        'ceil': [ 'double', [ 'double' ] ]
    })
    assert(typeof libm.ceil === 'function');
    assert(libm.ceil(1.1) === 2);
  })

  it('should accept a lib name with file extension', function() {
    var lib = process.platform == 'win32'
      ? 'msvcrt.dll'
      : 'libm' + ffi.LIB_EXT
    var libm = new Library(lib, {
      'ceil': [ 'double', ['double'] ]
    })
    assert(typeof libm.ceil === 'function');
    assert(libm.ceil(100.9) === 101);
  })

  it('should throw when an invalid function name is used', function () {
    try {
      new Library(null, {
          'doesnotexist__': [ 'void', [] ]
      });
      assert(false); // unreachable
    } catch (e) {
      assert(e);
    }
  })

  it('should work with "strcpy" and a 128 length string', function () {
    var ZEROS_128 = Array(128 + 1).join('0');
    var buf = new Buffer(256);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_128);
    assert(buf.readCString() === ZEROS_128);
  })

  it('should work with "strcpy" and a 2k length string', function () {
    var ZEROS_2K = Array(2e3 + 1).join('0');
    var buf = new Buffer(4096);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_2K);
    assert(buf.readCString() === ZEROS_2K);
  })

  if (process.platform == 'win32') {

    it('should work with "GetTimeOfDay" and a "FILETIME" Struct pointer',
    function () {
      var FILETIME = new Struct({
          'dwLowDateTime': ref.types.uint32
        , 'dwHighDateTime': ref.types.uint32
      })
      var l = new Library('kernel32', {
          'GetSystemTimeAsFileTime': [ 'void', [ 'pointer' ]]
      })
      var ft = new FILETIME()
      l.GetSystemTimeAsFileTime(ft.ref())
      // TODO: Add an assert clause here...
    })

  } else {

    it('should work with "gettimeofday" and a "timeval" Struct pointer',
    function () {
      var timeval = new Struct({
          'tv_sec': ref.types.long
        , 'tv_usec': ref.types.long
      })
      var timevalPtr = ref.refType(timeval)
      var timezonePtr = ref.refType(ref.types.void)
      var l = new Library(null, {
          'gettimeofday': [ref.types.int, [timevalPtr, timezonePtr]]
      })
      var tv = new timeval()
      l.gettimeofday(tv.ref(), null)
      assert.equal(Math.floor(Date.now() / 1000), tv.tv_sec)
    })

  }

  describe('async', function () {

    it('should call a function asynchronously', function (done) {
      var lib = process.platform == 'win32' ? 'msvcrt' : 'libm'
      var libm = new Library(lib, {
          'ceil': [ 'double', [ 'double' ], { async: true } ]
      })
      libm.ceil(1.1, function (err, res) {
        assert(err === null);
        assert(res === 2);
        done();
      })
    })

  })

})
<commit_msg>Update library.js<commit_after>
var assert = require('assert')
  , ref = require('ref')
  , Struct = require('ref-struct')
  , ffi = require('../')
  , Library = ffi.Library

describe('Library', function () {

  var charPtr = ref.refType(ref.types.char)

  afterEach(gc)

  it('should be a function', function () {
    assert(typeof Library === 'function');
  })

  it('should work with the `new` operator', function () {
    var l = new Library()
    assert(typeof l === 'object');
  })

  if(process.platform === 'linux' || process.platform === 'darwin') {
  it('should accept `null` as a first argument', function () {
    var thisFuncs = new Library(null, {
      'printf': [ 'void', [ charPtr ] ]
    })
    assert(typeof thisFuncs.printf === 'function');
  })
  } else {
    // when win32 skit ..
  it.skip('should accept `null` as a first argument', function () {
    var thisFuncs = new Library(null, {
      'printf': [ 'void', [ charPtr ] ]
    })
    assert(typeof thisFuncs.printf === 'function');
  })
  }

  it('should accept a lib name as the first argument', function () {
    var lib = process.platform == 'win32' ? 'msvcrt' : 'libm'
    var libm = new Library(lib, {
        'ceil': [ 'double', [ 'double' ] ]
    })
    assert(typeof libm.ceil === 'function');
    assert(libm.ceil(1.1) === 2);
  })

  it('should accept a lib name with file extension', function() {
    var lib = process.platform == 'win32'
      ? 'msvcrt.dll'
      : 'libm' + ffi.LIB_EXT
    var libm = new Library(lib, {
      'ceil': [ 'double', ['double'] ]
    })
    assert(typeof libm.ceil === 'function');
    assert(libm.ceil(100.9) === 101);
  })

  it('should throw when an invalid function name is used', function () {
    try {
      new Library(null, {
          'doesnotexist__': [ 'void', [] ]
      });
      assert(false); // unreachable
    } catch (e) {
      assert(e);
    }
  })

  if(process.platform === 'linux' || process.platform === 'darwin') {
  it('should work with "strcpy" and a 128 length string', function () {
    var ZEROS_128 = Array(128 + 1).join('0');
    var buf = new Buffer(256);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_128);
    assert(buf.readCString() === ZEROS_128);
  })
  } else {
  it.skip('should work with "strcpy" and a 128 length string', function () {
    var ZEROS_128 = Array(128 + 1).join('0');
    var buf = new Buffer(256);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_128);
    assert(buf.readCString() === ZEROS_128);
  })
  }

  if(process.platform === 'linux' || process.platform === 'darwin') {
  it('should work with "strcpy" and a 2k length string', function () {
    var ZEROS_2K = Array(2e3 + 1).join('0');
    var buf = new Buffer(4096);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_2K);
    assert(buf.readCString() === ZEROS_2K);
  })
  } else {
  it.skip('should work with "strcpy" and a 2k length string', function () {
    var ZEROS_2K = Array(2e3 + 1).join('0');
    var buf = new Buffer(4096);
    var strcpy = new Library(null, {
        'strcpy': [ charPtr, [ charPtr, 'string' ] ]
    }).strcpy;
    strcpy(buf, ZEROS_2K);
    assert(buf.readCString() === ZEROS_2K);
  })
  }
  if (process.platform == 'win32') {

    it('should work with "GetTimeOfDay" and a "FILETIME" Struct pointer',
    function () {
      var FILETIME = new Struct({
          'dwLowDateTime': ref.types.uint32
        , 'dwHighDateTime': ref.types.uint32
      })
      var l = new Library('kernel32', {
          'GetSystemTimeAsFileTime': [ 'void', [ 'pointer' ]]
      })
      var ft = new FILETIME()
      l.GetSystemTimeAsFileTime(ft.ref())
      // TODO: Add an assert clause here...
    })

  } else {

    it('should work with "gettimeofday" and a "timeval" Struct pointer',
    function () {
      var timeval = new Struct({
          'tv_sec': ref.types.long
        , 'tv_usec': ref.types.long
      })
      var timevalPtr = ref.refType(timeval)
      var timezonePtr = ref.refType(ref.types.void)
      var l = new Library(null, {
          'gettimeofday': [ref.types.int, [timevalPtr, timezonePtr]]
      })
      var tv = new timeval()
      l.gettimeofday(tv.ref(), null)
      assert.equal(Math.floor(Date.now() / 1000), tv.tv_sec)
    })

  }

  describe('async', function () {

    it('should call a function asynchronously', function (done) {
      var lib = process.platform == 'win32' ? 'msvcrt' : 'libm'
      var libm = new Library(lib, {
          'ceil': [ 'double', [ 'double' ], { async: true } ]
      })
      libm.ceil(1.1, function (err, res) {
        assert(err === null);
        assert(res === 2);
        done();
      })
    })

  })

})
<|endoftext|>


<commit_before>var assert  = require('assert');
var path    = require('path');
var fs      = require('fs');
var nock    = require('nock');
var _       = require('lodash');
var rimraf  = require('rimraf');
var async   = require('async');
var config  = require('../lib/core/config');
var Package = require('../lib/core/package');

describe('package', function () {
  it('Should resolve git URLs properly', function () {
    var pkg = new Package('jquery', 'git://github.com/jquery/jquery.git');
    assert.equal(pkg.gitUrl, 'git://github.com/jquery/jquery.git');
  });

  it('Should resolve git HTTP URLs properly', function () {
    var pkg = new Package('jquery', 'git+http://example.com/project.git');
    assert.equal(pkg.gitUrl, 'http://example.com/project.git');
  });

  it('Should resolve git HTTPS URLs properly', function () {
    var pkg = new Package('jquery', 'git+https://example.com/project.git');
    assert.equal(pkg.gitUrl, 'https://example.com/project.git');
  });

  it('Should resolve git URL tags', function () {
    var pkg = new Package('jquery', 'git://github.com/jquery/jquery.git#v1.0.1');
    assert.equal(pkg.tag, 'v1.0.1');
  });

  it('Should resolve github urls', function () {
    var pkg = new Package('jquery', 'git@github.com:twitter/flight.git#v1.0.1');
    assert.equal(pkg.tag, 'v1.0.1');
    assert.equal(pkg.gitUrl, 'git@github.com:twitter/flight.git');
  });

  it('Should resolve url when we got redirected', function() {
    var redirecting_url    = 'http://redirecting-url.com';
    var redirecting_to_url = 'http://redirected-to-url.com';

    var redirect_scope = nock(redirecting_url)
      .defaultReplyHeaders({'location': redirecting_to_url + '/jquery.zip'})
      .get('/jquery.zip')
      .reply(302);

    var redirect_to_scope = nock(redirecting_to_url)
      .get('/jquery.zip')
      .reply(200, "jquery content");

    var pkg = new Package('jquery', redirecting_url + '/jquery.zip');

    pkg.on('resolve', function () {
      assert(pkg.assetUrl);
      assert.equal(pkg.assetUrl, redirecting_to_url + '/jquery.zip');
    });

    pkg.download();
  });

  it('Should clone git packages', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');

    pkg.on('resolve', function () {
      assert(pkg.path);
      assert(fs.existsSync(pkg.path));
      next();
    });

    pkg.on('error', function (err) {
      throw new Error(err);
    });

    pkg.clone();
  });

  it('Should copy path packages', function (next) {
    var pkg = new Package('jquery', __dirname + '/assets/package-jquery');

    pkg.on('resolve', function () {
      assert(pkg.path);
      assert(fs.existsSync(pkg.path));
      next();
    });

    pkg.on('error', function (err) {
      throw new Error(err);
    });

    pkg.copy();
  });

  it('Should error on clone fail', function (next) {
    var pkg = new Package('random', 'git://example.com');

    pkg.on('error', function (err) {
      assert(err);
      next();
    });

    pkg.clone();
  });

  it('Should load correct json', function (next) {
    var pkg = new Package('jquery', __dirname + '/assets/package-jquery');

    pkg.on('loadJSON', function () {
      assert(pkg.json);
      assert.equal(pkg.json.name, 'jquery');
      next();
    });

    pkg.loadJSON();
  });

  it('Should resolve JSON dependencies', function (next) {
    var pkg = new Package('project', __dirname + '/assets/project');

    pkg.on('resolve', function () {
      var deps = _.pluck(pkg.getDeepDependencies(), 'name');
      assert.deepEqual(_.uniq(deps), ["package-bootstrap", "jquery-ui", "jquery"]);
      next();
    });

    pkg.resolve();
  });

  it('Should error when copying fails from non existing path', function (next) {
    var pkg = new Package('project', __dirname + '/assets/project-non-existent');

    pkg.on('error', function (err) {
      assert(err);
      next();
    });

    pkg.resolve();
  });

  it('Should copy files from temp folder to local path', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');

    pkg.on('resolve', function () {
      pkg.install();
    });
    pkg.on('install',function () {
      assert(fs.existsSync(pkg.localPath));
      rimraf(config.directory, function(err){
        next();
      });
    });
    pkg.clone();
  });

  it('Should have accessible file permissions on temp folder', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');
    var cachePath;

    pkg.on('cache', function() {
      cachePath = pkg.path;
    });
    pkg.on('resolve', function () {
      pkg.install();
    });
    pkg.on('install',function () {
      assert(fs.existsSync(pkg.localPath));
      async.map([pkg.localPath, cachePath], fs.stat, function (err, results) {
        if (err) throw new Error(err);
        assert.equal(results[0].mode, results[1].mode)
        rimraf(config.directory, function(err){
          next();
        });
      });
    });

    pkg.clone();
  });

});
<commit_msg>remove leftover assert in test<commit_after>var assert  = require('assert');
var path    = require('path');
var fs      = require('fs');
var nock    = require('nock');
var _       = require('lodash');
var rimraf  = require('rimraf');
var async   = require('async');
var config  = require('../lib/core/config');
var Package = require('../lib/core/package');

describe('package', function () {
  it('Should resolve git URLs properly', function () {
    var pkg = new Package('jquery', 'git://github.com/jquery/jquery.git');
    assert.equal(pkg.gitUrl, 'git://github.com/jquery/jquery.git');
  });

  it('Should resolve git HTTP URLs properly', function () {
    var pkg = new Package('jquery', 'git+http://example.com/project.git');
    assert.equal(pkg.gitUrl, 'http://example.com/project.git');
  });

  it('Should resolve git HTTPS URLs properly', function () {
    var pkg = new Package('jquery', 'git+https://example.com/project.git');
    assert.equal(pkg.gitUrl, 'https://example.com/project.git');
  });

  it('Should resolve git URL tags', function () {
    var pkg = new Package('jquery', 'git://github.com/jquery/jquery.git#v1.0.1');
    assert.equal(pkg.tag, 'v1.0.1');
  });

  it('Should resolve github urls', function () {
    var pkg = new Package('jquery', 'git@github.com:twitter/flight.git#v1.0.1');
    assert.equal(pkg.tag, 'v1.0.1');
    assert.equal(pkg.gitUrl, 'git@github.com:twitter/flight.git');
  });

  it('Should resolve url when we got redirected', function() {
    var redirecting_url    = 'http://redirecting-url.com';
    var redirecting_to_url = 'http://redirected-to-url.com';

    var redirect_scope = nock(redirecting_url)
      .defaultReplyHeaders({'location': redirecting_to_url + '/jquery.zip'})
      .get('/jquery.zip')
      .reply(302);

    var redirect_to_scope = nock(redirecting_to_url)
      .get('/jquery.zip')
      .reply(200, "jquery content");

    var pkg = new Package('jquery', redirecting_url + '/jquery.zip');

    pkg.on('resolve', function () {
      assert(pkg.assetUrl);
      assert.equal(pkg.assetUrl, redirecting_to_url + '/jquery.zip');
    });

    pkg.download();
  });

  it('Should clone git packages', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');

    pkg.on('resolve', function () {
      assert(pkg.path);
      assert(fs.existsSync(pkg.path));
      next();
    });

    pkg.on('error', function (err) {
      throw new Error(err);
    });

    pkg.clone();
  });

  it('Should copy path packages', function (next) {
    var pkg = new Package('jquery', __dirname + '/assets/package-jquery');

    pkg.on('resolve', function () {
      assert(pkg.path);
      assert(fs.existsSync(pkg.path));
      next();
    });

    pkg.on('error', function (err) {
      throw new Error(err);
    });

    pkg.copy();
  });

  it('Should error on clone fail', function (next) {
    var pkg = new Package('random', 'git://example.com');

    pkg.on('error', function (err) {
      assert(err);
      next();
    });

    pkg.clone();
  });

  it('Should load correct json', function (next) {
    var pkg = new Package('jquery', __dirname + '/assets/package-jquery');

    pkg.on('loadJSON', function () {
      assert(pkg.json);
      assert.equal(pkg.json.name, 'jquery');
      next();
    });

    pkg.loadJSON();
  });

  it('Should resolve JSON dependencies', function (next) {
    var pkg = new Package('project', __dirname + '/assets/project');

    pkg.on('resolve', function () {
      var deps = _.pluck(pkg.getDeepDependencies(), 'name');
      assert.deepEqual(_.uniq(deps), ["package-bootstrap", "jquery-ui", "jquery"]);
      next();
    });

    pkg.resolve();
  });

  it('Should error when copying fails from non existing path', function (next) {
    var pkg = new Package('project', __dirname + '/assets/project-non-existent');

    pkg.on('error', function (err) {
      assert(err);
      next();
    });

    pkg.resolve();
  });

  it('Should copy files from temp folder to local path', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');

    pkg.on('resolve', function () {
      pkg.install();
    });
    pkg.on('install',function () {
      assert(fs.existsSync(pkg.localPath));
      rimraf(config.directory, function(err){
        next();
      });
    });
    pkg.clone();
  });

  it('Should have accessible file permissions on temp folder', function (next) {
    var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git');
    var cachePath;

    pkg.on('cache', function() {
      cachePath = pkg.path;
    });
    pkg.on('resolve', function () {
      pkg.install();
    });
    pkg.on('install',function () {
      async.map([pkg.localPath, cachePath], fs.stat, function (err, results) {
        if (err) throw new Error(err);
        assert.equal(results[0].mode, results[1].mode)
        rimraf(config.directory, function(err){
          next();
        });
      });
    });

    pkg.clone();
  });

});
<|endoftext|>


<commit_before>
var should = require( 'should' ),
    payload = require( '../lib/payload' );

describe( 'payload', function()
{
    describe( 'payload()', function()
    {
        it( 'should return a function that takes 3 arguments when invoked', function()
        {
            payload().should.be.a( 'function' ).with.lengthOf( 3 );
        } );
    } );

    describe( 'payload()( req, res, next )', function()
    {
        var res = {};

        it( 'should continue with an Error with non-POST requests', function( done )
        {
            var _payload = payload(),
                req = { method: 'GET' },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should error if there is no POST argument named "payload', function( done )
        {
            var _payload = payload(),
                req = { method: 'POST', body: { params: {} } },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

         it( 'should work if there is a POST argument named "payload', function( done )
        {
            var _payload = payload(),
                req = { method: 'POST', body: { payload: 'Hello, World' } },
                next = function( err )
                {
                    should.not.exist( err );
                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should error if there is no POST argument whose name has been configured', function( done )
        {
            var _payload = payload( 'checkforme' ),
                req = { method: 'POST', body: { payload: 'Hello, World' } },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should work if there is a POST argument whose name has been configured', function( done )
        {
            var _payload = payload( 'checkforme' ),
                req = { method: 'POST', body: { checkforme: 'Hello, World' } },
                next = function( err )
                {
                    should.not.exist( err );
                    done();
                };

            _payload( req, res, next );
        } );
    } );

} );
<commit_msg>Pass a (stub) JSON payload in the unit tests.<commit_after>
var should = require( 'should' ),
    payload = require( '../lib/payload' );

describe( 'payload', function()
{
    describe( 'payload()', function()
    {
        it( 'should return a function that takes 3 arguments when invoked', function()
        {
            payload().should.be.a( 'function' ).with.lengthOf( 3 );
        } );
    } );

    describe( 'payload()( req, res, next )', function()
    {
        var res = {};

        it( 'should continue with an Error with non-POST requests', function( done )
        {
            var _payload = payload(),
                req = { method: 'GET' },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should error if there is no POST argument named "payload', function( done )
        {
            var _payload = payload(),
                req = { method: 'POST', body: {} },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

         it( 'should work if there is a POST argument named "payload', function( done )
        {
            var _payload = payload(),
                req = { method: 'POST', body: { payload: '"Hello, World"' } },
                next = function( err )
                {
                    should.not.exist( err );
                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should error if there is no POST argument whose name has been configured', function( done )
        {
            var _payload = payload( 'checkforme' ),
                req = { method: 'POST', body: { payload: '"Hello, World"' } },
                next = function( err )
                {
                    should.exist( err );
                    err.should.be.an.instanceOf( Error );

                    should.exist( err.status );
                    err.status.should.equal( 400 );

                    done();
                };

            _payload( req, res, next );
        } );

        it( 'should work if there is a POST argument whose name has been configured', function( done )
        {
            var _payload = payload( 'checkforme' ),
                req = { method: 'POST', body: { checkforme: '"Hello, World"' } },
                next = function( err )
                {
                    should.not.exist( err );
                    done();
                };

            _payload( req, res, next );
        } );
    } );

} );
<|endoftext|>


<commit_before>// Txn PouchDB unit tests
//
// Copyright 2011 Jason Smith, Jarrett Cruger and contributors
//
//    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.

var tap = require('tap')
var util = require('util')
var request = require('request')
var PouchDB = require('pouchdb')
var memdown = require('memdown')

var Txn = require('..')
var Txn_lib = require('../lib.js')

var TICK = typeof global.setImmediate !== 'function' ? process.nextTick : setImmediate;
var DB = process.env.db || 'txn_test';
var state = {};

// If $couchdb is defined, then test against Apache CouchDB. Otherwise, test against PouchDB.
var COUCH = process.env.couchdb
var POUCH = !COUCH

// This will be set in setup_*() and used throughout the tests.
var txn = function() { throw new Error('txn not set yet') }

tap.test('PouchDB plugin API', function(t) {
  t.type(Txn.PouchDB, 'object', 'Txn PouchDB plugin in the API')
  t.type(Txn.PouchDB.Transaction, 'function', 'Transaction initializer in the API')
  t.type(Txn.PouchDB.txn        , 'function', 'Transaction shortcut in the API')
  t.end()
})

tap.test('Setup', function(t) {
  var doc = {_id:'doc_a', val:23}

  if (COUCH)
    setup_couchdb()
  else
    setup_pouchdb()

  function done() {
    if (!state.db)
      throw new Error('Failed to create test DB')

    if (typeof txn != 'function')
      throw new Error('txn() not in the global state for further use in testing')

    if (POUCH) {
      t.type(state.db.Transaction, 'function', 'PouchDB plugin loaded Transaction class')
      t.type(state.db.txn        , 'function', 'PouchDB plugin loaded txn shortcut')
    }

    t.end()
  }

  function setup_pouchdb() {
    PouchDB.plugin(Txn.PouchDB)
    var db = new PouchDB(DB, {db:memdown})
    db.put(doc, function(er, body) {
      if (er) throw er
      if (!body || !body.ok)
        throw new Error('Cannot create doc: ' + JSON.stringify(body))

      state.db = db
      state.doc_a = doc
      state.doc_a._rev = body.rev
      txn = state.db.txn.bind(state.db)
      done()
    })
  }

  function setup_couchdb() {
    var url = COUCH + '/' + DB;
    request({method:'DELETE', uri:url}, function(er, resp, body) {
      if(er) throw er;
      var json = JSON.parse(body);

      var already_gone = (resp.statusCode === 404 && json.error === 'not_found');
      var deleted      = (resp.statusCode === 200 && json.ok    === true);

      if(! (already_gone || deleted))
        throw new Error('Unknown DELETE response: ' + resp.statusCode + ' ' + body);

      request({method:'PUT', uri:url}, function(er, resp, body) {
        if(er) throw er;
        var json = JSON.parse(body);

        if(resp.statusCode !== 201 || json.ok !== true)
          throw new Error('Unknown PUT response: ' + resp.statusCode + ' ' + body);

        request({method:'POST', uri:url, json:doc}, function(er, resp, body) {
          if(er) throw er;

          if(resp.statusCode !== 201 || body.ok !== true)
            throw new Error("Cannot store doc: " + resp.statusCode + ' ' + JSON.stringify(body));

          // CouchDB just uses the main API from require().
          txn = Txn

          doc._rev = body.rev;
          state.doc_a = doc;
          state.db = COUCH + '/' + DB
          done();
        })
      })
    })
  }
})

tap.test('Required params', function(t) {
  var ID = state.doc_a._id;
  var orig = state.doc_a.val;

  var noop_ran = false;
  var noop = function(_doc, to_txn) { noop_ran = true; to_txn() }

  t.throws(function() { txn({}, noop, noop) }, "Mandatory uri");

  t.throws(function() { txn({couch:COUCH}, noop, noop) }, "Mandatory uri; missing db,id");
  t.throws(function() { txn({db   :DB   }, noop, noop) }, "Mandatory uri; missing couch,id");
  t.throws(function() { txn({couch:COUCH, db:DB}, noop, noop) }, "Mandatory uri; missing id");

  if (COUCH) {
    t.throws(function() { txn({id   :ID   }, noop, noop) }, "Mandatory uri; missing couch,db");
    t.throws(function() { txn({couch:COUCH, id:ID}, noop, noop) }, "Mandatory uri");
    t.throws(function() { txn({db:DB      , id:ID}, noop, noop) }, "Mandatory uri");
    assert.equal(false, noop_ran, "CouchDB: Should never have called noop");
    t.equal(orig, state.doc_a.val, "Val should not have been updated");
    t.end()
  } else {
    t.throws(function() { txn({id:ID, uri:'http://127.0.0.1:5984/db/doc'}, noop, noop) }, 'PouchDB call with uri')
    t.throws(function() { txn({id:ID, url:'http://127.0.0.1:5984/db/doc'}, noop, noop) }, 'PouchDB call with url')
    t.doesNotThrow(function() { txn({id:ID}, noop, end) }, 'PouchDB call, only id')
  }

  function end() {
    t.equal(noop_ran, true, 'PouchDB call with id runs noop()')
    t.end()
  }
})

tap.test('Clashing parameters', function(t) {
  var url = 'http://127.0.0.1:4321/db/doc';
  var noop_ran = false;
  var noop = function(_doc, to_txn) { noop_ran = true; to_txn() }

  thrown(function() { txn({uri:url, couch:COUCH}, noop, noop) }, "Clashing params: uri,couch");
  thrown(function() { txn({url:url, couch:COUCH}, noop, noop) }, "Clashing params: url,couch");
  thrown(function() { txn({uri:url, db   :DB   }, noop, noop) }, "Clashing params: uri,db");
  thrown(function() { txn({url:url, id   :'foo'}, noop, noop) }, "Clashing params: url,id");

  thrown(function() { txn({uri:url, couch:COUCH, db:DB, id:'doc_a'}, noop, noop) }, "Clashing params, uri,couch,db,id");

  t.equal(false, noop_ran, "Noop should never run");
  t.end()

  function thrown(func, label) {
    var exception = null;
    try       { func()        }
    catch (e) { exception = e }

    var msg = COUCH ? /Clashing/ : /PouchDB disallows/
    t.ok(exception, 'Exception thrown: ' + label)
    t.match(exception && exception.message, msg, 'Exception message ' + msg + ': ' + label)
  }
})

tap.test('Update with URI', function(t) {
  function opts() {
    return COUCH ? {url: COUCH + '/' + DB + '/doc_a'}
                 : {id:'doc_a'}
  }

  txn(opts(), plus(3), function(er, doc) {
    if(er) throw er;
    t.equal(26, doc.val, "Update value in doc_a");

    txn(opts(), plus(6), function(er, doc) {
      if(er) throw er;
      t.equal(32, doc.val, "Second update value in doc_a");

      state.doc_a = doc;
      t.end()
    })
  })
})

tap.test('Update with parameters', function(t) {
  var opts = {id:state.doc_a._id}
  if (COUCH) {
    opts.db = DB
    opts.couch = COUCH
  }

  txn(opts, plus(-7), function(er, doc) {
    if(er) throw er;

    t.equal(25, doc.val, "Update via couch args");
    t.end()
  })
})

tap.test('Update with defaults', function(t) {
  // Set TXN to use for these tests, to test defaultable for CouchDB and PouchDB. All subsequent tests will assume txn()
  // has these defaults. Since PouchDB needs only the id option, it is harder to confirm its defaultable behavior. So
  // use the test_callback feature.
  if (COUCH) {
    txn = txn.defaults({couch:COUCH, db:DB})
    var TXN = txn
  } else if (POUCH) {
    PouchDB.plugin(Txn.defaults({test_callback:checker}).PouchDB)

    // XXX Pouch seems to re-use a database if the name is the same. If that ever changes, def_db will be missing doc_a.
    var def_db = new PouchDB(DB, {db:memdown})
    var TXN = def_db.txn.bind(def_db)
  }

  var op_ran = false
  function checker() { op_ran = true }

  TXN({id:'doc_a'}, plus(11), function(er, doc) {
    if(er) throw er;

    t.equal(36, doc.val, "Defaulted parameters: couch and db")

    if (POUCH)
      t.equal(op_ran, true, 'Defaultable PouchDB plugin ran test_callback')

    state.doc_a = doc;
    t.end()
  })
})

tap.test('Operation timeout', function(t) {
  var val = state.doc_a.val;
  txn({id:'doc_a', timeout:200}, waitfor(100), function(er, doc) {
    t.equal(er, null, 'No problem waiting 200ms for a 100ms operation')

    txn({id:'doc_a', timeout:200}, waitfor(300), function(er, doc) {
      t.match(er && er.message, /timeout/, 'Expect a timeout error for a long operation')
      t.end()
    })
  })
})

tap.test('Create a document', function(t) {
  txn({id:'no_create'}, setter('foo', 'nope'), function(er, doc) {
    t.match(er && er.message, /not_found/, 'Error on unknown doc ID')
    t.equal(doc, undefined, "Should not have a doc to work with")

    txn({id:'create_me', create:true}, setter('foo', 'yep'), function(er, doc) {
      t.equal(er, null, 'No problem creating a doc with create:true')
      t.equal(doc.foo, 'yep', 'Created doc data looks good')
      t.equal(Object.keys(doc).length, 3, "No unexpected fields in doc create")
      t.end()
    })
  })
})

tap.test('Timestamps', function(t) {
  txn({id:'doc_a'}, plus(-6), function(er, doc) {
    if(er) throw er;

    t.equal(doc.val, 30, "Normal update works")
    t.equal(doc.created_at, undefined, 'Normal update has no create timestamp')
    t.equal(doc.updated_at, undefined, 'Normal update has no update timestamp')

    txn({id:'doc_a', timestamps:true}, plus(2), function(er, doc) {
      if(er) throw er;

      t.equal(doc.val, 32, "Timestamps update works")
      t.equal(doc.created_at, undefined, "Updating existing docs does not add creation timestamp")
      t.type(doc.updated_at, 'string', "Update with timestamps")

      state.doc_a = doc

      txn({id:'stamps', create:true, timestamps:true}, setter('val', 10), function(er, doc) {
        if(er) throw er;

        t.equal(doc.val, 10, "Timestamps create works")
        t.type(doc.created_at, 'string', "Create with created_at")
        t.type(doc.updated_at, 'string', "Create with updated_at")
        t.equal(doc.updated_at, doc.created_at, "Creation and update stamps are equal")

        t.end()
      })
    })
  })
})

//
// Some helper operations
//

function plus(X) {
  return adder;
  function adder(doc, to_txn) {
    if(!doc.val)
      return to_txn(new Error('No value'));
    doc.val += X;
    return to_txn();
  }
}

function setter(K, V) {
  return set;
  function set(doc, to_txn) {
    doc[K] = V;
    return to_txn();
  }
}

function waitfor(X) {
  return finisher;
  function finisher(doc, to_txn) {
    setTimeout(finish, X);
    function finish() {
      return to_txn();
    }
  }
}

function thrower(er) {
  return thrower;
  function thrower() {
    if(er) throw er;
  }
}

// TODO
//
// db.txn('doc_id', operation, callback)
// db.txn({_id:'foo'}) throws because it is probably a bad call
// db.txn({doc:{_id:'foo'}}) works with the standard shortcut
//
// t = require('txn')
// db = new PouchDB('foo')
// t({db:db, id:'blah'}) works because it checks (db instanceof PouchDB)

function I(obj) {
  return util.inspect(obj, {colors:true, depth:10})
}
<commit_msg>Port preloaded doc tests to PouchDB and tap<commit_after>// Txn PouchDB unit tests
//
// Copyright 2011 Jason Smith, Jarrett Cruger and contributors
//
//    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.

var tap = require('tap')
var util = require('util')
var request = require('request')
var PouchDB = require('pouchdb')
var memdown = require('memdown')

var Txn = require('..')
var Txn_lib = require('../lib.js')

var TICK = typeof global.setImmediate !== 'function' ? process.nextTick : setImmediate;
var DB = process.env.db || 'txn_test';
var state = {};

// If $couchdb is defined, then test against Apache CouchDB. Otherwise, test against PouchDB.
var COUCH = process.env.couchdb
var POUCH = !COUCH

// This will be set in setup_*() and used throughout the tests.
var txn = function() { throw new Error('txn not set yet') }

tap.test('PouchDB plugin API', function(t) {
  t.type(Txn.PouchDB, 'object', 'Txn PouchDB plugin in the API')
  t.type(Txn.PouchDB.Transaction, 'function', 'Transaction initializer in the API')
  t.type(Txn.PouchDB.txn        , 'function', 'Transaction shortcut in the API')
  t.end()
})

tap.test('Setup', function(t) {
  var doc = {_id:'doc_a', val:23}

  if (COUCH)
    setup_couchdb()
  else
    setup_pouchdb()

  function done() {
    if (!state.db)
      throw new Error('Failed to create test DB')

    if (typeof txn != 'function')
      throw new Error('txn() not in the global state for further use in testing')

    if (POUCH) {
      t.type(state.db.Transaction, 'function', 'PouchDB plugin loaded Transaction class')
      t.type(state.db.txn        , 'function', 'PouchDB plugin loaded txn shortcut')
    }

    t.end()
  }

  function setup_pouchdb() {
    PouchDB.plugin(Txn.PouchDB)
    var db = new PouchDB(DB, {db:memdown})
    db.put(doc, function(er, body) {
      if (er) throw er
      if (!body || !body.ok)
        throw new Error('Cannot create doc: ' + JSON.stringify(body))

      state.db = db
      state.doc_a = doc
      state.doc_a._rev = body.rev
      txn = state.db.txn.bind(state.db)
      done()
    })
  }

  function setup_couchdb() {
    var url = COUCH + '/' + DB;
    request({method:'DELETE', uri:url}, function(er, resp, body) {
      if(er) throw er;
      var json = JSON.parse(body);

      var already_gone = (resp.statusCode === 404 && json.error === 'not_found');
      var deleted      = (resp.statusCode === 200 && json.ok    === true);

      if(! (already_gone || deleted))
        throw new Error('Unknown DELETE response: ' + resp.statusCode + ' ' + body);

      request({method:'PUT', uri:url}, function(er, resp, body) {
        if(er) throw er;
        var json = JSON.parse(body);

        if(resp.statusCode !== 201 || json.ok !== true)
          throw new Error('Unknown PUT response: ' + resp.statusCode + ' ' + body);

        request({method:'POST', uri:url, json:doc}, function(er, resp, body) {
          if(er) throw er;

          if(resp.statusCode !== 201 || body.ok !== true)
            throw new Error("Cannot store doc: " + resp.statusCode + ' ' + JSON.stringify(body));

          // CouchDB just uses the main API from require().
          txn = Txn

          doc._rev = body.rev;
          state.doc_a = doc;
          state.db = COUCH + '/' + DB
          done();
        })
      })
    })
  }
})

tap.test('Required params', function(t) {
  var ID = state.doc_a._id;
  var orig = state.doc_a.val;

  var noop_ran = false;
  var noop = function(_doc, to_txn) { noop_ran = true; to_txn() }

  t.throws(function() { txn({}, noop, noop) }, "Mandatory uri");

  t.throws(function() { txn({couch:COUCH}, noop, noop) }, "Mandatory uri; missing db,id");
  t.throws(function() { txn({db   :DB   }, noop, noop) }, "Mandatory uri; missing couch,id");
  t.throws(function() { txn({couch:COUCH, db:DB}, noop, noop) }, "Mandatory uri; missing id");

  if (COUCH) {
    t.throws(function() { txn({id   :ID   }, noop, noop) }, "Mandatory uri; missing couch,db");
    t.throws(function() { txn({couch:COUCH, id:ID}, noop, noop) }, "Mandatory uri");
    t.throws(function() { txn({db:DB      , id:ID}, noop, noop) }, "Mandatory uri");
    assert.equal(false, noop_ran, "CouchDB: Should never have called noop");
    t.equal(orig, state.doc_a.val, "Val should not have been updated");
    t.end()
  } else {
    t.throws(function() { txn({id:ID, uri:'http://127.0.0.1:5984/db/doc'}, noop, noop) }, 'PouchDB call with uri')
    t.throws(function() { txn({id:ID, url:'http://127.0.0.1:5984/db/doc'}, noop, noop) }, 'PouchDB call with url')
    t.doesNotThrow(function() { txn({id:ID}, noop, end) }, 'PouchDB call, only id')
  }

  function end() {
    t.equal(noop_ran, true, 'PouchDB call with id runs noop()')
    t.end()
  }
})

tap.test('Clashing parameters', function(t) {
  var url = 'http://127.0.0.1:4321/db/doc';
  var noop_ran = false;
  var noop = function(_doc, to_txn) { noop_ran = true; to_txn() }

  thrown(function() { txn({uri:url, couch:COUCH}, noop, noop) }, "Clashing params: uri,couch");
  thrown(function() { txn({url:url, couch:COUCH}, noop, noop) }, "Clashing params: url,couch");
  thrown(function() { txn({uri:url, db   :DB   }, noop, noop) }, "Clashing params: uri,db");
  thrown(function() { txn({url:url, id   :'foo'}, noop, noop) }, "Clashing params: url,id");

  thrown(function() { txn({uri:url, couch:COUCH, db:DB, id:'doc_a'}, noop, noop) }, "Clashing params, uri,couch,db,id");

  t.equal(false, noop_ran, "Noop should never run");
  t.end()

  function thrown(func, label) {
    var exception = null;
    try       { func()        }
    catch (e) { exception = e }

    var msg = COUCH ? /Clashing/ : /PouchDB disallows/
    t.ok(exception, 'Exception thrown: ' + label)
    t.match(exception && exception.message, msg, 'Exception message ' + msg + ': ' + label)
  }
})

tap.test('Update with URI', function(t) {
  function opts() {
    return COUCH ? {url: COUCH + '/' + DB + '/doc_a'}
                 : {id:'doc_a'}
  }

  txn(opts(), plus(3), function(er, doc) {
    if(er) throw er;
    t.equal(26, doc.val, "Update value in doc_a");

    txn(opts(), plus(6), function(er, doc) {
      if(er) throw er;
      t.equal(32, doc.val, "Second update value in doc_a");

      state.doc_a = doc;
      t.end()
    })
  })
})

tap.test('Update with parameters', function(t) {
  var opts = {id:state.doc_a._id}
  if (COUCH) {
    opts.db = DB
    opts.couch = COUCH
  }

  txn(opts, plus(-7), function(er, doc) {
    if(er) throw er;

    t.equal(25, doc.val, "Update via couch args");
    t.end()
  })
})

tap.test('Update with defaults', function(t) {
  // Set TXN to use for these tests, to test defaultable for CouchDB and PouchDB. All subsequent tests will assume txn()
  // has these defaults. Since PouchDB needs only the id option, it is harder to confirm its defaultable behavior. So
  // use the test_callback feature.
  if (COUCH) {
    txn = txn.defaults({couch:COUCH, db:DB})
    var TXN = txn
  } else if (POUCH) {
    PouchDB.plugin(Txn.defaults({test_callback:checker}).PouchDB)

    // XXX Pouch seems to re-use a database if the name is the same. If that ever changes, def_db will be missing doc_a.
    var def_db = new PouchDB(DB, {db:memdown})
    var TXN = def_db.txn.bind(def_db)
  }

  var op_ran = false
  function checker() { op_ran = true }

  TXN({id:'doc_a'}, plus(11), function(er, doc) {
    if(er) throw er;

    t.equal(36, doc.val, "Defaulted parameters: couch and db")

    if (POUCH)
      t.equal(op_ran, true, 'Defaultable PouchDB plugin ran test_callback')

    state.doc_a = doc;
    t.end()
  })
})

tap.test('Operation timeout', function(t) {
  var val = state.doc_a.val;
  txn({id:'doc_a', timeout:200}, waitfor(100), function(er, doc) {
    t.equal(er, null, 'No problem waiting 200ms for a 100ms operation')

    txn({id:'doc_a', timeout:200}, waitfor(300), function(er, doc) {
      t.match(er && er.message, /timeout/, 'Expect a timeout error for a long operation')
      t.end()
    })
  })
})

tap.test('Create a document', function(t) {
  txn({id:'no_create'}, setter('foo', 'nope'), function(er, doc) {
    t.match(er && er.message, /not_found/, 'Error on unknown doc ID')
    t.equal(doc, undefined, "Should not have a doc to work with")

    txn({id:'create_me', create:true}, setter('foo', 'yep'), function(er, doc) {
      t.equal(er, null, 'No problem creating a doc with create:true')
      t.equal(doc.foo, 'yep', 'Created doc data looks good')
      t.equal(Object.keys(doc).length, 3, "No unexpected fields in doc create")
      t.end()
    })
  })
})

tap.test('Timestamps', function(t) {
  txn({id:'doc_a'}, plus(-6), function(er, doc) {
    if(er) throw er;

    t.equal(doc.val, 30, "Normal update works")
    t.equal(doc.created_at, undefined, 'Normal update has no create timestamp')
    t.equal(doc.updated_at, undefined, 'Normal update has no update timestamp')

    txn({id:'doc_a', timestamps:true}, plus(2), function(er, doc) {
      if(er) throw er;

      t.equal(doc.val, 32, "Timestamps update works")
      t.equal(doc.created_at, undefined, "Updating existing docs does not add creation timestamp")
      t.type(doc.updated_at, 'string', "Update with timestamps")

      state.doc_a = doc

      txn({id:'stamps', create:true, timestamps:true}, setter('val', 10), function(er, doc) {
        if(er) throw er;

        t.equal(doc.val, 10, "Timestamps create works")
        t.type(doc.created_at, 'string', "Create with created_at")
        t.type(doc.updated_at, 'string', "Create with updated_at")
        t.equal(doc.updated_at, doc.created_at, "Creation and update stamps are equal")

        t.end()
      })
    })
  })
})

tap.test('Preloaded doc with no conflicts', function(t) {
  txn({id:'doc_b', create:true}, setter('type','first'), function(er, doc_b, txr) {
    if(er) throw er;
    t.equal(doc_b.type, 'first', 'Create doc for preload')
    t.equal(txr.tries, 1, 'Takes 1 try for doc update')
    t.equal(txr.fetches, 1, 'Takes 1 fetch for doc update')

    var ops = 0;
    function update_b(doc, to_txn) {
      ops += 1;
      doc.type = 'preloaded';
      return to_txn();
    }

    txn({doc:doc_b}, update_b, function(er, doc, txr) {
      if(er) throw er;

      t.equal(doc.type, 'preloaded', 'Preloaded operation runs normally')
      t.equal(ops, 1, 'Only one op for preloaded doc without conflicts')
      t.equal(txr.tries, 1, 'One try for preloaded doc without conflicts')
      t.equal(txr.fetches, 0, 'No fetches for preloaded doc without conflicts')

      state.doc_b = doc
      t.end()
    })
  })
})

//
// Some helper operations
//

function plus(X) {
  return adder;
  function adder(doc, to_txn) {
    if(!doc.val)
      return to_txn(new Error('No value'));
    doc.val += X;
    return to_txn();
  }
}

function setter(K, V) {
  return set;
  function set(doc, to_txn) {
    doc[K] = V;
    return to_txn();
  }
}

function waitfor(X) {
  return finisher;
  function finisher(doc, to_txn) {
    setTimeout(finish, X);
    function finish() {
      return to_txn();
    }
  }
}

function thrower(er) {
  return thrower;
  function thrower() {
    if(er) throw er;
  }
}

// TODO
//
// db.txn('doc_id', operation, callback)
// db.txn({_id:'foo'}) throws because it is probably a bad call
// db.txn({doc:{_id:'foo'}}) works with the standard shortcut
//
// t = require('txn')
// db = new PouchDB('foo')
// t({db:db, id:'blah'}) works because it checks (db instanceof PouchDB)

function I(obj) {
  return util.inspect(obj, {colors:true, depth:10})
}
<|endoftext|>