<commit_before>/* eslint no-sync: 0 */
var mvm = require('../');
var assert = require('assert');
var exec = require('child_process').exec;
var path = require('path');
var which = require('which');
var fs = require('fs');
var debug = require('debug')('mongodb-version-manager:test');

var M = path.resolve(__dirname, '../bin/m.js');
var NODE = which.sync('node');

debug('path to m bin is %s', M);
debug('path to node bin is %s', NODE);

var run = function(args, done) {
  /* eslint no-sync:0 no-console:0 */
  if (typeof args === 'function') {
    done = args;
    args = '';
  }

  var cmd = '"' + NODE + '" ' + M + ' ' + args;
  debug('running `%s`', cmd);
  assert(fs.existsSync(M), M + ' does not exist');
  assert(fs.existsSync(NODE), NODE + ' does not exist');

  exec(cmd, function(err, stdout, stderr) {
    debug('result of `%s`', cmd, JSON.stringify({
      stdout: stdout.toString('utf-8'),
      stderr: stderr.toString('utf-8')
    }, null, 2));

    if (err) {
      debug('failed to run `%s`', cmd);
      console.error('exec failed: ', err);
      return done(err);
    }
    debug('completed successfully `%s`', cmd);
    done();
  });
};

describe('mongodb-version-manager', function() {
  describe('bin', function() {
    it('should work if i run `m available`', function(done) {
      run('available', done);
    });

    it('should work if i run `m path`', function(done) {
      run('path', done);
    });
  });
  describe('current', function() {
    it('should provide the current version', function(done) {
      mvm.current(function(err) {
        done(err);
      });
    });
  });
  describe('available', function() {
    it('should list stable versions', function(done) {
      mvm.available({
        stable: true
      }, function(err, versions) {
        assert.ifError(err);
        var unstable = versions.filter(function(v) {
          return parseInt(v.split('.')[1], 10) % 2 > 0;
        });
        assert.equal(unstable.length, 0);
        done();
      });
    });
    it('should list unstable versions', function(done) {
      mvm.available({
        unstable: true
      }, function(err, versions) {
        assert.ifError(err);
        var stable = versions.filter(function(v) {
          return parseInt(v.split('.')[1], 10) % 2 === 0;
        });
        assert.equal(stable.length, 0);
        done();
      });
    });
    it('should list rc versions', function(done) {
      mvm.available({
        rc: true
      }, function(err, versions) {
        assert.ifError(err);
        var stable = versions.filter(function(v) {
          return v.indexOf('rc') === -1;
        });
        assert.equal(stable.length, 0);
        done();
      });
    });
  });
  describe('functional', function() {
    it('should install 2.6.11 [#15]', function(done) {
      run('use 2.6.11', function(err) {
        if (err) {
          return done(err);
        }
        var dest = path.join(mvm.config.cache, 'mongodb', '2.6.11', 'bin', 'mongod');
        fs.exists(dest, function(exists) {
          assert(exists, dest + ' does not exist');
          done();
        });
      });
    });
    it('should update $PATH');
    it('should have an executable shell binary');
    it('should install 2.6.11 enterprise');
    it('should install have 2.6.11 and a separate 2.6.11 enterprise');
  });
});
<commit_msg>skip functional test for now<commit_after>/* eslint no-sync: 0 */
var mvm = require('../');
var assert = require('assert');
var exec = require('child_process').exec;
var path = require('path');
var which = require('which');
var fs = require('fs');
var debug = require('debug')('mongodb-version-manager:test');

var M = path.resolve(__dirname, '../bin/m.js');
var NODE = which.sync('node');

debug('path to m bin is %s', M);
debug('path to node bin is %s', NODE);

var run = function(args, done) {
  /* eslint no-sync:0 no-console:0 */
  if (typeof args === 'function') {
    done = args;
    args = '';
  }

  var cmd = '"' + NODE + '" ' + M + ' ' + args;
  debug('running `%s`', cmd);
  assert(fs.existsSync(M), M + ' does not exist');
  assert(fs.existsSync(NODE), NODE + ' does not exist');

  exec(cmd, function(err, stdout, stderr) {
    debug('result of `%s`', cmd, JSON.stringify({
      stdout: stdout.toString('utf-8'),
      stderr: stderr.toString('utf-8')
    }, null, 2));

    if (err) {
      debug('failed to run `%s`', cmd);
      console.error('exec failed: ', err);
      return done(err);
    }
    debug('completed successfully `%s`', cmd);
    done();
  });
};

describe('mongodb-version-manager', function() {
  describe('bin', function() {
    it('should work if i run `m available`', function(done) {
      run('available', done);
    });

    it('should work if i run `m path`', function(done) {
      run('path', done);
    });
  });
  describe('current', function() {
    it('should provide the current version', function(done) {
      mvm.current(function(err) {
        done(err);
      });
    });
  });
  describe('available', function() {
    it('should list stable versions', function(done) {
      mvm.available({
        stable: true
      }, function(err, versions) {
        assert.ifError(err);
        var unstable = versions.filter(function(v) {
          return parseInt(v.split('.')[1], 10) % 2 > 0;
        });
        assert.equal(unstable.length, 0);
        done();
      });
    });
    it('should list unstable versions', function(done) {
      mvm.available({
        unstable: true
      }, function(err, versions) {
        assert.ifError(err);
        var stable = versions.filter(function(v) {
          return parseInt(v.split('.')[1], 10) % 2 === 0;
        });
        assert.equal(stable.length, 0);
        done();
      });
    });
    it('should list rc versions', function(done) {
      mvm.available({
        rc: true
      }, function(err, versions) {
        assert.ifError(err);
        var stable = versions.filter(function(v) {
          return v.indexOf('rc') === -1;
        });
        assert.equal(stable.length, 0);
        done();
      });
    });
  });
  describe.skip('functional', function() {
    it('should install 2.6.11 [#15]', function(done) {
      run('use 2.6.11', function(err) {
        if (err) {
          return done(err);
        }
        var dest = path.join(mvm.config.cache, 'mongodb', '2.6.11', 'bin', 'mongod');
        fs.exists(dest, function(exists) {
          assert(exists, dest + ' does not exist');
          done();
        });
      });
    });
    it('should update $PATH');
    it('should have an executable shell binary');
    it('should install 2.6.11 enterprise');
    it('should install have 2.6.11 and a separate 2.6.11 enterprise');
  });
});
<|endoftext|>


<commit_before>'use strict';

var arrayUnique = require('../');
var assert = require('assert');
var mongoose = require('mongoose');

if (process.env.D) {
  mongoose.set('debug', true);
}

describe('arrayUnique', function() {
  before(function() {
    mongoose.connect('mongodb://localhost:27017/mongoose_test');
  });

  beforeEach(function(done) {
    mongoose.connection.dropDatabase(done);
  });

  it('works', function(done) {
    var schema = new mongoose.Schema({
      arr: [{ type: String, unique: true }],
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T1', schema);

    M.create({}, function(error, doc) {
      assert.ifError(error);
      doc.arr.push('test');
      doc.docArr.push({ name: 'test' });
      doc.save(function(error) {
        assert.ifError(error);
        doc.arr.push('test');
        doc.save(function(error) {
          assert.ok(error);
          assert.ok(error.errors['arr'].message.indexOf('Duplicate values') !== -1,
            error.errors['arr'].message);
          done();
        });
      });
    });
  });

  it('pushing onto doc array', function(done) {
    var schema = new mongoose.Schema({
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T2', schema);

    M.create({}, function(error, doc) {
      assert.ifError(error);
      doc.docArr.push({ name: 'test' });
      doc.save(function(error) {
        assert.ifError(error);
        doc.docArr.push('test');
        doc.save(function(error) {
          assert.ok(error);
          assert.ok(error.errors['docArr'].message.indexOf('Duplicate values') !== -1,
            error.errors['docArr'].message);
          done();
        });
      });
    });
  });

  it('with new docs', function(done) {
    var schema = new mongoose.Schema({
      arr: [{ type: String, unique: true }],
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T3', schema);
    var m = new M({
      arr: ['test', 'test'],
      docArr: [{ name: 'test' }, { name: 'test' }]
    });

    m.save(function(error) {
      assert.ok(error);
      assert.ok(error.errors['arr'].message.indexOf('Duplicate values') !== -1,
        error.errors['arr'].message);
      assert.ok(error.errors['docArr'].message.indexOf('Duplicate values') !== -1,
        error.errors['docArr'].message);
      done();
    });
  });

  it('nested', function(done) {
    var schema = new mongoose.Schema({
      nested: {
        arr: [{ type: String, unique: true }],
        docArr: [{ name: { type: String, unique: true } }]
      }
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T4', schema);
    var m = new M({
      nested: {
        arr: ['test', 'test'],
        docArr: [{ name: 'test' }, { name: 'test' }]
      }
    });

    m.save(function(error) {
      assert.ok(error);
      assert.ok(error.errors['nested.arr'].message.indexOf('Duplicate values') !== -1,
        error.errors['nested.arr'].message);
      assert.ok(error.errors['nested.docArr'].message.indexOf('Duplicate values') !== -1,
        error.errors['nested.docArr'].message);
      done();
    });
  });
});
<commit_msg>add race condition test<commit_after>'use strict';

var arrayUnique = require('../');
var assert = require('assert');
var mongoose = require('mongoose');

if (process.env.D) {
  mongoose.set('debug', true);
}

describe('arrayUnique', function() {
  before(function() {
    mongoose.connect('mongodb://localhost:27017/mongoose_test');
  });

  beforeEach(function(done) {
    mongoose.connection.dropDatabase(done);
  });

  it('works', function(done) {
    var schema = new mongoose.Schema({
      arr: [{ type: String, unique: true }],
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T1', schema);

    M.create({}, function(error, doc) {
      assert.ifError(error);
      doc.arr.push('test');
      doc.docArr.push({ name: 'test' });
      doc.save(function(error) {
        assert.ifError(error);
        doc.arr.push('test');
        doc.save(function(error) {
          assert.ok(error);
          assert.ok(error.errors['arr'].message.indexOf('Duplicate values') !== -1,
            error.errors['arr'].message);
          done();
        });
      });
    });
  });

  it('pushing onto doc array', function(done) {
    var schema = new mongoose.Schema({
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T2', schema);

    M.create({}, function(error, doc) {
      assert.ifError(error);
      doc.docArr.push({ name: 'test' });
      doc.save(function(error) {
        assert.ifError(error);
        doc.docArr.push('test');
        doc.save(function(error) {
          assert.ok(error);
          assert.ok(error.errors['docArr'].message.indexOf('Duplicate values') !== -1,
            error.errors['docArr'].message);
          done();
        });
      });
    });
  });

  it('with race condition', function(done) {
    var schema = new mongoose.Schema({
      arr: [{ type: String, unique: true }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T3', schema);

    M.create({}, function(error, doc) {
      assert.ifError(error);
      M.findById(doc, function(error, doc1) {
        M.findById(doc, function(error, doc2) {
          doc1.arr.push('test');
          doc1.save(function(error) {
            assert.ifError(error);
            doc2.arr.push('test');
            doc2.save(function(error) {
              assert.ok(error);
              assert.ok(error.message.indexOf('No matching document') !== -1,
                error.message);
              done();
            });
          });
        });
      });
    });
  });

  it('with new docs', function(done) {
    var schema = new mongoose.Schema({
      arr: [{ type: String, unique: true }],
      docArr: [{ name: { type: String, unique: true } }]
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T4', schema);
    var m = new M({
      arr: ['test', 'test'],
      docArr: [{ name: 'test' }, { name: 'test' }]
    });

    m.save(function(error) {
      assert.ok(error);
      assert.ok(error.errors['arr'].message.indexOf('Duplicate values') !== -1,
        error.errors['arr'].message);
      assert.ok(error.errors['docArr'].message.indexOf('Duplicate values') !== -1,
        error.errors['docArr'].message);
      done();
    });
  });

  it('nested', function(done) {
    var schema = new mongoose.Schema({
      nested: {
        arr: [{ type: String, unique: true }],
        docArr: [{ name: { type: String, unique: true } }]
      }
    });
    schema.plugin(arrayUnique);
    var M = mongoose.model('T5', schema);
    var m = new M({
      nested: {
        arr: ['test', 'test'],
        docArr: [{ name: 'test' }, { name: 'test' }]
      }
    });

    m.save(function(error) {
      assert.ok(error);
      assert.ok(error.errors['nested.arr'].message.indexOf('Duplicate values') !== -1,
        error.errors['nested.arr'].message);
      assert.ok(error.errors['nested.docArr'].message.indexOf('Duplicate values') !== -1,
        error.errors['nested.docArr'].message);
      done();
    });
  });
});
<|endoftext|>


<commit_before>"use strict";

/* global describe, it, xit */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
import { expect } from "chai";
import isFunction from "lodash/isFunction";
import size from "lodash/size";
import reduxApi from "../src/index";
import transformers from "../src/transformers";

function getState() {
  return { test: { loading: false, data: {} } };
}

describe("index", function() {
  it("check transformers", function() {
    expect(transformers.array()).to.eql([]);
    expect(transformers.array({ id: 1 })).to.eql([{ id: 1 }]);
    expect(transformers.array([1])).to.eql([1]);

    expect(transformers.object()).to.eql({});
    expect(transformers.object({ id: 1 })).to.eql({ id: 1 });
    expect(transformers.object([1])).to.eql({ data: [1] });
    expect(transformers.object("test")).to.eql({ data: "test" });
    expect(transformers.object(1)).to.eql({ data: 1 });
    expect(transformers.object(true)).to.eql({ data: true });
  });
  it("check null params", function() {
    expect(isFunction(reduxApi)).to.be.true;
    const api = reduxApi();
    expect(api.actions).to.eql({});
    expect(api.reducers).to.eql({});
  });
  it("check rootUrl", function() {
    const urls = [];
    function fetchUrl(url) {
      urls.push(url);
      return new Promise(resolve=> resolve({ msg: "hello" }));
    }
    const res = reduxApi({
      test1: "/url1/",
      test2: "url2",
      test3: "",
      test4: "/(:id)"
    })
    .use("fetch", fetchUrl)
    .use("server", false)
    .use("rootUrl", "http://api.com/root");

    const res2 = reduxApi({
      test1: "/url1/",
      test2: "url2",
      test3: "",
      test4: "/(:id)"
    })
    .use("fetch", fetchUrl)
    .use("server", false)
    .use("rootUrl", "http://api.ru/");

    const act = res.actions;
    const act2 = res2.actions;
    return Promise.all([
      act.test1.request(),
      act.test2.request(),
      act.test3.request(),
      act.test4.request({ id: 1 }),
      act2.test1.request(),
      act2.test2.request(),
      act2.test3.request(),
      act2.test4.request({ id: 2 })
    ]).then(()=> {
      expect([
        "http://api.com/root/url1/",
        "http://api.com/root/url2",
        "http://api.com/root/",
        "http://api.com/root/1",
        "http://api.ru/url1/",
        "http://api.ru/url2",
        "http://api.ru/",
        "http://api.ru/2"
      ]).to.eql(urls);
    });
  });
  it("check string url", function() {
    function fetchSuccess(url, data) {
      expect(url).to.eql("/plain/url");
      expect(data).to.eql({});
      return new Promise(function(resolve) {
        resolve({ msg: "hello" });
      });
    }
    const res = reduxApi({
      test: "/plain/url"
    })
    .use("fetch", fetchSuccess);
    expect(size(res.actions)).to.eql(1);
    expect(size(res.events)).to.eql(1);

    expect(size(res.reducers)).to.eql(1);
    expect(res.actions.test).to.exist;
    expect(res.events.test).to.have.keys(
      "actionFetch",
      "actionSuccess",
      "actionFail",
      "actionReset"
    );
    expect(res.reducers.test).to.exist;
    const expectedEvent = [
      {
        type: "@@redux-api@test",
        syncing: false,
        request: { pathvars: undefined, params: {} }
      }, {
        type: "@@redux-api@test_success",
        data: { msg: "hello" },
        origData: { msg: "hello" },
        syncing: false,
        request: { pathvars: undefined, params: {} }
      }
    ];
    return new Promise((resolve)=> {
      const action = res.actions.test(resolve);
      function dispatch(msg) {
        expect(expectedEvent).to.have.length.above(0);
        const exp = expectedEvent.shift();
        expect(msg).to.eql(exp);
      }
      action(dispatch, getState);
    }).then(()=> {
      expect(expectedEvent).to.have.length(0);
    });
  });
  it("check object url", function() {
    function fetchSuccess(url, options) {
      expect(url).to.eql("/plain/url/1");
      expect(options).to.eql({
        headers: {
          Accept: "application/json"
        }
      });
      return new Promise(function(resolve) {
        resolve({ msg: "hello" });
      });
    }
    const res = reduxApi({
      test: {
        url: "/plain/url/:id",
        options: {
          headers: {
            Accept: "application/json"
          }
        }
      }
    }).use("fetch", fetchSuccess);
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.exist;

    const expectedEvent = [{
      type: "@@redux-api@test",
      syncing: false,
      request: { pathvars: { id: 1 }, params: {} }
    }, {
      type: "@@redux-api@test_success",
      data: { msg: "hello" },
      origData: { msg: "hello" },
      syncing: false,
      request: { pathvars: { id: 1 }, params: {} }
    }];
    return new Promise((resolve)=> {
      const action = res.actions.test({ id: 1 }, resolve);
      function dispatch(msg) {
        expect(expectedEvent).to.have.length.above(0);
        const exp = expectedEvent.shift();
        expect(msg).to.eql(exp);
      }
      action(dispatch, getState);
    }).then(()=> {
      expect(expectedEvent).to.have.length(0);
    });
  });
  it("use provided reducerName when avaliable", function() {
    const res = reduxApi({
      test: {
        reducerName: "foo",
        url: "/plain/url/:id",
        options: {
          headers: {
            Accept: "application/json"
          }
        }
      }
    }).use("fetch", function fetchSuccess() {});
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.not.exist;
    expect(res.reducers.foo).to.exist;
  });

  xit("check virtual option with broadcast", function() {
    const BROADCAST_ACTION = "BROADCAST_ACTION";
    const res = reduxApi({
      test: {
        url: "/api",
        broadcast: [BROADCAST_ACTION],
        virtual: true
      }
    }).use("fetch", function fetchSuccess() {});
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.not.exist;
  });

  it("check prefetch options", function() {
    const expectUrls = [];
    function fetchSuccess(url) {
      expectUrls.push(url);
      return new Promise(resolve=> resolve({ url }));
    }
    const res = reduxApi({
      test: "/test",
      test1: {
        url: "/test1",
        prefetch: [
          function(opts, cb) {
            opts.actions.test(cb)(
              opts.dispatch, opts.getState
            );
          }
        ]
      }
    }).use("fetch", fetchSuccess);
    return new Promise((resolve)=> {
      const action = res.actions.test1(resolve);
      action(function() {}, getState);
    }).then(()=> {
      expect(expectUrls).to.eql([
        "/test", "/test1"
      ]);
    });
  });

  it("check helpers", function() {
    const result = [];
    function getState() {
      return {
        params: { id: 9, name: "kitty" },
        hello: { loading: false, data: {} }
      };
    }
    function dispatch() {}
    const res = reduxApi({
      hello: {
        url: "/test/:name/:id",
        helpers: {
          test1(id, name) {
            return [{ id, name }];
          },
          test2() {
            const { id, name } = this.getState().params;
            return [{ id, name }];
          },
          testSync: {
            sync: true,
            call(id) {
              return [{ id, name: "admin" }, { method: "post" }];
            }
          }
        }
      }
    }).use("fetch", function(url, opts) {
      result.push({ url, opts });
      return new Promise(
        resolve=> resolve({ hello: "world" }));
    });
    const a1 = new Promise((resolve)=> {
      res.actions.hello.test1(2, "lexich", resolve)(dispatch, getState);
    });
    const a2 = new Promise((resolve)=> {
      res.actions.hello.test2(resolve)(dispatch, getState);
    });
    const a3 = new Promise((resolve)=> {
      const mockSync = res.actions.hello.sync;
      let counter = 0;
      res.actions.hello.sync = function(...args) {
        counter += 1;
        return mockSync.apply(this, args);
      };
      res.actions.hello.testSync(1, resolve)(dispatch, getState);
      expect(counter).to.eql(1);
    });
    return Promise.all([a1, a2, a3]).then(()=> {
      expect(result).to.eql([
        { url: "/test/lexich/2", opts: {} },
        { url: "/test/kitty/9", opts: {} },
        { url: "/test/admin/1", opts: { method: "post" } }
      ]);
    });
  });
  it("check global options", ()=> {
    let expOpts;
    const rest = reduxApi({
      test: {
        options: {
          headers: {
            "X-Header": 1
          }
        },
        url: "/api/test"
      }
    })
    .use("options", {
      headers: {
        Accept: "application/json"
      }
    })
    .use("fetch", (url, options)=> {
      expOpts=options;
    });
    rest.actions.test.request();
    expect(expOpts).to.eql({
      headers: {
        Accept: "application/json",
        "X-Header": 1
      }
    });
  });
  it("check global options as function", ()=> {
    let expOpts;
    const rest = reduxApi({
      test: {
        options: {
          headers: {
            "X-Header": 1
          }
        },
        url: "/api/test/(:id)"
      }
    })
    .use("options", (url, params /* , getState */)=> {
      expect(url).to.eql("/api/test/1");
      expect(params).to.eql({ a: "b" });
      return {
        headers: {
          Accept: "application/json"
        }
      };
    })
    .use("fetch", (url, options)=> {
      expOpts=options;
    });
    rest.actions.test.request({ id: 1 }, { a: "b" });
    expect(expOpts).to.eql({
      a: "b",
      headers: {
        Accept: "application/json",
        "X-Header": 1
      }
    });
  });

  it("check crud option", ()=> {
    const rest = reduxApi({
      test: { url: "/test", crud: true }
    });
    expect(rest.actions.test).to.include.keys(
      "get", "post", "delete", "put", "patch"
    );
    expect(rest.actions.test).to.include.keys(
      "request", "reset", "sync"
    );
  });
});
<commit_msg>Add: test for responseHandler option<commit_after>"use strict";

/* global describe, it, xit */
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
import { expect } from "chai";
import isFunction from "lodash/isFunction";
import size from "lodash/size";
import reduxApi from "../src/index";
import transformers from "../src/transformers";

function getState() {
  return { test: { loading: false, data: {} } };
}

describe("index", function() {
  it("check transformers", function() {
    expect(transformers.array()).to.eql([]);
    expect(transformers.array({ id: 1 })).to.eql([{ id: 1 }]);
    expect(transformers.array([1])).to.eql([1]);

    expect(transformers.object()).to.eql({});
    expect(transformers.object({ id: 1 })).to.eql({ id: 1 });
    expect(transformers.object([1])).to.eql({ data: [1] });
    expect(transformers.object("test")).to.eql({ data: "test" });
    expect(transformers.object(1)).to.eql({ data: 1 });
    expect(transformers.object(true)).to.eql({ data: true });
  });
  it("check null params", function() {
    expect(isFunction(reduxApi)).to.be.true;
    const api = reduxApi();
    expect(api.actions).to.eql({});
    expect(api.reducers).to.eql({});
  });
  it("check rootUrl", function() {
    const urls = [];
    function fetchUrl(url) {
      urls.push(url);
      return new Promise(resolve=> resolve({ msg: "hello" }));
    }
    const res = reduxApi({
      test1: "/url1/",
      test2: "url2",
      test3: "",
      test4: "/(:id)"
    })
    .use("fetch", fetchUrl)
    .use("server", false)
    .use("rootUrl", "http://api.com/root");

    const res2 = reduxApi({
      test1: "/url1/",
      test2: "url2",
      test3: "",
      test4: "/(:id)"
    })
    .use("fetch", fetchUrl)
    .use("server", false)
    .use("rootUrl", "http://api.ru/");

    const act = res.actions;
    const act2 = res2.actions;
    return Promise.all([
      act.test1.request(),
      act.test2.request(),
      act.test3.request(),
      act.test4.request({ id: 1 }),
      act2.test1.request(),
      act2.test2.request(),
      act2.test3.request(),
      act2.test4.request({ id: 2 })
    ]).then(()=> {
      expect([
        "http://api.com/root/url1/",
        "http://api.com/root/url2",
        "http://api.com/root/",
        "http://api.com/root/1",
        "http://api.ru/url1/",
        "http://api.ru/url2",
        "http://api.ru/",
        "http://api.ru/2"
      ]).to.eql(urls);
    });
  });
  it("check string url", function() {
    function fetchSuccess(url, data) {
      expect(url).to.eql("/plain/url");
      expect(data).to.eql({});
      return new Promise(function(resolve) {
        resolve({ msg: "hello" });
      });
    }
    const res = reduxApi({
      test: "/plain/url"
    })
    .use("fetch", fetchSuccess);
    expect(size(res.actions)).to.eql(1);
    expect(size(res.events)).to.eql(1);

    expect(size(res.reducers)).to.eql(1);
    expect(res.actions.test).to.exist;
    expect(res.events.test).to.have.keys(
      "actionFetch",
      "actionSuccess",
      "actionFail",
      "actionReset"
    );
    expect(res.reducers.test).to.exist;
    const expectedEvent = [
      {
        type: "@@redux-api@test",
        syncing: false,
        request: { pathvars: undefined, params: {} }
      }, {
        type: "@@redux-api@test_success",
        data: { msg: "hello" },
        origData: { msg: "hello" },
        syncing: false,
        request: { pathvars: undefined, params: {} }
      }
    ];
    return new Promise((resolve)=> {
      const action = res.actions.test(resolve);
      function dispatch(msg) {
        expect(expectedEvent).to.have.length.above(0);
        const exp = expectedEvent.shift();
        expect(msg).to.eql(exp);
      }
      action(dispatch, getState);
    }).then(()=> {
      expect(expectedEvent).to.have.length(0);
    });
  });
  it("check object url", function() {
    function fetchSuccess(url, options) {
      expect(url).to.eql("/plain/url/1");
      expect(options).to.eql({
        headers: {
          Accept: "application/json"
        }
      });
      return new Promise(function(resolve) {
        resolve({ msg: "hello" });
      });
    }
    const res = reduxApi({
      test: {
        url: "/plain/url/:id",
        options: {
          headers: {
            Accept: "application/json"
          }
        }
      }
    }).use("fetch", fetchSuccess);
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.exist;

    const expectedEvent = [{
      type: "@@redux-api@test",
      syncing: false,
      request: { pathvars: { id: 1 }, params: {} }
    }, {
      type: "@@redux-api@test_success",
      data: { msg: "hello" },
      origData: { msg: "hello" },
      syncing: false,
      request: { pathvars: { id: 1 }, params: {} }
    }];
    return new Promise((resolve)=> {
      const action = res.actions.test({ id: 1 }, resolve);
      function dispatch(msg) {
        expect(expectedEvent).to.have.length.above(0);
        const exp = expectedEvent.shift();
        expect(msg).to.eql(exp);
      }
      action(dispatch, getState);
    }).then(()=> {
      expect(expectedEvent).to.have.length(0);
    });
  });
  it("use provided reducerName when avaliable", function() {
    const res = reduxApi({
      test: {
        reducerName: "foo",
        url: "/plain/url/:id",
        options: {
          headers: {
            Accept: "application/json"
          }
        }
      }
    }).use("fetch", function fetchSuccess() {});
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.not.exist;
    expect(res.reducers.foo).to.exist;
  });

  xit("check virtual option with broadcast", function() {
    const BROADCAST_ACTION = "BROADCAST_ACTION";
    const res = reduxApi({
      test: {
        url: "/api",
        broadcast: [BROADCAST_ACTION],
        virtual: true
      }
    }).use("fetch", function fetchSuccess() {});
    expect(res.actions.test).to.exist;
    expect(res.reducers.test).to.not.exist;
  });

  it("check prefetch options", function() {
    const expectUrls = [];
    function fetchSuccess(url) {
      expectUrls.push(url);
      return new Promise(resolve=> resolve({ url }));
    }
    const res = reduxApi({
      test: "/test",
      test1: {
        url: "/test1",
        prefetch: [
          function(opts, cb) {
            opts.actions.test(cb)(
              opts.dispatch, opts.getState
            );
          }
        ]
      }
    }).use("fetch", fetchSuccess);
    return new Promise((resolve)=> {
      const action = res.actions.test1(resolve);
      action(function() {}, getState);
    }).then(()=> {
      expect(expectUrls).to.eql([
        "/test", "/test1"
      ]);
    });
  });

  it("check helpers", function() {
    const result = [];
    function getState() {
      return {
        params: { id: 9, name: "kitty" },
        hello: { loading: false, data: {} }
      };
    }
    function dispatch() {}
    const res = reduxApi({
      hello: {
        url: "/test/:name/:id",
        helpers: {
          test1(id, name) {
            return [{ id, name }];
          },
          test2() {
            const { id, name } = this.getState().params;
            return [{ id, name }];
          },
          testSync: {
            sync: true,
            call(id) {
              return [{ id, name: "admin" }, { method: "post" }];
            }
          }
        }
      }
    }).use("fetch", function(url, opts) {
      result.push({ url, opts });
      return new Promise(
        resolve=> resolve({ hello: "world" }));
    });
    const a1 = new Promise((resolve)=> {
      res.actions.hello.test1(2, "lexich", resolve)(dispatch, getState);
    });
    const a2 = new Promise((resolve)=> {
      res.actions.hello.test2(resolve)(dispatch, getState);
    });
    const a3 = new Promise((resolve)=> {
      const mockSync = res.actions.hello.sync;
      let counter = 0;
      res.actions.hello.sync = function(...args) {
        counter += 1;
        return mockSync.apply(this, args);
      };
      res.actions.hello.testSync(1, resolve)(dispatch, getState);
      expect(counter).to.eql(1);
    });
    return Promise.all([a1, a2, a3]).then(()=> {
      expect(result).to.eql([
        { url: "/test/lexich/2", opts: {} },
        { url: "/test/kitty/9", opts: {} },
        { url: "/test/admin/1", opts: { method: "post" } }
      ]);
    });
  });
  it("check global options", ()=> {
    let expOpts;
    const rest = reduxApi({
      test: {
        options: {
          headers: {
            "X-Header": 1
          }
        },
        url: "/api/test"
      }
    })
    .use("options", {
      headers: {
        Accept: "application/json"
      }
    })
    .use("fetch", (url, options)=> {
      expOpts=options;
    });
    rest.actions.test.request();
    expect(expOpts).to.eql({
      headers: {
        Accept: "application/json",
        "X-Header": 1
      }
    });
  });
  it("check global options as function", ()=> {
    let expOpts;
    const rest = reduxApi({
      test: {
        options: {
          headers: {
            "X-Header": 1
          }
        },
        url: "/api/test/(:id)"
      }
    })
    .use("options", (url, params /* , getState */)=> {
      expect(url).to.eql("/api/test/1");
      expect(params).to.eql({ a: "b" });
      return {
        headers: {
          Accept: "application/json"
        }
      };
    })
    .use("fetch", (url, options)=> {
      expOpts=options;
    });
    rest.actions.test.request({ id: 1 }, { a: "b" });
    expect(expOpts).to.eql({
      a: "b",
      headers: {
        Accept: "application/json",
        "X-Header": 1
      }
    });
  });

  it("check crud option", ()=> {
    const rest = reduxApi({
      test: { url: "/test", crud: true }
    });
    expect(rest.actions.test).to.include.keys(
      "get", "post", "delete", "put", "patch"
    );
    expect(rest.actions.test).to.include.keys(
      "request", "reset", "sync"
    );
  });

  it("check responseHandler option", ()=> {
    let called = false;
    function fetchSuccess() {
      return new Promise(resolve=> resolve({ msg: "hello" }));
    }
    const res = reduxApi({
      hello: "/test/",
    })
    .use("fetch", fetchSuccess)
    .use("responseHandler", ()=> {
      called = true;
    });
    return res.actions.hello.request().then(()=> {
      expect(called).to.true;
    });
  });
});
<|endoftext|>


<commit_before>/* eslint-env jest */

import parseIP from "../src/ipv46";

describe("IPv4", () => {
    describe("sorting", () => {
        it("considers addresses equal to themselves", () => {
            const a = parseIP("1.2.3.4");
            expect(a.cmp(a)).toBe(0);

            const b = parseIP("1.2.3.4");
            expect(a.cmp(b)).toBe(0);
            expect(b.cmp(a)).toBe(0);
        });

        it("is not lexical", () => {
            const a = parseIP("9.0.0.0");
            const b = parseIP("10.0.0.0");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });

        it("considers 127.255.255.255 less than 128.0.0.0", () => {
            const a = parseIP("127.255.255.255");
            const b = parseIP("128.0.0.0");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });
    });

    describe("parser", () => {
        it("requires numbers and .", () => {
            expect(parseIP("x.y.z.0")).toBeNull();
        });
        it("disallows leading zeroes", () => {
            expect(parseIP("01.02.03.04")).toBeNull();
            expect(parseIP("001.002.003.004")).toBeNull();
        });
        it("disallows numbers larger than 255", () => {
            expect(parseIP("0.0.0.256")).toBeNull();
        });
        it("disallows numbers less than 0", () => {
            expect(parseIP("0.0.0.-1")).toBeNull();
        });
        it("disallows too many octets", () => {
            expect(parseIP("1.2.3.4.5")).toBeNull();
        });
        it("disallows too few octets", () => {
            expect(parseIP("1.2.3")).toBeNull();
        });
        it("disallows leading whitespace", () => {
            expect(parseIP(" 0.0.0.0")).toBeNull();
        });
        it("disallows trailing whitespace", () => {
            expect(parseIP("0.0.0.0 ")).toBeNull();
        });
        it("disallows inner whitespace after octets", () => {
            expect(parseIP("0.0.0 .0")).toBeNull();
        });
        it("disallows inner whitespace before octets", () => {
            expect(parseIP("0.0. 0.0")).toBeNull();
        });
    });

    describe("formatting", () => {
        it("produces the parsed value", () => {
            expect(String(parseIP("127.0.0.1"))).toBe("127.0.0.1");
        });
    });
});

describe("IPv6", () => {
    describe("sorting", () => {
        it("considers addresses equal to themselves", () => {
            const a = parseIP("1:2:3:4:5:6:7:8");
            expect(a.cmp(a)).toBe(0);

            const b = parseIP("1:2:3:4:5:6:7:8");
            expect(a.cmp(b)).toBe(0);
            expect(b.cmp(a)).toBe(0);
        });

        it("is not lexical", () => {
            const a = parseIP("9::");
            const b = parseIP("10::");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });

        it("is case-insensitive", () => {
            const a = parseIP("A::");
            const b = parseIP("a::");
            expect(a.cmp(b)).toBe(0);
        });
    });

    describe("parser", () => {
        it("disallows non-hexadecimal characters", () => {
            expect(parseIP("x:y:z:0:1:2:3:4")).toBeNull();
        });
        it("disallows a single colon", () => {
            expect(parseIP(":")).toBeNull();
        });
        it("disallows a triple colon", () => {
            expect(parseIP(":::")).toBeNull();
        });
        it("disallows leading whitespace", () => {
            expect(parseIP(" 1:2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows trailing whitespace", () => {
            expect(parseIP("1:2:3:4:5:6:7:8 ")).toBeNull();
        });
        it("disallows inner whitespace after words", () => {
            expect(parseIP("1 :2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows inner whitespace before words", () => {
            expect(parseIP("1: 2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows inner whitespace between colons", () => {
            expect(parseIP(": :")).toBeNull();
        });
        it("allows max. 8 words", () => {
            expect(parseIP("0:1:2:3:4:5:6:7:8")).toBeNull();
        });
        it("requires 8 words when there is no ::", () => {
            expect(parseIP("1:2:3:4:5:6:7")).toBeNull();
        });
        it("counts :: as at least one word", () => {
            expect(parseIP("1:2:3:4::5:6:7:8")).toBeNull();
        });
        it("allows only one ::", () => {
            expect(parseIP("1::4::8")).toBeNull();
        });
        it("allows leading zeroes", () => {
            const a = parseIP("0000:0001:0002:0003:0004:0005:0006:0007");
            const b = parseIP("0:1:2:3:4:5:6:7");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows max. 4 characters per word", () => {
            expect(parseIP("00000:1:2:3:4:5:6:7")).toBeNull();
            expect(parseIP("0:00001:2:3:4:5:6:7")).toBeNull();
        });
        it("requires at least one character per word", () => {
            expect(parseIP(":1:2:3:4:5:6:7")).toBeNull();
        });
        it("doesn't require :: to replace the longest run of zeroes", () => {
            const a = parseIP("1:0:0:3:4:0:0:0");
            const b = parseIP("1::3:4:0:0:0");
            expect(a.cmp(b)).toBe(0);
        });
        it("doesn't require :: to replace the leftmost run of zeroes", () => {
            const a = parseIP("1:0:0:0:4:0:0:0");
            const b = parseIP("1:0:0:0:4::");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows replacing all words with ::", () => {
            const a = parseIP("0:0:0:0:0:0:0:0");
            const b = parseIP("::");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows mixing zero words and and ::", () => {
            const a = parseIP("0:0:0:0:0:0:0:0");
            const b = parseIP("0::0");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows replacing just one zero word with ::", () => {
            const a = parseIP("1::3:4:5:6:7:8");
            const b = parseIP("1:0:3:4:5:6:7:8");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after prefix 0:0:0:0:0:0", () => {
            const a = parseIP("::192.0.2.1");
            const b = parseIP("::c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after prefix 0:0:0:0:0:ffff", () => {
            const a = parseIP("::ffff:192.0.2.1");
            const b = parseIP("::ffff:c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after any 96-bit prefix", () => {
            const a = parseIP("2001:db8::192.0.2.1");
            const b = parseIP("2001:db8::c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("doesn't interpret a single trailing number between 0-255 as an octet", () => {
            const a = parseIP("2001:db8::1ff");
            const b = parseIP("2001:db8::255");
            expect(a.cmp(b)).toBe(-1);
        });
        it("requires embedded IPv4 addresses to be well-formed", () => {
            expect(parseIP("2001:db8::192.0.2.256")).toBeNull();
            expect(parseIP("2001:db8::192.0.2.1.0")).toBeNull();
            expect(parseIP("2001:db8::192.0.2")).toBeNull();
            expect(parseIP("2001:db8::192.0")).toBeNull();
            expect(parseIP("2001:db8::192.0.2.")).toBeNull();
            expect(parseIP("2001:db8::.0.2.1")).toBeNull();
        });
        it("counts embedded IPv4 address as 2 words", () => {
            expect(parseIP("1:2:3:4:5:6:7:8:192.0.2.1")).toBeNull();
            expect(parseIP("1:2:3:4:5:6:7:192.0.2.1")).toBeNull();
        });
        it("disallows non-trailing IPv4 addresses", () => {
            expect(parseIP("192.0.2.1::")).toBeNull();
            expect(parseIP("0:192.0.2.1::")).toBeNull();
            expect(parseIP("0:0:192.0.2.1::")).toBeNull();
            expect(parseIP("::192.0.2.1:0:0:0")).toBeNull();
            expect(parseIP("::192.0.2.1:0:0")).toBeNull();
            expect(parseIP("::192.0.2.1:0")).toBeNull();
        });
    });

    describe("formatting", () => {
        it("doesn't output leading zeroes", () => {
            expect(String(parseIP("0001:0002:0003:0004:0005:0006:0007:0008"))).toBe("1:2:3:4:5:6:7:8");
        });
        it("doesn't output :: when there are no two or more consecutive zero words", () => {
            expect(String(parseIP("1:2:3:0:5:6:7:8"))).toBe("1:2:3:0:5:6:7:8");
        });
        it("collapses 2-8 zeroes", () => {
            expect(String(parseIP("1:2:3:0:0:6:7:8"))).toBe("1:2:3::6:7:8");
            expect(String(parseIP("1:2:3:0:0:0:7:8"))).toBe("1:2:3::7:8");
            expect(String(parseIP("1:2:0:0:0:0:7:8"))).toBe("1:2::7:8");
            expect(String(parseIP("1:2:0:0:0:0:0:8"))).toBe("1:2::8");
            expect(String(parseIP("1:0:0:0:0:0:0:8"))).toBe("1::8");
            expect(String(parseIP("0:0:0:0:0:0:0:8"))).toBe("::8");
            expect(String(parseIP("0:0:0:0:0:0:0:0"))).toBe("::");
        });
        it("collapses zeroes even from the beginning", () => {
            expect(String(parseIP("0:0:3:4:5:6:7:8"))).toBe("::3:4:5:6:7:8");
        });
        it("collapses zeroes even from the end", () => {
            expect(String(parseIP("1:2:3:4:5:6:0:0"))).toBe("1:2:3:4:5:6::");
        });
        it("collapses the longest run of zeroes", () => {
            expect(String(parseIP("1:0:0:4:5:0:0:0"))).toBe("1:0:0:4:5::");
        });
        it("collapses the leftmost longest run of zeroes", () => {
            expect(String(parseIP("1:0:0:0:5:0:0:0"))).toBe("1::5:0:0:0");
        });
        it("always outputs lower-case", () => {
            expect(String(parseIP("abcd:ef00::"))).toBe("abcd:ef00::");
            expect(String(parseIP("ABCD:EF00::"))).toBe("abcd:ef00::");
        });
    });
});

describe("parsing", () => {
    it("disallows empty strings", () => {
        expect(parseIP("")).toBeNull();
    });
    it("disallows values with no . or :", () => {
        expect(parseIP("Hello, World!")).toBeNull();
    });
});

describe("sorting", () => {
    it("considers all IPv4 addresses less than any IPv6 address", () => {
        const a = parseIP("255.255.255.255");
        const b = parseIP("::");
        expect(a.cmp(b)).toBe(-1);
        expect(b.cmp(a)).toBe(1);
    });
});
<commit_msg>Add formatting tests<commit_after>/* eslint-env jest */

import parseIP from "../src/ipv46";

describe("IPv4", () => {
    describe("sorting", () => {
        it("considers addresses equal to themselves", () => {
            const a = parseIP("1.2.3.4");
            expect(a.cmp(a)).toBe(0);

            const b = parseIP("1.2.3.4");
            expect(a.cmp(b)).toBe(0);
            expect(b.cmp(a)).toBe(0);
        });

        it("is not lexical", () => {
            const a = parseIP("9.0.0.0");
            const b = parseIP("10.0.0.0");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });

        it("considers 127.255.255.255 less than 128.0.0.0", () => {
            const a = parseIP("127.255.255.255");
            const b = parseIP("128.0.0.0");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });
    });

    describe("parser", () => {
        it("requires numbers and .", () => {
            expect(parseIP("x.y.z.0")).toBeNull();
        });
        it("disallows leading zeroes", () => {
            expect(parseIP("01.02.03.04")).toBeNull();
            expect(parseIP("001.002.003.004")).toBeNull();
        });
        it("disallows numbers larger than 255", () => {
            expect(parseIP("0.0.0.256")).toBeNull();
        });
        it("disallows numbers less than 0", () => {
            expect(parseIP("0.0.0.-1")).toBeNull();
        });
        it("disallows too many octets", () => {
            expect(parseIP("1.2.3.4.5")).toBeNull();
        });
        it("disallows too few octets", () => {
            expect(parseIP("1.2.3")).toBeNull();
        });
        it("disallows leading whitespace", () => {
            expect(parseIP(" 0.0.0.0")).toBeNull();
        });
        it("disallows trailing whitespace", () => {
            expect(parseIP("0.0.0.0 ")).toBeNull();
        });
        it("disallows inner whitespace after octets", () => {
            expect(parseIP("0.0.0 .0")).toBeNull();
        });
        it("disallows inner whitespace before octets", () => {
            expect(parseIP("0.0. 0.0")).toBeNull();
        });
    });

    describe("formatting", () => {
        it("produces the parsed value", () => {
            expect(String(parseIP("127.0.0.1"))).toBe("127.0.0.1");
        });
    });
});

describe("IPv6", () => {
    describe("sorting", () => {
        it("considers addresses equal to themselves", () => {
            const a = parseIP("1:2:3:4:5:6:7:8");
            expect(a.cmp(a)).toBe(0);

            const b = parseIP("1:2:3:4:5:6:7:8");
            expect(a.cmp(b)).toBe(0);
            expect(b.cmp(a)).toBe(0);
        });

        it("is not lexical", () => {
            const a = parseIP("9::");
            const b = parseIP("10::");
            expect(a.cmp(b)).toBe(-1);
            expect(b.cmp(a)).toBe(1);
        });

        it("is case-insensitive", () => {
            const a = parseIP("A::");
            const b = parseIP("a::");
            expect(a.cmp(b)).toBe(0);
        });
    });

    describe("parser", () => {
        it("disallows non-hexadecimal characters", () => {
            expect(parseIP("x:y:z:0:1:2:3:4")).toBeNull();
        });
        it("disallows a single colon", () => {
            expect(parseIP(":")).toBeNull();
        });
        it("disallows a triple colon", () => {
            expect(parseIP(":::")).toBeNull();
        });
        it("disallows leading whitespace", () => {
            expect(parseIP(" 1:2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows trailing whitespace", () => {
            expect(parseIP("1:2:3:4:5:6:7:8 ")).toBeNull();
        });
        it("disallows inner whitespace after words", () => {
            expect(parseIP("1 :2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows inner whitespace before words", () => {
            expect(parseIP("1: 2:3:4:5:6:7:8")).toBeNull();
        });
        it("disallows inner whitespace between colons", () => {
            expect(parseIP(": :")).toBeNull();
        });
        it("allows max. 8 words", () => {
            expect(parseIP("0:1:2:3:4:5:6:7:8")).toBeNull();
        });
        it("requires 8 words when there is no ::", () => {
            expect(parseIP("1:2:3:4:5:6:7")).toBeNull();
        });
        it("counts :: as at least one word", () => {
            expect(parseIP("1:2:3:4::5:6:7:8")).toBeNull();
        });
        it("allows only one ::", () => {
            expect(parseIP("1::4::8")).toBeNull();
        });
        it("allows leading zeroes", () => {
            const a = parseIP("0000:0001:0002:0003:0004:0005:0006:0007");
            const b = parseIP("0:1:2:3:4:5:6:7");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows max. 4 characters per word", () => {
            expect(parseIP("00000:1:2:3:4:5:6:7")).toBeNull();
            expect(parseIP("0:00001:2:3:4:5:6:7")).toBeNull();
        });
        it("requires at least one character per word", () => {
            expect(parseIP(":1:2:3:4:5:6:7")).toBeNull();
        });
        it("doesn't require :: to replace the longest run of zeroes", () => {
            const a = parseIP("1:0:0:3:4:0:0:0");
            const b = parseIP("1::3:4:0:0:0");
            expect(a.cmp(b)).toBe(0);
        });
        it("doesn't require :: to replace the leftmost run of zeroes", () => {
            const a = parseIP("1:0:0:0:4:0:0:0");
            const b = parseIP("1:0:0:0:4::");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows replacing all words with ::", () => {
            const a = parseIP("0:0:0:0:0:0:0:0");
            const b = parseIP("::");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows mixing zero words and and ::", () => {
            const a = parseIP("0:0:0:0:0:0:0:0");
            const b = parseIP("0::0");
            expect(a.cmp(b)).toBe(0);
        });
        it("allows replacing just one zero word with ::", () => {
            const a = parseIP("1::3:4:5:6:7:8");
            const b = parseIP("1:0:3:4:5:6:7:8");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after prefix 0:0:0:0:0:0", () => {
            const a = parseIP("::192.0.2.1");
            const b = parseIP("::c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after prefix 0:0:0:0:0:ffff", () => {
            const a = parseIP("::ffff:192.0.2.1");
            const b = parseIP("::ffff:c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("accepts embedded IPv4 addresses after any 96-bit prefix", () => {
            const a = parseIP("2001:db8::192.0.2.1");
            const b = parseIP("2001:db8::c000:201");
            expect(a.cmp(b)).toBe(0);
        });
        it("doesn't interpret a single trailing number between 0-255 as an octet", () => {
            const a = parseIP("2001:db8::1ff");
            const b = parseIP("2001:db8::255");
            expect(a.cmp(b)).toBe(-1);
        });
        it("requires embedded IPv4 addresses to be well-formed", () => {
            expect(parseIP("2001:db8::192.0.2.256")).toBeNull();
            expect(parseIP("2001:db8::192.0.2.1.0")).toBeNull();
            expect(parseIP("2001:db8::192.0.2")).toBeNull();
            expect(parseIP("2001:db8::192.0")).toBeNull();
            expect(parseIP("2001:db8::192.0.2.")).toBeNull();
            expect(parseIP("2001:db8::.0.2.1")).toBeNull();
        });
        it("counts embedded IPv4 address as 2 words", () => {
            expect(parseIP("1:2:3:4:5:6:7:8:192.0.2.1")).toBeNull();
            expect(parseIP("1:2:3:4:5:6:7:192.0.2.1")).toBeNull();
        });
        it("disallows non-trailing IPv4 addresses", () => {
            expect(parseIP("192.0.2.1::")).toBeNull();
            expect(parseIP("0:192.0.2.1::")).toBeNull();
            expect(parseIP("0:0:192.0.2.1::")).toBeNull();
            expect(parseIP("::192.0.2.1:0:0:0")).toBeNull();
            expect(parseIP("::192.0.2.1:0:0")).toBeNull();
            expect(parseIP("::192.0.2.1:0")).toBeNull();
        });
    });

    describe("formatting", () => {
        it("doesn't output leading zeroes", () => {
            expect(String(parseIP("0001:0002:0003:0004:0005:0006:0007:0008"))).toBe("1:2:3:4:5:6:7:8");
        });
        it("doesn't output :: when there are no two or more consecutive zero words", () => {
            expect(String(parseIP("1:2:3:0:5:6:7:8"))).toBe("1:2:3:0:5:6:7:8");
        });
        it("collapses 2-8 zeroes", () => {
            expect(String(parseIP("1:2:3:0:0:6:7:8"))).toBe("1:2:3::6:7:8");
            expect(String(parseIP("1:2:3:0:0:0:7:8"))).toBe("1:2:3::7:8");
            expect(String(parseIP("1:2:0:0:0:0:7:8"))).toBe("1:2::7:8");
            expect(String(parseIP("1:2:0:0:0:0:0:8"))).toBe("1:2::8");
            expect(String(parseIP("1:0:0:0:0:0:0:8"))).toBe("1::8");
            expect(String(parseIP("0:0:0:0:0:0:0:8"))).toBe("::8");
            expect(String(parseIP("0:0:0:0:0:0:0:0"))).toBe("::");
        });
        it("collapses zeroes even from the beginning", () => {
            expect(String(parseIP("0:0:3:4:5:6:7:8"))).toBe("::3:4:5:6:7:8");
        });
        it("collapses zeroes even from the end", () => {
            expect(String(parseIP("1:2:3:4:5:6:0:0"))).toBe("1:2:3:4:5:6::");
        });
        it("collapses the longest run of zeroes", () => {
            expect(String(parseIP("1:0:0:4:5:0:0:0"))).toBe("1:0:0:4:5::");
        });
        it("collapses the leftmost longest run of zeroes", () => {
            expect(String(parseIP("1:0:0:0:5:0:0:0"))).toBe("1::5:0:0:0");
        });
        it("always outputs lower-case", () => {
            expect(String(parseIP("abcd:ef00::"))).toBe("abcd:ef00::");
            expect(String(parseIP("ABCD:EF00::"))).toBe("abcd:ef00::");
        });
        it("doesn't output embedded IPv4 addresses", () => {
            expect(String(parseIP("::192.0.2.1"))).toBe("::c000:201");
            expect(String(parseIP("::ffff:192.0.2.1"))).toBe("::ffff:c000:201");
            expect(String(parseIP("2001:db8::192.0.2.1"))).toBe("2001:db8::c000:201");
        });
    });
});

describe("parsing", () => {
    it("disallows empty strings", () => {
        expect(parseIP("")).toBeNull();
    });
    it("disallows values with no . or :", () => {
        expect(parseIP("Hello, World!")).toBeNull();
    });
});

describe("sorting", () => {
    it("considers all IPv4 addresses less than any IPv6 address", () => {
        const a = parseIP("255.255.255.255");
        const b = parseIP("::");
        expect(a.cmp(b)).toBe(-1);
        expect(b.cmp(a)).toBe(1);
    });
});
<|endoftext|>


<commit_before>module.exports = function(config){
  config.set({

    basePath : '../',

    files : [
      'ext/angular.js',
      'ext/angular-mocks.js',
      'testables/testApp.js',
      'src/*.js',
      'test/unit/**/*.js'
    ],

// preprocessors: {
//   'src/*.js': ['coverage']
// },

    coverageReporter: {
      type : 'html',
      dir : 'coverage/'
    },

    autoWatch : true,

    reporters: ['progress', 'coverage'],

    logLevel: config.LOG_DEBUG,

    browsers: ['Chrome'],

    frameworks: ['jasmine'],

    captureTimeout: 60000,

    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }

  });
};
<commit_msg>tests now run on phantomjs<commit_after>module.exports = function(config){
  config.set({

    basePath : '../',

    files : [
      'ext/angular.js',
      'ext/angular-mocks.js',
      'testables/testApp.js',
      'src/*.js',
      'test/unit/**/*.js'
    ],

// preprocessors: {
//   'src/*.js': ['coverage']
// },

    coverageReporter: {
      type : 'html',
      dir : 'coverage/'
    },

    autoWatch : true,

    reporters: ['progress', 'coverage'],

    logLevel: config.LOG_DEBUG,

    //browsers: ['Chrome'],
    browsers: ['PhantomJS'],

    frameworks: ['jasmine'],

    captureTimeout: 60000,

    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }

  });
};
<|endoftext|>


<commit_before>const config = {
  browsers: ["ChromeHeadless"],
  frameworks: ["qunit"],
  files: [
    { pattern: "dist/trix.js", watched: false },
    { pattern: "dist/test.js", watched: false },
    { pattern: "src/test_helpers/fixtures/*.png", watched: false, included: false, served: true }
  ],
  proxies: {
    "/test_helpers/fixtures/": "/base/src/test_helpers/fixtures/"
  },
  client: {
    clearContext: false,
    qunit: {
      showUI: true
    }
  },

  singleRun: true,
  autoWatch: false,

  captureTimeout: 240000,
  browserDisconnectTimeout: 240000,
  browserDisconnectTolerance: 3,
  browserNoActivityTimeout: 300000,
}

if (process.env.CI) {
  config.customLaunchers = {
    sl_chrome_latest: {
      base: "SauceLabs",
      browserName: "chrome",
      version: "71"
    },
    sl_firefox_latest: {
      base: "SauceLabs",
      browserName: "firefox",
      version: "64"
    },
    sl_safari_previous: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "macOS 10.12",
      version: "11.0"
    },
    sl_safari_latest: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "macOS 10.13",
      version: "12.0"
    },
    sl_edge_previous: {
      base: "SauceLabs",
      browserName: "microsoftedge",
      platform: "Windows 10",
      version: "17.17134"
    },
    sl_edge_latest: {
      base: "SauceLabs",
      browserName: "microsoftedge",
      platform: "Windows 10",
      version: "18.17763"
    },
    sl_ie_11: {
      base: "SauceLabs",
      browserName: "internet explorer",
      platform: "Windows 8.1",
      version: "11"
    },
    sl_ios_previous: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "ios",
      device: "iPhone Simulator",
      version: "11.3"
    },
    sl_ios_latest: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "ios",
      device: "iPhone Simulator",
      version: "12.0"
    },
    sl_android_previous: {
      base: "SauceLabs",
      browserName: "chrome",
      platform: "android",
      device: "Android Emulator",
      version: "6.0"
    },
    sl_android_latest: {
      base: "SauceLabs",
      browserName: "chrome",
      platform: "android",
      device: "Android GoogleAPI Emulator",
      version: "7.1"
    }
  }

  config.browsers = Object.keys(config.customLaunchers)
  config.reporters = ["dots", "saucelabs"]

  config.sauceLabs = {
    testName: "Trix",
    retryLimit: 3,
    idleTimeout: 600,
    commandTimeout: 600,
    maxDuration: 900,
    build: buildId(),
  }

  function buildId() {
    const { TRAVIS_BUILD_NUMBER, TRAVIS_BUILD_ID } = process.env
    return TRAVIS_BUILD_NUMBER && TRAVIS_BUILD_ID
      ? `TRAVIS #${TRAVIS_BUILD_NUMBER} (${TRAVIS_BUILD_ID})`
      : ""
  }
}

module.exports = function(karmaConfig) {
  karmaConfig.set(config)
}
<commit_msg>CI: Freshen browser list<commit_after>const config = {
  browsers: ["ChromeHeadless"],
  frameworks: ["qunit"],
  files: [
    { pattern: "dist/trix.js", watched: false },
    { pattern: "dist/test.js", watched: false },
    { pattern: "src/test_helpers/fixtures/*.png", watched: false, included: false, served: true }
  ],
  proxies: {
    "/test_helpers/fixtures/": "/base/src/test_helpers/fixtures/"
  },
  client: {
    clearContext: false,
    qunit: {
      showUI: true
    }
  },

  singleRun: true,
  autoWatch: false,

  captureTimeout: 240000,
  browserDisconnectTimeout: 240000,
  browserDisconnectTolerance: 3,
  browserNoActivityTimeout: 300000,
}

if (process.env.CI) {
  config.customLaunchers = {
    sl_chrome_latest: {
      base: "SauceLabs",
      browserName: "chrome",
      version: "75"
    },
    sl_firefox_latest: {
      base: "SauceLabs",
      browserName: "firefox",
      version: "68"
    },
    sl_safari_previous: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "macOS 10.12",
      version: "11.0"
    },
    sl_safari_latest: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "macOS 10.13",
      version: "12.1"
    },
    sl_edge_previous: {
      base: "SauceLabs",
      browserName: "microsoftedge",
      platform: "Windows 10",
      version: "17.17134"
    },
    sl_edge_latest: {
      base: "SauceLabs",
      browserName: "microsoftedge",
      platform: "Windows 10",
      version: "18.17763"
    },
    sl_ie_11: {
      base: "SauceLabs",
      browserName: "internet explorer",
      platform: "Windows 8.1",
      version: "11"
    },
    sl_ios_previous: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "ios",
      device: "iPhone Simulator",
      version: "11.3"
    },
    sl_ios_latest: {
      base: "SauceLabs",
      browserName: "safari",
      platform: "ios",
      device: "iPhone Simulator",
      version: "12.2"
    },
    sl_android_previous: {
      base: "SauceLabs",
      browserName: "chrome",
      platform: "android",
      device: "Android GoogleAPI Emulator",
      version: "7.1"
    },
    sl_android_latest: {
      base: "SauceLabs",
      browserName: "chrome",
      platform: "android",
      device: "Android GoogleAPI Emulator",
      version: "8.1"
    }
  }

  config.browsers = Object.keys(config.customLaunchers)
  config.reporters = ["dots", "saucelabs"]

  config.sauceLabs = {
    testName: "Trix",
    retryLimit: 3,
    idleTimeout: 600,
    commandTimeout: 600,
    maxDuration: 900,
    build: buildId(),
  }

  function buildId() {
    const { TRAVIS_BUILD_NUMBER, TRAVIS_BUILD_ID } = process.env
    return TRAVIS_BUILD_NUMBER && TRAVIS_BUILD_ID
      ? `TRAVIS #${TRAVIS_BUILD_NUMBER} (${TRAVIS_BUILD_ID})`
      : ""
  }
}

module.exports = function(karmaConfig) {
  karmaConfig.set(config)
}
<|endoftext|>


<commit_before>import assert from 'assert'
import { eq, neq, oeq, oneq, mock } from './helpers'
import * as u from '../src/utils'
//import MatchRewired from '../src/match'
import { prefixSpec, spec, check, assignValues } from '../src/spec'
import { toggle, toggleSelected, match } from '../src/match'

//const matcher = MatchRewired.__GetDependency__('matcher')

function testToggle(match, id) {
let testOn = t => {
  assert(t.match())
  eq(t, match)
  eq(t.key, id)
}

let testOff = t => {
  assert(!t.match())
  eq(t.off, match)
  eq(t.key, id)
}
return { on: testOn, off: testOff }
}

describe('match: toggle', function() {
  it('toggle', function() {
    let match = { match: mock(true), resolve: mock() }
    let test = testToggle(match, 'x')
    let t = toggle('x', match)
    test.off(t)
    t = toggle('y', t)
    test.on(t)
    t = toggle('', t)
    test.off(t)
  })
  it('toggleSelected', function() {
    let m1 = { key: '', match: mock(true), resolve: mock() }
    let m2 = { key: 'y', match: mock(true), resolve: mock() }
    let m3 = { key: 'x', match: mock(true), resolve: mock() }
    let matchers = toggleSelected([m1,m2,m3], 'x')
    eq(matchers[0], m1)
    eq(matchers[1], m2)
    testToggle(m3, 'x').off(matchers[2])
  })
})

describe.only('match', function() {
  it('basic', function() {
    let next = mock(), err = mock()
    let matcher = match(spec('/a')(next, err))
    let run = u.pipe(matcher.match, matcher.resolve)
    run({href: '/a'})
    eq(next.mock.calls.length, 1)
    let res = next.mock.calls[0][0]['/a']
    assert(res.exact)
    run({href: '/a/b'})
    eq(err.mock.calls.length, 1)
    res = err.mock.calls[0][0]['/a']
    assert(res.passed)
    assert(!res.exact)
    eq(res.match, '/a')
  })
})<commit_msg>match test spec with check<commit_after>import assert from 'assert'
import { eq, neq, oeq, oneq, mock } from './helpers'
import * as u from '../src/utils'
//import MatchRewired from '../src/match'
import { prefixSpec, spec, check, assignValues } from '../src/spec'
import { toggle, toggleSelected, match } from '../src/match'

//const matcher = MatchRewired.__GetDependency__('matcher')

function testToggle(match, id) {
let testOn = t => {
  assert(t.match())
  eq(t, match)
  eq(t.key, id)
}

let testOff = t => {
  assert(!t.match())
  eq(t.off, match)
  eq(t.key, id)
}
return { on: testOn, off: testOff }
}

describe('match: toggle', function() {
  it('toggle', function() {
    let match = { match: mock(true), resolve: mock() }
    let test = testToggle(match, 'x')
    let t = toggle('x', match)
    test.off(t)
    t = toggle('y', t)
    test.on(t)
    t = toggle('', t)
    test.off(t)
  })
  it('toggleSelected', function() {
    let m1 = { key: '', match: mock(true), resolve: mock() }
    let m2 = { key: 'y', match: mock(true), resolve: mock() }
    let m3 = { key: 'x', match: mock(true), resolve: mock() }
    let matchers = toggleSelected([m1,m2,m3], 'x')
    eq(matchers[0], m1)
    eq(matchers[1], m2)
    testToggle(m3, 'x').off(matchers[2])
  })
})

describe.only('match', function() {
  let next, err
  beforeEach(function() {
    next = mock()
    err = mock()
  })
  it('specs', function() {
    let matcher = match(spec('/a')(next, err))
    let run = u.pipe(matcher.match, matcher.resolve)
    run({href: '/a'})
    eq(next.mock.calls.length, 1)
    let res = next.mock.calls[0][0]['/a']
    assert(res.exact)
    run({href: '/a/b'})
    eq(err.mock.calls.length, 1)
    res = err.mock.calls[0][0]['/a']
    assert(res.passed)
    assert(!res.exact)
    eq(res.match, '/a')
  })
  it.only('specs+checks', function() {
    let specs = [spec('/abc', '/abc/:x')(next, err), spec('/xyz', '/xyz/:x/:y')(next, err)]
    let checks = check(':x', ':y')(/^4/, /[2,3]$/)
    let matcher = match(specs, checks)
    let res, run = u.pipe(matcher.match, matcher.resolve)
    run({href: '/abc/42'})
    eq(next.mock.calls.length, 1)
    res = next.mock.calls[0][0]['/abc/:x']
    assert(res.exact)
    eq(res.values[0], '42')
    run({href: '/xyz/42/43'})
    eq(next.mock.calls.length, 2)
    res = next.mock.calls[1][0]['/xyz/:x/:y']
    assert(res.exact)
    oeq(res.values, ['42','43'])
    run({href: '/xyz/42/44'})
    eq(err.mock.calls.length, 1)
    assert(!err.mock.calls[0][0]['/xyz/:x/:y'])
    res = err.mock.calls[0][0]['/xyz']
    assert(res.passed)
  })
})<|endoftext|>


<commit_before>// External dependancies
var assert = require('assert'),
	should = require('should'),
	matchstick = require('../matchstick.js');

// Test the Redirect constructor
describe('Matchstick', function() {

	/* *
	 * Validation
	 */

	it('should throw an error for an unrecognized mode', function() {
		(function(){
			matchstick('pattern', 'made-up-mode');
		}).should.throw("[Matchstick] The 'mode' property must be one of strict, static, wildcard, template, colon, regexp");
	});

	it('should throw an error for a non-string pattern value', function() {
		(function(){
			matchstick([], 'strict');
		}).should.throw("[Matchstick] The 'pattern' property must be a string");
	});

	it('should throw an error for an invalid modifier character', function() {
		(function(){
			matchstick('pattern', 'static', 'x');
		}).should.throw("[Matchstick] Invalid modifier character 'x'");
	});

	it('should throw an error for a duplicate modifier character', function() {
		(function(){
			matchstick('pattern', 'static', 'gg');
		}).should.throw("[Matchstick] Invalid modifier character 'g'");
	});

	/* *
	 * RegExp property
	 */

	// Strict
	it("should return a regexp equivalent to '^\/path$' for the pattern string '/path'", function() {
		assert.equal(matchstick('/path', 'strict').regexp.toString(), new RegExp('^\\/path$').toString());
	});

	// Static (optional trailing slash)
	it("should return a regexp equivalent to '^\/path(/?)$' for the pattern string '/path'", function() {
		assert.equal(matchstick('/path', 'static').regexp.toString(), new RegExp('^\\/path(\/?)$').toString());
	});

	// Wildcard
	it("should return a regexp equivalent to '^\/path\/(.*)\/$' for the wildcard pattern '/path/*/'", function() {
		assert.equal(matchstick('/path/*/', 'wildcard').regexp.toString(), new RegExp('^\\/path\\/(.*)\\/$').toString());
	});

});<commit_msg>regexp property test for template type<commit_after>// External dependancies
var assert = require('assert'),
	should = require('should'),
	matchstick = require('../matchstick.js');

// Test the Redirect constructor
describe('Matchstick', function() {

	/* *
	 * Validation
	 */

	it('should throw an error for an unrecognized mode', function() {
		(function(){
			matchstick('pattern', 'made-up-mode');
		}).should.throw("[Matchstick] The 'mode' property must be one of strict, static, wildcard, template, colon, regexp");
	});

	it('should throw an error for a non-string pattern value', function() {
		(function(){
			matchstick([], 'strict');
		}).should.throw("[Matchstick] The 'pattern' property must be a string");
	});

	it('should throw an error for an invalid modifier character', function() {
		(function(){
			matchstick('pattern', 'static', 'x');
		}).should.throw("[Matchstick] Invalid modifier character 'x'");
	});

	it('should throw an error for a duplicate modifier character', function() {
		(function(){
			matchstick('pattern', 'static', 'gg');
		}).should.throw("[Matchstick] Invalid modifier character 'g'");
	});

	/* *
	 * RegExp property
	 */

	// Strict
	it("should return a regexp equivalent to '^\/path$' for the pattern string '/path'", function() {
		assert.equal(matchstick('/path', 'strict').regexp.toString(), new RegExp('^\\/path$').toString());
	});

	// Static (optional trailing slash)
	it("should return a regexp equivalent to '^\/path(/?)$' for the pattern string '/path'", function() {
		assert.equal(matchstick('/path', 'static').regexp.toString(), new RegExp('^\\/path(\/?)$').toString());
	});

	// Wildcard
	it("should return a regexp equivalent to '^\/path\/(.*)\/$' for the wildcard pattern '/path/*/'", function() {
		assert.equal(matchstick('/path/*/', 'wildcard').regexp.toString(), new RegExp('^\\/path\\/(.*)\\/$').toString());
	});

	// Template
	it("should return a regexp equivalent to '^\/path\/(.*)$' for the wildcard pattern '/path/{id}'", function() {
		assert.equal(matchstick('/path/{id}', 'template').regexp.toString(), new RegExp('^\\/path\\/(.*)$').toString());
	});
});<|endoftext|>


<commit_before>var Backend = require('../lib/backend');
var expect = require('expect.js');
var types = require('../lib/types');

describe('middleware', function() {

  beforeEach(function() {
    this.backend = new Backend();
  });

  describe('connect', function() {

    it('passes the agent on connect', function() {
      var clientId;
      this.backend.use('connect', function(request, next) {
        clientId = request.agent.clientId;
        next();
      });

      var connection = this.backend.connect();
      expect(connection.id).equal(null);
      connection.on('connected', function() {
        expect(connection.id).equal(clientId);
        done();
      });
    });

    it('passing an error on connect stops the client', function(done) {
      this.backend.use('connect', function(request, next) {
        next({message: 'No good'});
      });

      var connection = this.backend.connect();
      connection.on('stopped', function() {
        done();
      });
    });

  });

  describe('submit', function() {

    it('gets options passed to backend.submit', function(done) {
      this.backend.use('submit', function(request, next) {
        expect(request.options).eql({testOption: true});
        done();
      });
      var op = {create: {type: types.defaultType.uri}};
      var options = {testOption: true};
      this.backend.submit(null, 'dogs', 'fido', op, options, function(err) {
        if (err) throw err;
      });
    });

  });

});
<commit_msg>Add test for  chaining<commit_after>var Backend = require('../lib/backend');
var expect = require('expect.js');
var types = require('../lib/types');

describe('middleware', function() {

  beforeEach(function() {
    this.backend = new Backend();
  });

  describe('use', function() {

    it('returns itself to allow chaining', function() {
      var response = this.backend.use('submit', function(request, next) {});
      expect(response).equal(this.backend);
    });

  });

  describe('connect', function() {

    it('passes the agent on connect', function() {
      var clientId;
      this.backend.use('connect', function(request, next) {
        clientId = request.agent.clientId;
        next();
      });

      var connection = this.backend.connect();
      expect(connection.id).equal(null);
      connection.on('connected', function() {
        expect(connection.id).equal(clientId);
        done();
      });
    });

    it('passing an error on connect stops the client', function(done) {
      this.backend.use('connect', function(request, next) {
        next({message: 'No good'});
      });

      var connection = this.backend.connect();
      connection.on('stopped', function() {
        done();
      });
    });

  });

  describe('submit', function() {

    it('gets options passed to backend.submit', function(done) {
      this.backend.use('submit', function(request, next) {
        expect(request.options).eql({testOption: true});
        done();
      });
      var op = {create: {type: types.defaultType.uri}};
      var options = {testOption: true};
      this.backend.submit(null, 'dogs', 'fido', op, options, function(err) {
        if (err) throw err;
      });
    });

  });

});
<|endoftext|>


<commit_before>"use strict";

var assert = require("assert");
var testUtils = require("./helpers/util.js");

function promised(val) {
    return new Promise(function(f) {
        setTimeout(function() {
            f(val);
        }, 1);
    });
}

function thenabled(val, arr) {
    return {
        then: function(f){
            setTimeout(function() {
                if (arr) arr.push(val);
                f(val);
            }, 1);
        }
    };
}

describe("Promise.each", function() {

    it("should return the array's values mapped", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).mapSeries(function(val) {
            b.push(3-val);
            return val + 2;
        }).then(function(ret) {
            assert.deepEqual(ret, [3,4,5]);
            assert.deepEqual(b, [2, 1, 0]);
        });
    });

    it("takes value, index and length", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value, index, length) {
            b.push(value, index, length);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
        });
    });

    it("waits for returned promise before proceeding next", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value) {
            b.push(value);
            return Promise.delay(1).then(function(){
                b.push(value*2);
            });
        }).then(function(ret) {
            assert.deepEqual(b, [1,2,2,4,3,6]);
        });
    });

    it("waits for returned thenable before proceeding next", function() {
        var b = [1, 2, 3];
        var a = [thenabled(1), thenabled(2), thenabled(3)];
        return Promise.resolve(a).each(function(val) {
            b.push(val * 50);
            return thenabled(val * 500, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
        });
    });

    it("doesnt iterate with an empty array", function() {
        return Promise.each([], function(val) {
            throw new Error();
        }).then(function(ret) {
            assert.deepEqual(ret, []);
        });
    });

    it("iterates with an array of single item", function() {
        var b = [];
        return Promise.each([promised(1)], function(val) {
            b.push(val);
            return thenabled(val*2, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1,2]);
        });
    });
});

describe("Promise.prototype.each", function() {

    it("should return the array's values", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(val) {
            b.push(3-val);
            return val;
        }).then(function(ret) {
            assert.deepEqual(ret, [1,2,3]);
            assert.deepEqual(b, [2, 1, 0]);
        });
    });

    it("takes value, index and length", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value, index, length) {
            b.push(value, index, length);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
        });
    });

    it("waits for returned promise before proceeding next", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value) {
            b.push(value);
            return Promise.delay(1).then(function(){
                b.push(value*2);
            });
        }).then(function(ret) {
            assert.deepEqual(b, [1,2,2,4,3,6]);
        });
    });

    it("waits for returned thenable before proceeding next", function() {
        var b = [1, 2, 3];
        var a = [thenabled(1), thenabled(2), thenabled(3)];
        return Promise.resolve(a).each(function(val) {
            b.push(val * 50);
            return thenabled(val * 500, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
        });
    });

    it("doesnt iterate with an empty array", function() {
        return Promise.resolve([]).each(function(val) {
            throw new Error();
        }).then(function(ret) {
            assert.deepEqual(ret, []);
        });
    });

    it("iterates with an array of single item", function() {
        var b = [];
        return Promise.resolve([promised(1)]).each(function(val) {
            b.push(val);
            return thenabled(val*2, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1,2]);
        });
    });
});
<commit_msg>moar tests<commit_after>"use strict";

var assert = require("assert");
var testUtils = require("./helpers/util.js");

function promised(val) {
    return new Promise(function(f) {
        setTimeout(function() {
            f(val);
        }, 1);
    });
}

function thenabled(val, arr) {
    return {
        then: function(f){
            setTimeout(function() {
                if (arr) arr.push(val);
                f(val);
            }, 1);
        }
    };
}

describe("Promise.each", function() {

    it("should return the array's values mapped", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).mapSeries(function(val) {
            b.push(3-val);
            return val + 2;
        }).then(function(ret) {
            assert.deepEqual(ret, [3,4,5]);
            assert.deepEqual(b, [2, 1, 0]);
        });
    });

    it("takes value, index and length", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value, index, length) {
            b.push(value, index, length);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
        });
    });

    it("waits for returned promise before proceeding next", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value) {
            b.push(value);
            return Promise.delay(1).then(function(){
                b.push(value*2);
            });
        }).then(function(ret) {
            assert.deepEqual(b, [1,2,2,4,3,6]);
        });
    });

    it("waits for returned thenable before proceeding next", function() {
        var b = [1, 2, 3];
        var a = [thenabled(1), thenabled(2), thenabled(3)];
        return Promise.resolve(a).each(function(val) {
            b.push(val * 50);
            return thenabled(val * 500, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
        });
    });

    it("doesnt iterate with an empty array", function() {
        return Promise.each([], function(val) {
            throw new Error();
        }).then(function(ret) {
            assert.deepEqual(ret, []);
        });
    });

    it("iterates with an array of single item", function() {
        var b = [];
        return Promise.each([promised(1)], function(val) {
            b.push(val);
            return thenabled(val*2, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1,2]);
        });
    });
});

describe("Promise.prototype.each", function() {

    it("should return the array's values", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(val) {
            b.push(3-val);
            return val;
        }).then(function(ret) {
            assert.deepEqual(ret, [1,2,3]);
            assert.deepEqual(b, [2, 1, 0]);
        });
    });

    it("takes value, index and length", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value, index, length) {
            b.push(value, index, length);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
        });
    });

    it("waits for returned promise before proceeding next", function() {
        var a = [promised(1), promised(2), promised(3)];
        var b = [];
        return Promise.resolve(a).each(function(value) {
            b.push(value);
            return Promise.delay(1).then(function(){
                b.push(value*2);
            });
        }).then(function(ret) {
            assert.deepEqual(b, [1,2,2,4,3,6]);
        });
    });

    it("waits for returned thenable before proceeding next", function() {
        var b = [1, 2, 3];
        var a = [thenabled(1), thenabled(2), thenabled(3)];
        return Promise.resolve(a).each(function(val) {
            b.push(val * 50);
            return thenabled(val * 500, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
        });
    });

    it("doesnt iterate with an empty array", function() {
        return Promise.resolve([]).each(function(val) {
            throw new Error();
        }).then(function(ret) {
            assert.deepEqual(ret, []);
        });
    });

    it("iterates with an array of single item", function() {
        var b = [];
        return Promise.resolve([promised(1)]).each(function(val) {
            b.push(val);
            return thenabled(val*2, b);
        }).then(function(ret) {
            assert.deepEqual(b, [1,2]);
        });
    });
});

describe("mapSeries and each", function() {
    it("is mixed", function() {
        return Promise.mapSeries([1, 2, 3], function(value) {
            return value * 2;
        }).then(function(result) {
            assert.deepEqual(result, [2, 4, 6]);
        }).then(function() {
            return Promise.each([1, 2, 3], function(value) {
                return value * 2;
            }).then(function(result) {
                assert.deepEqual(result, [1, 2, 3]);
            });
        }).thenReturn([1, 2, 3]).mapSeries(function(value) {
            return value * 2;
        }).then(function(result) {
            assert.deepEqual(result, [2, 4, 6]);
        }).thenReturn([1, 2, 3]).each(function(value) {
            return value * 2;
        }).then(function(result) {
            assert.deepEqual(result, [1, 2, 3]);
        });
    })
});
<|endoftext|>


<commit_before>(function() {

  // When testing alternative View implementations, change this varaible.
  var View = Backbone.NativeView;

  var view;

  module("Backbone.NativeView", {

    setup: function() {
      view = new View({el: '#testElement'});
    }

  });

  test("extending", 3, function() {
    var BaseView = Backbone.View.extend();
    var NativeView = Backbone.NativeView;

    var ExtendedView = Backbone.View.extend(Backbone.NativeViewMixin);

    var MixinView = _.extend(BaseView, Backbone.NativeViewMixin);
    MixinView.prototype.initialize = function(options) { this._domEvents = []; }

    ok((new NativeView)._domEvents);
    ok((new ExtendedView)._domEvents);
    ok((new MixinView)._domEvents);
  });

  test("View#$", function() {
    var result = view.$('h1');
    equal(result.length, 1);
    equal(result[0].tagName.toLowerCase(), 'h1');
    equal(result[0].nodeType, 1);
  });

  test("delegate and undelegate", 6, function() {
    var counter1 = 0, counter2 = 0;
    view.delegate('click', function() { counter1++; });
    addEventListener.call(view.el, 'click', function() { counter2++ });

    click(view.el);

    equal(counter1, 1);
    equal(counter2, 1);
    equal(view._domEvents.length, 1);

    view.undelegate('click');

    click(view.el);

    equal(counter1, 1);
    equal(counter2, 2);
    equal(view._domEvents.length, 0);
  });

  test("undelegating only affects matched handlers", 1, function() {
    var counter = 0, handler = function() { counter++ };
    view.delegate('click', 'h1', handler);
    view.delegate('click', 'div', handler);
    view.undelegate('click', 'div');

    _.each(view.$('h1, div'), click);
    equal(counter, 1);
  });

  // Cross-browser helpers
  var addEventListener = typeof Element != 'undefined' && Element.prototype.addEventListener || function(eventName, listener) {
    return this.attachEvent('on' + eventName, listener);
  };

  function click(element) {
    var event;
    if (document.createEvent) {
      event = document.createEvent('MouseEvent');
      var args = [
        'click', true, true,
        // IE 10+ and Firefox require these
        event.view, event.detail, event.screenX, event.screenY, event.clientX,
        event.clientY, event.ctrlKey, event.altKey, event.shiftKey,
        event.metaKey, event.button, event.relatedTarget
      ];
      (event.initMouseEvent || event.initEvent).apply(event, args);
    } else {
      event = document.createEventObject();
      event.type = 'click';
      event.bubbles = true;
      event.cancelable = true;
    }

    if (element.dispatchEvent) {
      return element.dispatchEvent(event);
    }
    element.fireEvent('onclick', event);
  }
})();<commit_msg>clean up matched handlers test. still seems off, will fix<commit_after>(function() {

  // When testing alternative View implementations, change this varaible.
  var View = Backbone.NativeView;

  var view;

  module("Backbone.NativeView", {

    setup: function() {
      view = new View({el: '#testElement'});
    }

  });

  test("extending", 3, function() {
    var BaseView = Backbone.View.extend();
    var NativeView = Backbone.NativeView;

    var ExtendedView = Backbone.View.extend(Backbone.NativeViewMixin);

    var MixinView = _.extend(BaseView, Backbone.NativeViewMixin);
    MixinView.prototype.initialize = function(options) { this._domEvents = []; }

    ok((new NativeView)._domEvents);
    ok((new ExtendedView)._domEvents);
    ok((new MixinView)._domEvents);
  });

  test("View#$", function() {
    var result = view.$('h1');
    equal(result.length, 1);
    equal(result[0].tagName.toLowerCase(), 'h1');
    equal(result[0].nodeType, 1);
  });

  test("delegate and undelegate", 6, function() {
    var counter1 = 0, counter2 = 0;
    view.delegate('click', function() { counter1++; });
    addEventListener.call(view.el, 'click', function() { counter2++ });

    click(view.el);

    equal(counter1, 1);
    equal(counter2, 1);
    equal(view._domEvents.length, 1);

    view.undelegate('click');

    click(view.el);

    equal(counter1, 1);
    equal(counter2, 2);
    equal(view._domEvents.length, 0);
  });

  test("undelegating only affects matched handlers", 1, function() {
    view.delegate('click', 'h1', function() { ok(true); });
    view.delegate('click', 'div', function() { ok(false); });
    view.undelegate('click', 'div');

    _.each(view.$('h1, div'), click);
  });

  // Cross-browser helpers
  var addEventListener = typeof Element != 'undefined' && Element.prototype.addEventListener || function(eventName, listener) {
    return this.attachEvent('on' + eventName, listener);
  };

  function click(element) {
    var event;
    if (document.createEvent) {
      event = document.createEvent('MouseEvent');
      var args = [
        'click', true, true,
        // IE 10+ and Firefox require these
        event.view, event.detail, event.screenX, event.screenY, event.clientX,
        event.clientY, event.ctrlKey, event.altKey, event.shiftKey,
        event.metaKey, event.button, event.relatedTarget
      ];
      (event.initMouseEvent || event.initEvent).apply(event, args);
    } else {
      event = document.createEventObject();
      event.type = 'click';
      event.bubbles = true;
      event.cancelable = true;
    }

    if (element.dispatchEvent) {
      return element.dispatchEvent(event);
    }
    element.fireEvent('onclick', event);
  }
})();<|endoftext|>


<commit_before>/*global module:false*/
var Q = module.require('q');

QUnit.module('a test module');

QUnit.test('first test', function (assert) {
	assert.ok(true, 'true is ok');
});

QUnit.test('second test', 1, function (assert) {
  /* jshint -W109 */
	assert.equal(1, "1", '1 == "1"');
});

QUnit.test('qunit-promises is present', 1, function (assert) {
	assert.equal(typeof assert.will, 'function', 'assert.will is there');
});

function delayedFoo() {
	var deferred = Q.defer();
	setTimeout(function () { deferred.resolve('foo'); }, 100);
	return deferred.promise;
}

QUnit.test('example promise test', function (assert) {
	assert.will(delayedFoo(), 'promise is resolved');
	assert.willEqual(delayedFoo(), 'foo', 'promise is resolved with correct value');
});

function delayedHello() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.resolve('hello'); }, 100);
  return deferred.promise;
}

function delayedHelloFail() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.reject('bye'); }, 100);
  return deferred.promise;
}

function delayedOne() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.resolve(1); }, 100);
  return deferred.promise;
}

function delayedOneFail() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.reject(1); }, 100);
  return deferred.promise;
}

// regular custom code testing a successful promise
QUnit.test('test successful promise', 1, function (assert) {
  QUnit.stop();
  var promise = delayedHello();
  promise.then(function (actual) {
    assert.equal(actual, 'hello', 'promise resolved with "hello"');
  }).finally(QUnit.start);
});

// qunit-promises assertion
QUnit.test('promise will resolve', 1, function (assert) {
  assert.will(delayedHello());
});

QUnit.test('promise will resolve with message', 1, function (assert) {
  assert.will(delayedHello(), 'the promise is ok');
});

QUnit.test('promise will resolve with value', 1, function (assert) {
  assert.willEqual(delayedHello(), 'hello', 'returns "hello"');
});

QUnit.test('compare value using deep equality', 1, function (assert) {
  assert.willEqual(delayedOne(), 1, 'returns 1');
});

// regular code to test failed promise
QUnit.test('test failed promise', 1, function (assert) {
  QUnit.stop();
  var promise = delayedHelloFail();
  promise.then(function () {
    assert.ok(false, 'promise failed to fail!');
  }, function (actual) {
    assert.equal(actual, 'bye', 'promise failed');
  }).finally(QUnit.start);
});

QUnit.test('promise will reject', 1, function (assert) {
  assert.wont(delayedHelloFail(), 'promise fails');
});

QUnit.test('promise will reject with value', 1, function (assert) {
  assert.wontEqual(delayedHelloFail(), 'bye');
});

QUnit.test('promise will reject with value + message', 1, function (assert) {
  assert.wontEqual(delayedHelloFail(), 'bye', 'this is a failed promise');
});

QUnit.test('using deep equality', 1, function (assert) {
  assert.wontEqual(delayedOneFail(), 1, 'returns 1');
});

// advanced
QUnit.test('two resolved promises in sequence', 1, function (assert) {
  assert.willEqual(delayedHello().then(delayedHello), 'hello', 'promises chained');
});

QUnit.test('null promise throws an error', function (assert) {
  assert.throws(function () {
    assert.will(null, 'this should not resolve');
  }, 'null promise causes an error');
});

QUnit.test('invalid promise throws an error', function (assert) {
  assert.throws(function () {
    assert.will({}, 'this does not have .then');
  }, 'invalid promise object causes an error');
});

QUnit.test('promise without .always throws an error', function (assert) {
  assert.throws(function () {
    assert.will({
      then: function () {}
    }, 'this does not have .always');
  }, 'invalid promise object causes an error');
});

/* testing async module setup work around */
QUnit.module('async setup');

var counter = 0;
function initCounter() {
  var defer = Q.defer();
  setTimeout(function () {
    counter += 1;
    defer.resolve();
  }, 1000);
  return defer.promise;
}

function getCounter() {
  return counter;
}

QUnit.test('manual async init', function (assert) {
  /*jshint -W064*/
  assert.willEqual(initCounter().then(getCounter), 1);
});
<commit_msg>getting counter after initialization<commit_after>/*global module:false*/
var Q = module.require('q');

QUnit.module('a test module');

QUnit.test('first test', function (assert) {
	assert.ok(true, 'true is ok');
});

QUnit.test('second test', 1, function (assert) {
  /* jshint -W109 */
	assert.equal(1, "1", '1 == "1"');
});

QUnit.test('qunit-promises is present', 1, function (assert) {
	assert.equal(typeof assert.will, 'function', 'assert.will is there');
});

function delayedFoo() {
	var deferred = Q.defer();
	setTimeout(function () { deferred.resolve('foo'); }, 100);
	return deferred.promise;
}

QUnit.test('example promise test', function (assert) {
	assert.will(delayedFoo(), 'promise is resolved');
	assert.willEqual(delayedFoo(), 'foo', 'promise is resolved with correct value');
});

function delayedHello() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.resolve('hello'); }, 100);
  return deferred.promise;
}

function delayedHelloFail() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.reject('bye'); }, 100);
  return deferred.promise;
}

function delayedOne() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.resolve(1); }, 100);
  return deferred.promise;
}

function delayedOneFail() {
  var deferred = Q.defer();
  setTimeout(function () { deferred.reject(1); }, 100);
  return deferred.promise;
}

// regular custom code testing a successful promise
QUnit.test('test successful promise', 1, function (assert) {
  QUnit.stop();
  var promise = delayedHello();
  promise.then(function (actual) {
    assert.equal(actual, 'hello', 'promise resolved with "hello"');
  }).finally(QUnit.start);
});

// qunit-promises assertion
QUnit.test('promise will resolve', 1, function (assert) {
  assert.will(delayedHello());
});

QUnit.test('promise will resolve with message', 1, function (assert) {
  assert.will(delayedHello(), 'the promise is ok');
});

QUnit.test('promise will resolve with value', 1, function (assert) {
  assert.willEqual(delayedHello(), 'hello', 'returns "hello"');
});

QUnit.test('compare value using deep equality', 1, function (assert) {
  assert.willEqual(delayedOne(), 1, 'returns 1');
});

// regular code to test failed promise
QUnit.test('test failed promise', 1, function (assert) {
  QUnit.stop();
  var promise = delayedHelloFail();
  promise.then(function () {
    assert.ok(false, 'promise failed to fail!');
  }, function (actual) {
    assert.equal(actual, 'bye', 'promise failed');
  }).finally(QUnit.start);
});

QUnit.test('promise will reject', 1, function (assert) {
  assert.wont(delayedHelloFail(), 'promise fails');
});

QUnit.test('promise will reject with value', 1, function (assert) {
  assert.wontEqual(delayedHelloFail(), 'bye');
});

QUnit.test('promise will reject with value + message', 1, function (assert) {
  assert.wontEqual(delayedHelloFail(), 'bye', 'this is a failed promise');
});

QUnit.test('using deep equality', 1, function (assert) {
  assert.wontEqual(delayedOneFail(), 1, 'returns 1');
});

// advanced
QUnit.test('two resolved promises in sequence', 1, function (assert) {
  assert.willEqual(delayedHello().then(delayedHello), 'hello', 'promises chained');
});

QUnit.test('null promise throws an error', function (assert) {
  assert.throws(function () {
    assert.will(null, 'this should not resolve');
  }, 'null promise causes an error');
});

QUnit.test('invalid promise throws an error', function (assert) {
  assert.throws(function () {
    assert.will({}, 'this does not have .then');
  }, 'invalid promise object causes an error');
});

QUnit.test('promise without .always throws an error', function (assert) {
  assert.throws(function () {
    assert.will({
      then: function () {}
    }, 'this does not have .always');
  }, 'invalid promise object causes an error');
});

/* testing async module setup work around */
QUnit.module('async setup');

var obj = {
  counter: 0,
  getCounter: function () {
    return this.counter;
  }
};

function initCounter() {
  var defer = Q.defer();
  setTimeout(function () {
    obj.counter += 1;
    defer.resolve();
  }, 1000);
  return defer.promise;
}

QUnit.test('manual async init', function (assert) {
  assert.willEqual(initCounter().then(obj.getCounter.bind(obj)), 1);
});
<|endoftext|>