<commit_before>var should = require('chai').should();
var expect = require('chai').expect;
var Weiqi = require('../index.js');

// shorthand for testing whole board
Object.prototype.looksLike = function(rows) {
  var expected = [];
  rows.forEach(function(str) {
    expected.push(str.split(''));
  });
  return this.toArray().should.deep.equal(expected);
};

describe("Board", function() {
  describe('#createBoard', function() {
    it('creates a board of size 9', function() {
      var board = Weiqi.createBoard(9);
      board.getSize().should.equal(9);
    });

    it('creates a board of size 13', function() {
      var board = Weiqi.createBoard(13);
      board.getSize().should.equal(13);
    });

    it('creates a board of size 19', function() {
      var board = Weiqi.createBoard(19);
      board.getSize().should.equal(19);
    });

    it('should start off empty', function() {
      var board = Weiqi.createBoard(9);
      var i, j;
      for (i = 0; i < 9; i++)
        for (j = 0; j < 9; j++)
          board.getStone([i, j]).should.equal(Weiqi.EMPTY);
    });

    it('requires a size', function() {
      var fn = function() { Weiqi.createBoard(); };
      expect(fn).to.throw("Size must be an integer greater than zero");
    });

    it('rejects negative size', function() {
      var fn = function() { Weiqi.createBoard(-9); };
      expect(fn).to.throw("Size must be an integer greater than zero");
    });
  });

  describe('#play', function() {
    it('should allow inner coords', function() {
      var i, j, board;
      var board = Weiqi.createBoard(9);
      for (i = 0; i < 9; i++)
        for (j = 0; j < 9; j++) {
          board
            .play(Weiqi.BLACK, [i, j])
           .getStone([i, j]).should.equal(Weiqi.BLACK);
        }
    });

    it('should reject out of bounds coords', function() {
      var positions = [[-1, 0], [0, -1], [-1, -1], [9, 0], [0, 9], [9, 9]];
      positions.forEach(function(position) {
        var fn = function() {
          return Weiqi.createBoard(9).play(Weiqi.BLACK, positions);
        };
        expect(fn).to.throw("Intersection out of bounds");
      });
    });

    it('should reject occupied intersections', function() {
      var fn = function() {
        Weiqi.createBoard(9)
          .play(Weiqi.BLACK, [0, 0])
          .play(Weiqi.WHITE, [0, 0]);
      };
      expect(fn).to.throw("Intersection occupied by existing stone");
    });

    it('should set the correct stone color', function() {
      Weiqi.createBoard(4)
        .play(Weiqi.BLACK, [0, 0])
        .looksLike(['x...', '....', '....', '....']);

      Weiqi.createBoard(4)
        .play(Weiqi.WHITE, [3, 2])
        .looksLike(['....', '....', '....', '..o.']);
    });

    it('should capture stones in the corner', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 0])
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['xx..', 'x...', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [1, 1]);

      board.looksLike(['xxo.', 'xo..', '....', '....']);

      board = board.play(Weiqi.WHITE, [2, 0]);
      board.looksLike(['..o.', '.o..', 'o...', '....']);
    });

    it('should capture stones on the side', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 3])
                    .play(Weiqi.BLACK, [1, 2]);

      board.looksLike(['....', '..xx', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [1, 1])
        .play(Weiqi.WHITE, [0, 3])
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [2, 3]);

      board.looksLike(['..oo', '.oxx', '...o', '....']);
      board = board.play(Weiqi.WHITE, [2, 2]);
      board.looksLike(['..oo', '.o..', '..oo', '....']);
    });

    it('should capture stones in the middle', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [1, 2]);

      board.looksLike(['....', '.xx.', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [1, 0])
        .play(Weiqi.WHITE, [1, 3])
        .play(Weiqi.WHITE, [2, 1])
        .play(Weiqi.WHITE, [2, 2]);

      board.looksLike(['..o.', 'oxxo', '.oo.', '....']);
      board = board.play(Weiqi.WHITE, [0, 1]);
      board.looksLike(['.oo.', 'o..o', '.oo.', '....']);
    });

    it('should allow suicide of one stone', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 2])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['.x..', 'x.x.', '.x..', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.x..', 'x.x.', '.x..', '....']);
    });

    it('should allow suicide of many stones', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [0, 2])
                    .play(Weiqi.BLACK, [1, 3])
                    .play(Weiqi.BLACK, [2, 2])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['.xx.', 'x..x', '.xx.', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.xx.', 'xo.x', '.xx.', '....']);
      board = board.play(Weiqi.WHITE, [1, 2]);
      board.looksLike(['.xx.', 'x..x', '.xx.', '....']);
    });

    it('should evaluate enemy liberties before player liberties', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.BLACK, [1, 2])
                    .play(Weiqi.WHITE, [1, 3])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.BLACK, [1, 0]);
      board.looksLike(['.xo.', 'x.xo', '.xo.', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.xo.', 'xo.o', '.xo.', '....']);
    });
  });

  describe('#getStones', function() {
    it('should return nothing for an empty board', function() {
      var board = Weiqi.createBoard(9);
      board.getStones(Weiqi.BLACK).length.should.equal(0);
      board.getStones(Weiqi.WHITE).length.should.equal(0);
    });

    it('should return only the correct color', function() {
      var board = Weiqi.createBoard(9)
        .play(Weiqi.BLACK, [2, 2])
        .play(Weiqi.BLACK, [2, 3])
        .play(Weiqi.WHITE, [6, 6])
        .play(Weiqi.WHITE, [7, 6]);

      board.getStones(Weiqi.BLACK).should.deep.equal([[2, 2], [2, 3]]);
      board.getStones(Weiqi.WHITE).should.deep.equal([[6, 6], [7, 6]]);
    });
  });

  describe('#areaScore', function() {
    it('should not award points for empty board', function() {
      var board = Weiqi.createBoard(4);
      board.looksLike(['....', '....', '....', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(0);
      score[Weiqi.WHITE].should.equal(0);
    });

    it('should award points for board with single stone', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 0]);
      board.looksLike(['x...', '....', '....', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(16);
      score[Weiqi.WHITE].should.equal(0);
    });

    it('should not award points for sparse board', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.WHITE, [2, 2]);
      board.looksLike(['....', '.x..', '..o.', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(1);
      score[Weiqi.WHITE].should.equal(1);
    });

    it('should count stones and territory', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [3, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.WHITE, [1, 2])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.WHITE, [3, 2]);
      board.looksLike(['.xo.', '.xo.', '.xo.', '.xo.']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(8);
      score[Weiqi.WHITE].should.equal(8);
    });

    it('should consider all stones alive', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [3, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.WHITE, [1, 2])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.WHITE, [3, 2])
                    .play(Weiqi.BLACK, [2, 3])
                    .play(Weiqi.BLACK, [3, 3]);
      board.looksLike(['.xo.', '.xo.', '.xox', '.xox']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(10);
      score[Weiqi.WHITE].should.equal(4);
    });
  });
});
<commit_msg>Update Board.getStones test to assume set semantics<commit_after>var should = require('chai').should();
var expect = require('chai').expect;
var Weiqi = require('../index.js');

// shorthand for testing whole board
Object.prototype.looksLike = function(rows) {
  var expected = [];
  rows.forEach(function(str) {
    expected.push(str.split(''));
  });
  return this.toArray().should.deep.equal(expected);
};

describe("Board", function() {
  describe('#createBoard', function() {
    it('creates a board of size 9', function() {
      var board = Weiqi.createBoard(9);
      board.getSize().should.equal(9);
    });

    it('creates a board of size 13', function() {
      var board = Weiqi.createBoard(13);
      board.getSize().should.equal(13);
    });

    it('creates a board of size 19', function() {
      var board = Weiqi.createBoard(19);
      board.getSize().should.equal(19);
    });

    it('should start off empty', function() {
      var board = Weiqi.createBoard(9);
      var i, j;
      for (i = 0; i < 9; i++)
        for (j = 0; j < 9; j++)
          board.getStone([i, j]).should.equal(Weiqi.EMPTY);
    });

    it('requires a size', function() {
      var fn = function() { Weiqi.createBoard(); };
      expect(fn).to.throw("Size must be an integer greater than zero");
    });

    it('rejects negative size', function() {
      var fn = function() { Weiqi.createBoard(-9); };
      expect(fn).to.throw("Size must be an integer greater than zero");
    });
  });

  describe('#play', function() {
    it('should allow inner coords', function() {
      var i, j, board;
      var board = Weiqi.createBoard(9);
      for (i = 0; i < 9; i++)
        for (j = 0; j < 9; j++) {
          board
            .play(Weiqi.BLACK, [i, j])
           .getStone([i, j]).should.equal(Weiqi.BLACK);
        }
    });

    it('should reject out of bounds coords', function() {
      var positions = [[-1, 0], [0, -1], [-1, -1], [9, 0], [0, 9], [9, 9]];
      positions.forEach(function(position) {
        var fn = function() {
          return Weiqi.createBoard(9).play(Weiqi.BLACK, positions);
        };
        expect(fn).to.throw("Intersection out of bounds");
      });
    });

    it('should reject occupied intersections', function() {
      var fn = function() {
        Weiqi.createBoard(9)
          .play(Weiqi.BLACK, [0, 0])
          .play(Weiqi.WHITE, [0, 0]);
      };
      expect(fn).to.throw("Intersection occupied by existing stone");
    });

    it('should set the correct stone color', function() {
      Weiqi.createBoard(4)
        .play(Weiqi.BLACK, [0, 0])
        .looksLike(['x...', '....', '....', '....']);

      Weiqi.createBoard(4)
        .play(Weiqi.WHITE, [3, 2])
        .looksLike(['....', '....', '....', '..o.']);
    });

    it('should capture stones in the corner', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 0])
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['xx..', 'x...', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [1, 1]);

      board.looksLike(['xxo.', 'xo..', '....', '....']);

      board = board.play(Weiqi.WHITE, [2, 0]);
      board.looksLike(['..o.', '.o..', 'o...', '....']);
    });

    it('should capture stones on the side', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 3])
                    .play(Weiqi.BLACK, [1, 2]);

      board.looksLike(['....', '..xx', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [1, 1])
        .play(Weiqi.WHITE, [0, 3])
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [2, 3]);

      board.looksLike(['..oo', '.oxx', '...o', '....']);
      board = board.play(Weiqi.WHITE, [2, 2]);
      board.looksLike(['..oo', '.o..', '..oo', '....']);
    });

    it('should capture stones in the middle', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [1, 2]);

      board.looksLike(['....', '.xx.', '....', '....']);

      board = board
        .play(Weiqi.WHITE, [0, 2])
        .play(Weiqi.WHITE, [1, 0])
        .play(Weiqi.WHITE, [1, 3])
        .play(Weiqi.WHITE, [2, 1])
        .play(Weiqi.WHITE, [2, 2]);

      board.looksLike(['..o.', 'oxxo', '.oo.', '....']);
      board = board.play(Weiqi.WHITE, [0, 1]);
      board.looksLike(['.oo.', 'o..o', '.oo.', '....']);
    });

    it('should allow suicide of one stone', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 2])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['.x..', 'x.x.', '.x..', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.x..', 'x.x.', '.x..', '....']);
    });

    it('should allow suicide of many stones', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [0, 2])
                    .play(Weiqi.BLACK, [1, 3])
                    .play(Weiqi.BLACK, [2, 2])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [1, 0]);

      board.looksLike(['.xx.', 'x..x', '.xx.', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.xx.', 'xo.x', '.xx.', '....']);
      board = board.play(Weiqi.WHITE, [1, 2]);
      board.looksLike(['.xx.', 'x..x', '.xx.', '....']);
    });

    it('should evaluate enemy liberties before player liberties', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.BLACK, [1, 2])
                    .play(Weiqi.WHITE, [1, 3])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.BLACK, [1, 0]);
      board.looksLike(['.xo.', 'x.xo', '.xo.', '....']);
      board = board.play(Weiqi.WHITE, [1, 1]);
      board.looksLike(['.xo.', 'xo.o', '.xo.', '....']);
    });
  });

  describe('#getStones', function() {
    it('should return nothing for an empty board', function() {
      var board = Weiqi.createBoard(9);
      board.getStones(Weiqi.BLACK).length.should.equal(0);
      board.getStones(Weiqi.WHITE).length.should.equal(0);
    });

    it('should return only the correct color', function() {
      var board = Weiqi.createBoard(9)
        .play(Weiqi.BLACK, [2, 2])
        .play(Weiqi.BLACK, [2, 3])
        .play(Weiqi.WHITE, [6, 6])
        .play(Weiqi.WHITE, [7, 6]);

      board.getStones(Weiqi.BLACK).should.deep.have.members([[2, 2], [2, 3]]);
      board.getStones(Weiqi.WHITE).should.deep.have.members([[7, 6], [6, 6]]);
    });
  });

  describe('#areaScore', function() {
    it('should not award points for empty board', function() {
      var board = Weiqi.createBoard(4);
      board.looksLike(['....', '....', '....', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(0);
      score[Weiqi.WHITE].should.equal(0);
    });

    it('should award points for board with single stone', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 0]);
      board.looksLike(['x...', '....', '....', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(16);
      score[Weiqi.WHITE].should.equal(0);
    });

    it('should not award points for sparse board', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.WHITE, [2, 2]);
      board.looksLike(['....', '.x..', '..o.', '....']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(1);
      score[Weiqi.WHITE].should.equal(1);
    });

    it('should count stones and territory', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [3, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.WHITE, [1, 2])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.WHITE, [3, 2]);
      board.looksLike(['.xo.', '.xo.', '.xo.', '.xo.']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(8);
      score[Weiqi.WHITE].should.equal(8);
    });

    it('should consider all stones alive', function() {
      var board = Weiqi.createBoard(4)
                    .play(Weiqi.BLACK, [0, 1])
                    .play(Weiqi.BLACK, [1, 1])
                    .play(Weiqi.BLACK, [2, 1])
                    .play(Weiqi.BLACK, [3, 1])
                    .play(Weiqi.WHITE, [0, 2])
                    .play(Weiqi.WHITE, [1, 2])
                    .play(Weiqi.WHITE, [2, 2])
                    .play(Weiqi.WHITE, [3, 2])
                    .play(Weiqi.BLACK, [2, 3])
                    .play(Weiqi.BLACK, [3, 3]);
      board.looksLike(['.xo.', '.xo.', '.xox', '.xox']);
      var score = board.areaScore();
      score[Weiqi.BLACK].should.equal(10);
      score[Weiqi.WHITE].should.equal(4);
    });
  });
});
<|endoftext|>


<commit_before>/*jslint node: true*/
/*jslint expr: true*/
/*global describe, it*/
"use strict";

var should = require('should');
var emoji = require('../index');

describe("emoji.js", function () {
  describe("get(emoji)", function () {
    it("should return an emoji code", function () {
      var coffee = emoji.get('coffee');
      should.exist(coffee);
      coffee.should.be.exactly('☕');
    });

    it("should support github flavored markdown emoji", function () {
      var coffee = emoji.get(':coffee:');
      should.exist(coffee);
      coffee.should.be.exactly('☕');
    });
  });

  describe("random()", function () {
    it("should return a random emoji and the corresponding key", function () {
      var result = emoji.random();
      should.exist(result);
      should.exist(result.key);
      should.exist(result.emoji);
      result.emoji.should.be.exactly(emoji.get(result.key));
    });
  });

  describe("which(emoji_code)", function () {
    it("should return name of the emoji", function () {
      var coffee = emoji.which('☕');
      should.exist(coffee);
      coffee.should.be.exactly('coffee');
    });

    it("should work for differently formed characters", function () {
      var umbrella = emoji.which('☔');
      should.exist(umbrella);
      umbrella.should.be.exactly('umbrella');
    });

    it("should return the same name for differently formed characters", function () {
      var umbrella1 = emoji.which('☔');
      should.exist(umbrella1);
      var umbrella2 = emoji.which('☔');
      should.exist(umbrella2);
      umbrella1.should.equal(umbrella2);
    });

    it("should work for flags", function() {
      var mexico = emoji.which('🇲🇽');
      should.exists(mexico);
      mexico.should.be.exactly('flag-mx');

      var marocco = emoji.which('🇲🇦');
      should.exists(marocco);
      marocco.should.be.exactly('flag-ma');

      // see issue #21
      mexico.should.not.equal(marocco);
    });
  });

  describe("emojify(str)", function () {
    it("should parse :emoji: in a string and replace them with the right emoji", function () {
      var coffee = emoji.emojify('I :heart:  :coffee:! -  :hushed::star::heart_eyes:  ::: test : : :+1:+');
      should.exist(coffee);
      coffee.should.be.exactly('I ❤  ☕! -  😯⭐😍  ::: test : : 👍+');
    });

    it("should handle flags correctly", function() {
      var flags = emoji.emojify('Mexico :flag-mx: and Marocco :flag-ma: are not the same');
      should.exists(flags);
      flags.should.be.exactly('Mexico 🇲🇽 and Marocco 🇲🇦 are not the same');
    });

    it("should leave unknown emoji", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :star: :another_one:');
      should.exist(coffee);
      coffee.should.be.exactly('I :unknown_emoji: ⭐ :another_one:');
    });

    it("should replace unknown emoji using provided cb function", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :star: :another_one:', function(name) {
        return name;
      });
      should.exist(coffee);
      coffee.should.be.exactly('I unknown_emoji ⭐ another_one');
    });

    it("should wrap emoji using provided format function", function () {
      var coffee = emoji.emojify('I :heart: :coffee:', null, function(code, name) {
        return '';
      });

      should.exist(coffee);
      coffee.should.be.exactly('I  ');
    });

    it("should not wrap unknown using provided format function", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :coffee:', null, function(code, name) {
        return '';
      });

      should.exist(coffee);
      coffee.should.be.exactly('I :unknown_emoji: ');
    });

    it("should replace unknown emojis and wrap known emojis using cb functions", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :coffee:',
        function(name) {
          return name;
        },
        function(code, name) {
          return '';
        }
      );

      should.exist(coffee);
      coffee.should.be.exactly('I unknown_emoji ');
    });
  });

  it("should return an emoji code", function () {
    var coffee = emoji.emoji.coffee;
    should.exist(coffee);
    coffee.should.be.exactly('☕');
  });

  describe("search(str)", function () {
    it("should return partially matched emojis", function () {
      var matchingEmojis = emoji.search("cof");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        emoji.key.should.match(/^cof/);
      });
    });

    it("should only include emojies that begin with the search", function () {
      var matchingEmojis = emoji.search("ca");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        var index = emoji.key.indexOf("ca");
        index.should.be.exactly(0);
      });
    });

    it("should match when you include the colon", function () {
      var matchingEmojis = emoji.search(":c");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        var index = emoji.key.indexOf("c");
        index.should.be.exactly(0);
      });
    });

    it("should return an empty array when no matching emojis are found", function () {
      var matchingEmojis = emoji.search("notAnEmoji");
      matchingEmojis.length.should.be.exactly(0);
    });
  });

  describe("unemojify(str)", function () {
    it("should parse emoji and replace them with :emoji:", function() {
      var coffee = emoji.unemojify('I ❤  ☕! -  😯⭐😍  ::: test : : 👍+');
      should.exist(coffee);
      coffee.should.be.exactly('I :heart:  :coffee:! -  :hushed::star::heart_eyes:  ::: test : : :thumbsup:+');
    })

    it("should leave unknown emoji", function () {
      var coffee = emoji.unemojify('I ⭐ :another_one: 🥕');
      should.exist(coffee);
      coffee.should.be.exactly('I :star: :another_one: 🥕');
    });

    it("should parse a complex emoji like woman-kiss-woman and replace it with :woman-kiss-woman:", function() {
      var coffee = emoji.unemojify('I love 👩❤💋👩');
      should.exist(coffee);
      coffee.should.be.exactly('I love :woman-kiss-woman:');
    });

    it("should parse flags correctly", function () {
      var flags = emoji.unemojify('The flags of 🇲🇽 and 🇲🇦 are not the same');
      should.exists(flags);
      flags.should.be.exactly('The flags of :flag-mx: and :flag-ma: are not the same');
    });
  });

  describe('find emoji', function() {
    it('Should be able to find a emoji by :name:', function() {
      var result = emoji.find(':heart:')
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should be able to find an emoji by name', function() {
      var result = emoji.find('heart');
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should be able to find an emoji by code', function() {
      var result = emoji.find('❤');
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should return `undefined` for unknown emojis', function() {
      var result = emoji.find('unknown_emoji');
      should.not.exists(result);
    })
  });

  describe('hasEmoji', function() {
    it('Should be able to check a emoji by :name:', function() {
      var result = emoji.hasEmoji(':heart:');
      result.should.equal(true)
    });

    it('Should be able to check a emoji by name', function() {
      var result = emoji.hasEmoji('heart');
      result.should.equal(true);
    });

    it('Should be able to check a emoji by code text form)', function() {
      var result = emoji.hasEmoji('❤');
      result.should.equal(true);
    });

    it('Should be able to check a emoji by code in variant form', function() {
      var result = emoji.hasEmoji('❤');
      result.should.equal(true);
    });

    it('Should return false for unknown emoji names', function() {
      var result = emoji.hasEmoji(':pizza-kiss-coffee:');
      result.should.equal(false);
    });

    it('Should return false for unknown emoji codes', function() {
      var result = emoji.hasEmoji('🍕❤💋☕');
      result.should.equal(false);
    });
  });
});
<commit_msg>Add failing tests for Emoji.replace and Emoji.strip<commit_after>/*jslint node: true*/
/*jslint expr: true*/
/*global describe, it*/
"use strict";

var should = require('should');
var emoji = require('../index');

describe("emoji.js", function () {
  describe("get(emoji)", function () {
    it("should return an emoji code", function () {
      var coffee = emoji.get('coffee');
      should.exist(coffee);
      coffee.should.be.exactly('☕');
    });

    it("should support github flavored markdown emoji", function () {
      var coffee = emoji.get(':coffee:');
      should.exist(coffee);
      coffee.should.be.exactly('☕');
    });
  });

  describe("random()", function () {
    it("should return a random emoji and the corresponding key", function () {
      var result = emoji.random();
      should.exist(result);
      should.exist(result.key);
      should.exist(result.emoji);
      result.emoji.should.be.exactly(emoji.get(result.key));
    });
  });

  describe("which(emoji_code)", function () {
    it("should return name of the emoji", function () {
      var coffee = emoji.which('☕');
      should.exist(coffee);
      coffee.should.be.exactly('coffee');
    });

    it("should work for differently formed characters", function () {
      var umbrella = emoji.which('☔');
      should.exist(umbrella);
      umbrella.should.be.exactly('umbrella');
    });

    it("should return the same name for differently formed characters", function () {
      var umbrella1 = emoji.which('☔');
      should.exist(umbrella1);
      var umbrella2 = emoji.which('☔');
      should.exist(umbrella2);
      umbrella1.should.equal(umbrella2);
    });

    it("should work for flags", function() {
      var mexico = emoji.which('🇲🇽');
      should.exists(mexico);
      mexico.should.be.exactly('flag-mx');

      var marocco = emoji.which('🇲🇦');
      should.exists(marocco);
      marocco.should.be.exactly('flag-ma');

      // see issue #21
      mexico.should.not.equal(marocco);
    });
  });

  describe("emojify(str)", function () {
    it("should parse :emoji: in a string and replace them with the right emoji", function () {
      var coffee = emoji.emojify('I :heart:  :coffee:! -  :hushed::star::heart_eyes:  ::: test : : :+1:+');
      should.exist(coffee);
      coffee.should.be.exactly('I ❤  ☕! -  😯⭐😍  ::: test : : 👍+');
    });

    it("should handle flags correctly", function() {
      var flags = emoji.emojify('Mexico :flag-mx: and Marocco :flag-ma: are not the same');
      should.exists(flags);
      flags.should.be.exactly('Mexico 🇲🇽 and Marocco 🇲🇦 are not the same');
    });

    it("should leave unknown emoji", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :star: :another_one:');
      should.exist(coffee);
      coffee.should.be.exactly('I :unknown_emoji: ⭐ :another_one:');
    });

    it("should replace unknown emoji using provided cb function", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :star: :another_one:', function(name) {
        return name;
      });
      should.exist(coffee);
      coffee.should.be.exactly('I unknown_emoji ⭐ another_one');
    });

    it("should wrap emoji using provided format function", function () {
      var coffee = emoji.emojify('I :heart: :coffee:', null, function(code, name) {
        return '';
      });

      should.exist(coffee);
      coffee.should.be.exactly('I  ');
    });

    it("should not wrap unknown using provided format function", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :coffee:', null, function(code, name) {
        return '';
      });

      should.exist(coffee);
      coffee.should.be.exactly('I :unknown_emoji: ');
    });

    it("should replace unknown emojis and wrap known emojis using cb functions", function () {
      var coffee = emoji.emojify('I :unknown_emoji: :coffee:',
        function(name) {
          return name;
        },
        function(code, name) {
          return '';
        }
      );

      should.exist(coffee);
      coffee.should.be.exactly('I unknown_emoji ');
    });
  });

  it("should return an emoji code", function () {
    var coffee = emoji.emoji.coffee;
    should.exist(coffee);
    coffee.should.be.exactly('☕');
  });

  describe("search(str)", function () {
    it("should return partially matched emojis", function () {
      var matchingEmojis = emoji.search("cof");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        emoji.key.should.match(/^cof/);
      });
    });

    it("should only include emojies that begin with the search", function () {
      var matchingEmojis = emoji.search("ca");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        var index = emoji.key.indexOf("ca");
        index.should.be.exactly(0);
      });
    });

    it("should match when you include the colon", function () {
      var matchingEmojis = emoji.search(":c");
      matchingEmojis.length.should.not.eql(0);
      matchingEmojis.forEach(function(emoji) {
        var index = emoji.key.indexOf("c");
        index.should.be.exactly(0);
      });
    });

    it("should return an empty array when no matching emojis are found", function () {
      var matchingEmojis = emoji.search("notAnEmoji");
      matchingEmojis.length.should.be.exactly(0);
    });
  });

  describe("unemojify(str)", function () {
    it("should parse emoji and replace them with :emoji:", function() {
      var coffee = emoji.unemojify('I ❤  ☕! -  😯⭐😍  ::: test : : 👍+');
      should.exist(coffee);
      coffee.should.be.exactly('I :heart:  :coffee:! -  :hushed::star::heart_eyes:  ::: test : : :thumbsup:+');
    })

    it("should leave unknown emoji", function () {
      var coffee = emoji.unemojify('I ⭐ :another_one: 🥕');
      should.exist(coffee);
      coffee.should.be.exactly('I :star: :another_one: 🥕');
    });

    it("should parse a complex emoji like woman-kiss-woman and replace it with :woman-kiss-woman:", function() {
      var coffee = emoji.unemojify('I love 👩❤💋👩');
      should.exist(coffee);
      coffee.should.be.exactly('I love :woman-kiss-woman:');
    });

    it("should parse flags correctly", function () {
      var flags = emoji.unemojify('The flags of 🇲🇽 and 🇲🇦 are not the same');
      should.exists(flags);
      flags.should.be.exactly('The flags of :flag-mx: and :flag-ma: are not the same');
    });
  });

  describe('find emoji', function() {
    it('Should be able to find a emoji by :name:', function() {
      var result = emoji.find(':heart:')
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should be able to find an emoji by name', function() {
      var result = emoji.find('heart');
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should be able to find an emoji by code', function() {
      var result = emoji.find('❤');
      should.exists(result);
      result.should.eql({ emoji: '❤', key: 'heart' });
    });

    it('Should return `undefined` for unknown emojis', function() {
      var result = emoji.find('unknown_emoji');
      should.not.exists(result);
    })
  });

  describe('hasEmoji', function() {
    it('Should be able to check a emoji by :name:', function() {
      var result = emoji.hasEmoji(':heart:');
      result.should.equal(true)
    });

    it('Should be able to check a emoji by name', function() {
      var result = emoji.hasEmoji('heart');
      result.should.equal(true);
    });

    it('Should be able to check a emoji by code text form)', function() {
      var result = emoji.hasEmoji('❤');
      result.should.equal(true);
    });

    it('Should be able to check a emoji by code in variant form', function() {
      var result = emoji.hasEmoji('❤');
      result.should.equal(true);
    });

    it('Should return false for unknown emoji names', function() {
      var result = emoji.hasEmoji(':pizza-kiss-coffee:');
      result.should.equal(false);
    });

    it('Should return false for unknown emoji codes', function() {
      var result = emoji.hasEmoji('🍕❤💋☕');
      result.should.equal(false);
    });
  });

  describe('replace', function() {
    it('Should be able to strip emojis', function() {
      var result = emoji.replace('Host: eseaps001 Addr: 10.XX.XX.XX: - ⚠ 〰 〰 low disk space', '', true);
      result.should.equal('Host: eseaps001 Addr: 10.XX.XX.XX: - low disk space');
    });

    it('Should keep the trailing spaces when not explicitly told to clean', function() {
      var result = emoji.replace('Host: eseaps001 Addr: 10.XX.XX.XX: - ⚠ 〰 〰 low disk space', '');
      result.should.equal('Host: eseaps001 Addr: 10.XX.XX.XX: -    low disk space');
    });

    it('Should be able to strip a emoji by code text form', function() {
      var result = emoji.replace('I ❤ coffee', '', true);
      result.should.equal('I coffee');
    });

    it('Should be able to strip a emoji by code in variant form', function() {
      var result = emoji.replace('I ❤ cleaning', '', true);
      result.should.equal('I cleaning');
    });

    it('Should be able to strip complex emojis', function() {
      var result = emoji.replace('Where did this 👩❤💋👩 happen?', '', true);
      result.should.equal('Where did this happen?');
    });

    it('Should be able to strip flag emojis', function() {
      var result = emoji.replace('There is no flag 🇲🇽', '', true);
      result.should.equal('There is no flag');
    });

    it('Should be able to replace by callback function', function() {
      var result = emoji.replace('There is no ⚠ on my hard drive', function (emoji) {
        return emoji.key;
      });
      result.should.equal('There is no warning on my hard drive');
    });

    it('Non existing complex emojis are known to be ignored', function() {
      var result = emoji.replace('Some 🍕❤💋☕ emoji', '');
      result.should.not.equal('Some emoji');
    });
  });

  describe('strip', function() {
    it('Should be able to strip emojis', function() {
      var result = emoji.strip('Host: eseaps001 Addr: 10.XX.XX.XX: - ⚠ 〰 〰 low disk space');
      result.should.equal('Host: eseaps001 Addr: 10.XX.XX.XX: - low disk space');
    });
  });
});
<|endoftext|>


<commit_before>"use strict";
/*jshint mocha: true*/
/*eslint-env mocha*/
/*global assert*/

describe("error", function () {

    describe("gpf.Error", function () {

        it("is used as an exception", function () {
            try {
                throw gpf.Error.abstract();
            } catch (e) {
                assert(e instanceof gpf.Error);
                assert(e.constructor === gpf.Error);
            }
        });

        it("is documented", function () {
            try {
                throw gpf.Error.abstract();
            } catch (e) {
                assert(e.code === gpf.Error.CODE_ABSTRACT);
                assert(e.code === gpf.Error.abstract.CODE);
                assert(e.name === "abstract");
                assert(e.message === "Abstract");
            }
        });

        it("can use substitution for message", function () {
            try {
                throw gpf.Error.assertionFailed({
                    message: "Test"
                });
            } catch (e) {
                assert(e instanceof gpf.Error);
                assert(e.code === gpf.Error.CODE_ASSERTIONFAILED);
                assert(e.code === gpf.Error.assertionFailed.CODE);
                assert(e.name === "assertionFailed");
                assert(e.message === "Assertion failed: Test");
            }
        });

    });

});
<commit_msg>ESLint fixes<commit_after>"use strict";
/*jshint mocha: true*/
/*eslint-env mocha*/
/*global assert*/

describe("error", function () {

    describe("gpf.Error", function () {

        it("is used as an exception", function () {
            try {
                throw gpf.Error.abstractMethod();
            } catch (e) {
                assert(e instanceof gpf.Error);
                assert(e.constructor === gpf.Error);
            }
        });

        it("is documented", function () {
            try {
                throw gpf.Error.abstractMethod();
            } catch (e) {
                assert(e.code === gpf.Error.CODE_ABSTRACTMETHOD);
                assert(e.code === gpf.Error.abstractMethod.CODE);
                assert(e.name === "abstractMethod");
                assert(e.message === "Abstract method");
            }
        });

        it("can use substitution for message", function () {
            try {
                throw gpf.Error.assertionFailed({
                    message: "Test"
                });
            } catch (e) {
                assert(e instanceof gpf.Error);
                assert(e.code === gpf.Error.CODE_ASSERTIONFAILED);
                assert(e.code === gpf.Error.assertionFailed.CODE);
                assert(e.name === "assertionFailed");
                assert(e.message === "Assertion failed: Test");
            }
        });

    });

});
<|endoftext|>


<commit_before>'use strict';

// Plaits
var Plaits = require('../index');

// Promise
var Promise = require('bluebird');

/**
 * ProfileForm Declaration
 */
var ProfileForm = Plaits.Model.extend({
    name: 'profileForm',
    fields: [
        'avatar'
    ],
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.minSize('100kB'),
            Plaits.Validators.File.maxSize('200kB'),
            Plaits.Validators.File.mimeTypes([
                'image/jpg',
                'image/jpeg',
                'image/png',
                'image/gif'
            ])
        ]
    }
});

/**
 * Profile Form with Wildcard Regex
 */
var ProfileFormWildCardRegex = ProfileForm.extend({
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.minSize('100kB'),
            Plaits.Validators.File.maxSize('200kB'),
            Plaits.Validators.File.mimeTypes([
                'image/*'
            ])
        ]
    }
});

/**
 * Profile Form with Enforced MIME Type Matching
 */
var ProfileFormEnforceMimeType = ProfileForm.extend({
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.enforceMimeMatch()
        ]
    }
});

/**
 * File Upload Good Values
 */
var fileGoodValuesRequestStub = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 162258, type: 'image/png'}}};
var fileGoodValuesRequestStubCorrectMimeInspect = {files: {profileForm_avatar: {name: 'plaits.png', originalFilename: 'plaits.png', path: 'test/files/plaits.png', size: 166258, type: 'image/png'}}};

/**
 * File Upload Bad Values
 */
var filesBadValueRequestStubNoFile = {files: {profileForm_avatar: {name: '', originalFilename: '', path: '/var/tmp/', size: 0, type: 'application/octet-stream'}}};
var filesBadValueRequestStubTooSmall = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 66258, type: 'image/jpeg'}}};
var filesBadValueRequestStubTooLarge = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 3145728, type: 'image/jpeg'}}};
var filesBadValueRequestStubInvalidType = {files: {profileForm_avatar: {name: 'you.zip', originalFilename: 'you.zip', path: '/var/tmp/9911-lpnc5.zip', size: 166258, type: 'application/zip'}}};
var fileGoodValuesRequestStubIncorrectMimeInspect = {files: {profileForm_avatar: {name: 'plaits.jpg', originalFilename: 'plaits.jpg', path: 'test/files/plaits.jpg', size: 166258, type: 'image/jpeg'}}};

/**
 * Plaits File Tests
 */
describe('Plaits File Validators', function () {

    /**
     * Required - Valid
     */
    it('should validate good required file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Required - Invalid
     */
    it('should invalidate bad required file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubNoFile).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar is a required field.');
        }).then(done, done);
    });

    /**
     * Min Size - Valid
     */
    it('should validate good minimum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Min Size - Invalid
     */
    it('should invalidate bad minimum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubTooSmall).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Error Message
            this.getErrors('avatar').should.containEql('Avatar must be at least 100kB.');
        }).then(done, done);
    });

    /**
     * Max Size - Valid
     */
    it('should validate good maximum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Max Size - Invalid
     */
    it('should invalidate bad maximum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubTooLarge).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Error Message
            this.getErrors('avatar').should.containEql('Avatar must be smaller than 200kB.');
        }).then(done, done);
    });

    /**
     * Mime Type - Valid
     */
    it('should validate good mime types on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Mime Type - Invalid
     */
    it('should invalidate bad mime types on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubInvalidType).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar must be one of the following file types: image/jpg, image/jpeg, image/png, image/gif.');
        }).then(done, done);
    });

    /**
     * Mime Type Wildcard - Valid
     */
    it('should validate good mime types on file uploads when a wildcard regex is given', function (done) {
        new ProfileFormWildCardRegex().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Mime Type Wildcard - Invalid
     */
    it('should invalidate bad mime types on file uploads when a wildcard regex is given', function (done) {
        new ProfileFormWildCardRegex().parseRequestSync(filesBadValueRequestStubInvalidType).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar must be one of the following file types: image/*.');
        }).then(done, done);
    });

    /**
     * Enforce MIME Match - Valid
     */
    it('should validate good mime matches on file uploads', function (done) {
        new ProfileFormEnforceMimeType().parseRequestSync(fileGoodValuesRequestStubCorrectMimeInspect).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Enforce MIME Match - Invalid
     */
    it('should invalidate bad mime matches on file uploads', function (done) {
        new ProfileFormEnforceMimeType().parseRequestSync(fileGoodValuesRequestStubIncorrectMimeInspect).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('The MIME Type of Avatar does not match its contents.');
        }).then(done, done);
    });
});<commit_msg>Promise rejection test<commit_after>'use strict';

// Plaits
var Plaits = require('../index');

// Promise
var Promise = require('bluebird');

/**
 * ProfileForm Declaration
 */
var ProfileForm = Plaits.Model.extend({
    name: 'profileForm',
    fields: [
        'avatar'
    ],
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.minSize('100kB'),
            Plaits.Validators.File.maxSize('200kB'),
            Plaits.Validators.File.mimeTypes([
                'image/jpg',
                'image/jpeg',
                'image/png',
                'image/gif'
            ])
        ]
    }
});

/**
 * Profile Form with Wildcard Regex
 */
var ProfileFormWildCardRegex = ProfileForm.extend({
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.minSize('100kB'),
            Plaits.Validators.File.maxSize('200kB'),
            Plaits.Validators.File.mimeTypes('image/*')
        ]
    }
});

/**
 * Profile Form with Enforced MIME Type Matching
 */
var ProfileFormEnforceMimeType = ProfileForm.extend({
    validators: {
        avatar: [
            Plaits.Validators.File.required(),
            Plaits.Validators.File.enforceMimeMatch()
        ]
    }
});

/**
 * File Upload Good Values
 */
var fileGoodValuesRequestStub = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 162258, type: 'image/png'}}};
var fileGoodValuesRequestStubCorrectMimeInspect = {files: {profileForm_avatar: {name: 'plaits.png', originalFilename: 'plaits.png', path: 'test/files/plaits.png', size: 166258, type: 'image/png'}}};

/**
 * File Upload Bad Values
 */
var filesBadValueRequestStubNoFile = {files: {profileForm_avatar: {name: '', originalFilename: '', path: '/var/tmp/', size: 0, type: 'application/octet-stream'}}};
var filesBadValueRequestStubTooSmall = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 66258, type: 'image/jpeg'}}};
var filesBadValueRequestStubTooLarge = {files: {profileForm_avatar: {name: 'me.jpg', originalFilename: 'me.jpg', path: '/var/tmp/9911-lpnc4.jpg', size: 3145728, type: 'image/jpeg'}}};
var filesBadValueRequestStubInvalidType = {files: {profileForm_avatar: {name: 'you.zip', originalFilename: 'you.zip', path: '/var/tmp/9911-lpnc5.zip', size: 166258, type: 'application/zip'}}};
var fileGoodValuesRequestStubIncorrectMimeInspect = {files: {profileForm_avatar: {name: 'plaits.jpg', originalFilename: 'plaits.jpg', path: 'test/files/plaits.jpg', size: 166258, type: 'image/jpeg'}}};

/**
 * File Upload Reject Promise
 */
var fileGoodValuesRequestStubPromiseReject = {files: {profileForm_avatar: {name: 'plaits-logo.jpg', originalFilename: 'plaits-logo.jpg', path: 'test/files/plaits-logo.jpg', size: 166258, type: 'image/jpeg'}}};

/**
 * Plaits File Tests
 */
describe('Plaits File Validators', function () {

    /**
     * Required - Valid
     */
    it('should validate good required file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Required - Invalid
     */
    it('should invalidate bad required file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubNoFile).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar is a required field.');
        }).then(done, done);
    });

    /**
     * Min Size - Valid
     */
    it('should validate good minimum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Min Size - Invalid
     */
    it('should invalidate bad minimum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubTooSmall).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Error Message
            this.getErrors('avatar').should.containEql('Avatar must be at least 100kB.');
        }).then(done, done);
    });

    /**
     * Max Size - Valid
     */
    it('should validate good maximum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Max Size - Invalid
     */
    it('should invalidate bad maximum size on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubTooLarge).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Error Message
            this.getErrors('avatar').should.containEql('Avatar must be smaller than 200kB.');
        }).then(done, done);
    });

    /**
     * Mime Type - Valid
     */
    it('should validate good mime types on file uploads', function (done) {
        new ProfileForm().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Mime Type - Invalid
     */
    it('should invalidate bad mime types on file uploads', function (done) {
        new ProfileForm().parseRequestSync(filesBadValueRequestStubInvalidType).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar must be one of the following file types: image/jpg, image/jpeg, image/png, image/gif.');
        }).then(done, done);
    });

    /**
     * Mime Type Wildcard - Valid
     */
    it('should validate good mime types on file uploads when a wildcard regex is given', function (done) {
        new ProfileFormWildCardRegex().parseRequestSync(fileGoodValuesRequestStub).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Mime Type Wildcard - Invalid
     */
    it('should invalidate bad mime types on file uploads when a wildcard regex is given', function (done) {
        new ProfileFormWildCardRegex().parseRequestSync(filesBadValueRequestStubInvalidType).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('Avatar must be one of the following file types: image/*.');
        }).then(done, done);
    });

    /**
     * Enforce MIME Match - Valid
     */
    it('should validate good mime matches on file uploads', function (done) {
        new ProfileFormEnforceMimeType().parseRequestSync(fileGoodValuesRequestStubCorrectMimeInspect).validate().then(function (result) {
            // Check Result
            result.should.equal(true);
        }).then(done, done);
    });

    /**
     * Enforce MIME Match - Invalid
     */
    it('should invalidate bad mime matches on file uploads', function (done) {
        new ProfileFormEnforceMimeType().parseRequestSync(fileGoodValuesRequestStubIncorrectMimeInspect).validate().then(function (result) {
            // Check Result
            result.should.equal(false);
            // Check Error
            this.getErrors('avatar').should.containEql('The MIME Type of Avatar does not match its contents.');
        }).then(done, done);
    });

    /**
     * Enforce MIME Match - Exception - Promise Rejection
     */
    it('should reject the promise if there is an issue with LibMagic', function (done) {
        new ProfileFormEnforceMimeType().parseRequestSync(fileGoodValuesRequestStubPromiseReject).validate().then().catch(function (error) {
            error.message.should.startWith('cannot stat');
        }).then(done, done);
    });
});<|endoftext|>


<commit_before>const fs = require('fs-extra')
const path = require('path-extra')
const assert = require('assert')
const utils = require('../lib/utils')
const ROOT = path.join(__dirname, '..')

const flashPath = (() => {
  switch (process.platform) {
  case 'darwin':
    return path.join(ROOT, 'PepperFlash', `mac-${process.arch}`, 'PepperFlashPlayer.plugin')
  case 'win32':
    return path.join(ROOT, 'PepperFlash', `win-${process.arch}`, 'pepflashplayer.dll')
  case 'linux':
    return path.join(ROOT, 'PepperFlash', `linux-${process.arch}`, 'libpepflashplayer.so')
  }
})()

const checkFlash = () => {
  try {
    fs.accessSync(flashPath, fs.R_OK | fs.W_OK)
    return true
  } catch (e) {
    return false
  }
}

describe('Flash', () => {
  it('should exist', () => {
    assert.equal(checkFlash(), true)
  })
})
<commit_msg>Simplify test<commit_after>const fs = require('fs-extra')
const path = require('path-extra')
const assert = require('assert')
const utils = require('../lib/utils')
const ROOT = path.join(__dirname, '..')

const flashPath = (() => {
  switch (process.platform) {
  case 'darwin':
    return path.join(ROOT, 'PepperFlash', `mac-${process.arch}`, 'PepperFlashPlayer.plugin')
  case 'win32':
    return path.join(ROOT, 'PepperFlash', `win-${process.arch}`, 'pepflashplayer.dll')
  case 'linux':
    return path.join(ROOT, 'PepperFlash', `linux-${process.arch}`, 'libpepflashplayer.so')
  }
})()

describe('Flash', () => {
  it('should exist', () => {
    fs.accessSync(flashPath, fs.R_OK | fs.W_OK)
  })
})
<|endoftext|>


<commit_before>/**
 * Copyright 2015 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var LoginPageView = Backbone.View.extend({

    initialize: function(options) {
        this.options = options || {};
        this.defaults = _.clone(this.defaults);
        this.el = options.el;
        this.render();
        this.addHandlers();
    },

    addHandlers: function() {
        var self = this;

        $('.login-form').on('submit', function(e) {
            e.preventDefault();
            self.submitLogin($(this).serialize());
        });
    },

    submitLogin: function(input) {
        var self = this;

        // Upon clicking the submit button, the serialized user input is sent
        // via $.post to check the credentials. If successful, invoke "done"
        // if not, invoke "fail"

        $.post('/accounts/login', input, function() {})
            .done(function(success) {

                // store the auth token
                self.storeAuthToken(success.auth_token);

                // and add a message to the top of the screen that logs what
                // is returned from the call
                goldstone.raiseInfo('Authorization Successful, redirecting to goldstone', true);
                self.redirectPostSuccessfulAuth();
            })
            .fail(function(fail) {

                // and add a message to the top of the screen that logs what
                // is returned from the call
                goldstone.raiseInfo(fail.responseJSON.non_field_errors[0], true);
            });
    },

    storeAuthToken: function(token) {
        localStorage.setItem('userToken', token);
    },

    redirectPostSuccessfulAuth: function() {

        // if there was a previously visited page that
        // had redirected to the login page due to lack
        // of credentials, redirect back to that page
        if (location.hash && location.hash.length > 0) {
            locationhref = '/' + location.hash.slice(1);
        } else {

            // or just redirect to /discover
            locationhref = '/';
        }

        location.href = locationhref;

    },

    render: function() {
        this.$el.html(this.template());
        return this;
    },

    template: _.template('' +
        '
' +
        '
' +
        '
' +
        '
' +
        '
Goldstone
' +
        '
' +
        '<form class="login-form">' +
        '
Please sign in
' +
        'Username' +
        '<input name="username" type="text" class="form-control" placeholder="Username" required autofocus>' +
        'Password' +
        '<input name="password" type="password" class="form-control" placeholder="Password" required>
' +
        '<button name="submit" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>' +
        '</form>' +
        '
forgot username or password?
' +
        '
' +
        '
' +
        '
'
    )

});
<commit_msg>Adds cosmetic changes to loginPageView to match new passwordResetView.<commit_after>/**
 * Copyright 2015 Solinea, Inc.
 *
 * Licensed under the Solinea Software License Agreement (goldstone),
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *     http://www.solinea.com/goldstone/LICENSE.pdf
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var LoginPageView = Backbone.View.extend({

    initialize: function(options) {
        this.options = options || {};
        this.defaults = _.clone(this.defaults);
        this.el = options.el;
        this.render();
        this.addHandlers();
    },

    addHandlers: function() {
        var self = this;

        $('.login-form').on('submit', function(e) {
            e.preventDefault();
            self.submitRequest($(this).serialize());
        });
    },

    submitRequest: function(input) {
        var self = this;

        // Upon clicking the submit button, the serialized user input is sent
        // via $.post to check the credentials. If successful, invoke "done"
        // if not, invoke "fail"

        $.post('/accounts/login', input, function() {})
            .done(function(success) {

                // store the auth token
                self.storeAuthToken(success.auth_token);

                // and add a message to the top of the screen that logs what
                // is returned from the call
                goldstone.raiseInfo('Authorization Successful, redirecting to goldstone', true);
                self.redirectPostSuccessfulAuth();
            })
            .fail(function(fail) {
                // and add a message to the top of the screen that logs what
                // is returned from the call
                goldstone.raiseInfo(fail.responseJSON.non_field_errors[0], true);
            });
    },

    storeAuthToken: function(token) {
        localStorage.setItem('userToken', token);
    },

    redirectPostSuccessfulAuth: function() {

        // if there was a previously visited page that
        // had redirected to the login page due to lack
        // of credentials, redirect back to that page
        if (location.hash && location.hash.length > 0) {
            locationhref = '/' + location.hash.slice(1);
        } else {

            // or just redirect to /discover
            locationhref = '/';
        }

        location.href = locationhref;

    },

    render: function() {
        this.$el.html(this.template());
        return this;
    },

    template: _.template('' +
        '
' +
        '
' +
        '
' +
        '<form class="login-form">' +
        '
Please sign in
' +
        'Username' +
        '<input name="username" type="text" class="form-control" placeholder="Username" required autofocus>' +
        'Password' +
        '<input name="password" type="password" class="form-control" placeholder="Password" required>
' +
        '<button name="submit" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>' +
        '</form>' +
        '
Forgot username or password?
' +
        '
' +
        '
' +
        '
'
    )

});
<|endoftext|>


<commit_before>var levelup = require('level-test')()
var sublevel = require('level-sublevel')
var assert = require('assert')

var mac     = require('macgyver')().autoValidate()
var Trigger = require('..')

var db = sublevel(levelup('level-trigger-test'))

var reduceDb = db.sublevel('reduce')
var reduced = 0

var trigDb = Trigger(db, 'test-trigger', function (item) {
    //map
    console.log('MAP', JSON.stringify({
      key: ''+item.key,
      type: item.type
    }))
    var obj = item.value ? JSON.parse(item.value) : null
    return JSON.stringify({
      key: ''+item.key,
      type: item.type
    })
  },
  function (value, done) {
    value = JSON.parse(value)

    function reduce (acc, n, put) {
      return (acc || 0) + (put ? 1 : -1)
    }

    var put = value.type == 'put'

    console.log('reduced', reduced, value)
    reduced = reduce(reduced, value, put)
    reduceDb.put('reduced', JSON.stringify(reduced), done)
    db.emit('test:reduce', reduced)
  })

var _done = false
trigDb.on('complete', mac(function (k, n) {
  _done = true
  console.log('jobs finished')
}).atLeast(1))

//if we don't wait for the queue to drain,
//then it will read puts from these twice.
//TODO: add snapshot option for leveldb.

db.put('hello-A', JSON.stringify({thing: 1}))
db.put('hello-B', JSON.stringify({thing: 2}))
db.put('hello-C', JSON.stringify({thing: 3}))
db.put('hello-D', JSON.stringify({thing: 6}))
db.del('hello-C')

var i = setInterval(function () {
  assert.equal(typeof trigDb.isComplete(), 'boolean')
  if(trigDb.isComplete())
    clearInterval(i)
}, 20)

db.on('test:reduce', mac().times(5))

process.on('exit', function () {
  assert.equal(_done, true)
})

<commit_msg>work-around in test :(<commit_after>var levelup = require('level-test')()
var sublevel = require('level-sublevel')
var assert = require('assert')

var mac     = require('macgyver')().autoValidate()
var Trigger = require('..')

var db = sublevel(levelup('level-trigger-test'))

var reduceDb = db.sublevel('reduce')
var reduced = 0

var trigDb = Trigger(db, 'test-trigger', function (item) {
    //map
    console.log('MAP', JSON.stringify({
      key: ''+item.key,
      type: item.type
    }))
    var obj = item.value ? JSON.parse(item.value) : null
    return JSON.stringify({
      key: ''+item.key,
      type: item.type
    })
  },
  function (value, done) {
    value = JSON.parse(value)

    function reduce (acc, n, put) {
      return (acc || 0) + (put ? 1 : -1)
    }

    var put = value.type == 'put'

    console.log('reduced', reduced, value)
    reduced = reduce(reduced, value, put)
    reduceDb.put('reduced', JSON.stringify(reduced), done)
    db.emit('test:reduce', reduced)
  })

var _done = false
trigDb.on('complete', mac(function (k, n) {
  _done = true
  console.log('jobs finished')
}).atLeast(1))

//if we don't wait for the queue to drain,
//then it will read puts from these twice.
//TODO: add snapshot option for leveldb.

//THIS IS UGLY AND BAD.

// TESTS SHOULD NOT HAVE A SETTIMEOUT IN THEM.
// However, this is a racecondition that only breaks
// during the tests. basically, the prehook triggers
// for the puts that are created before the database
// is opened, but also the readstream that recovers
// incomplete jobs processes some things.
// this needs to be fixed in either levelup or level-sublevel.

setTimeout(function () {

  db.put('hello-A', JSON.stringify({thing: 1}))
  db.put('hello-B', JSON.stringify({thing: 2}))
  db.put('hello-C', JSON.stringify({thing: 3}))
  db.put('hello-D', JSON.stringify({thing: 6}))
  db.del('hello-C')

  var i = setInterval(function () {
    assert.equal(typeof trigDb.isComplete(), 'boolean')
    if(trigDb.isComplete())
      clearInterval(i)
  }, 20)

}, 200)

db.on('test:reduce', mac().times(5))

process.on('exit', function () {
  assert.equal(_done, true)
})

<|endoftext|>


<commit_before>// Look up URLs in SURBL
var url       = require('url');
var dns       = require('dns');
var isIPv4    = require('net').isIPv4;
var net_utils = require('./net_utils.js');

// Default regexps to extract the URIs from the message
var numeric_ip = /\w{3,16}:\/+(\S+@)?(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)/gi;
var schemeless = /((?:www\.)?[a-zA-Z0-9][a-zA-Z0-9\-.]{,250}\.(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-zA-Z]{2}))(?!\w)/gi;
var schemed    = /(\w{3,16}:\/+(?:\S+@)?([a-zA-Z0-9][a-zA-Z0-9\-.]+\.(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-zA-Z]{2})))(?!\w)/gi;

var lists;
var zones;
var excludes = {};

function check_excludes_list(host) {
    host = host.toLowerCase().split('.').reverse();
    for (var i=0; i < host.length; i++) {
        if (i === 0) {
            var check = host[i];
        }
        else {
            check = [ host[i], check ].join('.');
        }
        if (excludes[check]) {
            return true;
        }
    }
    return false;
}

exports.register = function() {
    // Override regexps if top_level_tlds file is present
    if (net_utils.top_level_tlds && Object.keys(net_utils.top_level_tlds).length) {
        this.logdebug('Building new regexps from TLD file');
        var re_schemeless = '((?:www\\.)?[a-zA-Z0-9][a-zA-Z0-9\\-.]{,250}\\.(?:' +
            Object.keys(net_utils.top_level_tlds).join('|') + '))(?!\\w)';
        schemeless = new RegExp(re_schemeless, 'gi');
        var re_schemed = '(\\w{3,16}:\\/+(?:\\S+@)?([a-zA-Z0-9][a-zA-Z0-9\\-.]+\\.(?:' +
            Object.keys(net_utils.top_level_tlds).join('|') + ')))(?!\\w)';
        schemed = new RegExp(re_schemed, 'gi');
    }
}

exports.load_uri_config = function (next) {
    lists = this.config.get('data.uribl.ini');
    zones = Object.keys(lists);
    if (!zones || !zones.length > 1) {
        this.logerr('aborting: no zones configured');
        return next();
    }
    // Load excludes
    this.config.get('data.uribl.excludes', 'list').forEach(function (domain) {
        excludes[domain.toLowerCase()] = 1;
    });
    // Set defaults
    if (lists.main && !lists.main.max_uris_per_list) {
        lists.main.max_uris_per_list = 20;
    }
}

exports.do_lookups = function (connection, next, hosts, type) {
    var plugin = this;

    if (typeof hosts === 'string') {
        hosts = [ hosts ];
    }
    if (!hosts || (hosts && !hosts.length)) {
        connection.logdebug(plugin, '(' + type + ') no items found for lookup');
        return next();
    }
    else {
        connection.logdebug(plugin, '(' + type + ') found ' + hosts.length + ' items for lookup');
    }
    var queries = {};
    for (var i=0; i < hosts.length; i++) {
        var host = hosts[i].toLowerCase();
        connection.logdebug(plugin, '(' + type + ') checking: ' + host);
        // Make sure we have a valid TLD
        if (!isIPv4(host) && !net_utils.top_level_tlds[(host.split('\.').reverse())[0]]) {
            continue;
        }
        // Check the exclusion list
        if (check_excludes_list(host)) {
            connection.logdebug(plugin, 'skipping excluded domain:' + host);
            continue;
        }
        // Loop through the zones
        for (var j=0; j < zones.length; j++) {
            var zone = zones[j];
            if (zone === 'main') continue;  // skip config
            if (!lists[zone] || (lists[zone] && !/^(?:1|true|yes|enabled|on)$/i.test(lists[zone][type]))) {
                connection.logdebug(plugin, 'skipping zone ' + zone + ' as it does not support lookup type ' + type);
                continue;
            }
            // Convert in-addr.arpa into bare IPv4 lookup
            var arpa = host.split(/\./).reverse();
            if (arpa.shift() === 'arpa' && arpa.shift() === 'in-addr') {
                if (arpa.length < 4) continue; // Only full IP addresses
                host = arpa.join('.');
            }
            var lookup;
            // Handle zones that do not allow IP queries (e.g. Spamhaus DBL)
            if (isIPv4(host)) {
                if (/^(?:1|true|yes|enabled|on)$/i.test(lists[zone].no_ip_lookups)) {
                    connection.logdebug(plugin, 'skipping IP lookup (' + host + ') for zone ' + zone);
                    continue;
                }
                // Skip any private IPs
                if (net_utils.is_rfc1918(host)) continue;
                // Reverse IP for lookup
                lookup = host.split(/\./).reverse().join('.');
            }
            // Handle zones that require host to be stripped to a domain boundary
            else if (/^(?:1|true|yes|enabled|on)$/i.test(lists[zone].strip_to_domain)) {
                lookup = (net_utils.split_hostname(host, 3))[1];
            }
            // Anything else..
            else {
                lookup = host;
            }
            if (!lookup) continue;
            if (!queries[zone]) queries[zone] = {};
            if (Object.keys(queries[zone]).length > lists.main.max_uris_per_list) {
                connection.logwarn(plugin, 'discarding lookup ' + lookup + ' for zone ' +
                              zone + ' maximum query limit reached');
                continue;
            }
            queries[zone][lookup] = 1;
        }
    }

    // Flatten object into array for easier querying
    var queries_to_run = [];
    for (var j=0; j < Object.keys(queries).length; j++) {
        for (var k=0; k < Object.keys(queries[Object.keys(queries)[j]]).length; k++) {
            // host/domain, zone
            queries_to_run.push( [ Object.keys(queries[Object.keys(queries)[j]])[k], Object.keys(queries)[j] ] );
        }
    }
    // Randomize the order a bit
    queries_to_run.sort(Math.round(Math.random())-0.25);

    if(!queries_to_run.length) {
        return next();
    }

    // Perform the lookups
    var plugin = this;
    var pending_queries = 0;
    var called_next = false;

    var timer = setTimeout(function () {
        connection.logdebug(plugin, 'timeout');
        if (!called_next) {
            called_next = true;
            return next();
        }
    }, ((lists.main && lists.main.timeout) ?
        lists.main.timeout : 30) * 1000);

    queries_to_run.forEach(function (query) {
        var lookup = query.join('.');
        // Add root dot if necessary
        if (lookup[lookup.length-1] !== '.') {
            lookup = lookup + '.';
        }
        pending_queries++;
        dns.resolve4(lookup, function(err, addrs) {
            pending_queries--;
            connection.logdebug(plugin, lookup + ' => ' + ((err) ? err : addrs.join(', ')));
            if (!err && !called_next) {
                var skip = false;
                var do_reject = function (msg) {
                    if (!skip && !called_next) {
                        if (!msg) {
                            msg = query[0] + ' blacklisted in ' + query[1];
                        }
                        // Check for custom message
                        if (lists[query[1]] && lists[query[1]].custom_msg) {
                            msg = lists[query[1]].custom_msg.replace(/\{uri\}/g, query[0]).replace(/\{zone\}/g, query[1]);
                        }
                        clearTimeout(timer);
                        called_next = true;
                        return next(DENY, msg);
                    }
                }
                // Optionally validate first result against a regexp
                if (lists[query[1]] && lists[query[1]].validate) {
                    var re = new RegExp(lists[query[1]].validate);
                    if (!re.test(addrs[0])) {
                        connection.logdebug(plugin, 'ignoring result (' + addrs[0] + ') for: ' +
                                lookup + ' as it did not match validation rule');
                        var skip = true;
                    }
                }
                // Check for optional bitmask
                if (lists[query[1]] && lists[query[1]].bitmask) {
                    // A bitmask zone should only return a single result
                    // We only support a bitmask of up to 128 in a single octet
                    var last_octet = new Number((addrs[0].split('.'))[3]);
                    var bitmask = new Number(lists[query[1]].bitmask);
                    if ((last_octet & bitmask) > 0) {
                        connection.loginfo(plugin, 'found ' + query[0] + ' in zone ' + query[1] +
                            ' (' + addrs.join(',') + '; bitmask=' + bitmask + ')');
                        do_reject();
                    } else {
                        connection.logdebug(plugin, 'ignoring result (' + addrs[0] + ') for: ' +
                                lookup + ' as the bitmask did not match');
                        var skip = true;
                    }
                }
                else {
                    connection.loginfo(plugin, 'found ' + query[0] + ' in zone ' + query[1] +
                        ' (' + addrs.join(',') + ')');
                    do_reject();
                }
            }
            if (!called_next && pending_queries === 0) {
                clearTimeout(timer);
                return next();
            }
        });
    });

    if (pending_queries === 0) {
        return next();
    }
}

exports.hook_lookup_rdns = function (next, connection) {
    this.load_uri_config(next);
    var plugin = this;
    dns.reverse(connection.remote_ip, function (err, rdns) {
        if (err) return next();
        plugin.do_lookups(connection, next, rdns, 'rdns');
    });
}

exports.hook_ehlo = function (next, connection, helo) {
    this.load_uri_config(next);
    // Handle IP literals
    var literal;
    if ((literal = /^\[(\d+\.\d+\.\d+\.\d+)\]$/.exec(helo))) {
        this.do_lookups(connection, next, literal[1], 'helo');
    } else {
        this.do_lookups(connection, next, helo, 'helo');
    }
}
exports.hook_helo = exports.hook_ehlo;

exports.hook_mail = function (next, connection, params) {
    this.load_uri_config(next);
    this.do_lookups(connection, next, params[0].host, 'envfrom');
}

exports.hook_data = function (next, connection) {
    // enable mail body parsing
    connection.transaction.parse_body = 1;
    return next();
}

exports.hook_data_post = function (next, connection) {
    this.load_uri_config(next);
    var email_re = /<?[^@]+@([^> ]+)>?/;
    var plugin = this;
    var trans = connection.transaction;

    // From header
    var do_from_header = function (cb) {
        var from = trans.header.get('from');
        var fmatch;
        if (fmatch = email_re.exec(from)) {
            return plugin.do_lookups(connection, cb, fmatch[1], 'from');
        }
        cb();
    }

    // Reply-To header
    var do_replyto_header = function (cb) {
        var replyto = trans.header.get('reply-to');
        var rmatch;
        if (rmatch = email_re.exec(replyto)) {
            return plugin.do_lookups(connection, cb, rmatch[1], 'replyto');
        }
        cb();
    }

    // Message-Id header
    var do_msgid_header = function (cb) {
        var msgid = trans.header.get('message-id');
        var mmatch;
        if (mmatch = /@([^>]+)>/.exec(msgid)) {
            return plugin.do_lookups(connection, cb, mmatch[1], 'msgid');
        }
        cb();
    }

    // Body
    var do_body = function (cb) {
        var urls = {};
        extract_urls(urls, trans.body, connection, plugin);
        return plugin.do_lookups(connection, cb, Object.keys(urls), 'body');
    }

    var chain = [ do_from_header, do_replyto_header, do_msgid_header, do_body ];
    var chain_caller = function (code, msg) {
        if (code) {
            return next(code, msg);
        }
        if (!chain.length) {
            return next();
        }
        var next_in_chain = chain.shift();
        next_in_chain(chain_caller);
    }
    chain_caller();
}

function extract_urls (urls, body, connection, self) {
    // extract from body.bodytext
    var match;

    // extract numeric URIs
    while (match = numeric_ip.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse(match[0]);
            // Don't reverse the IPs here; we do it in the lookup
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[0] +
                                      ' ' + error.message);
        }
    }

    // match plain hostname.tld
    while (match = schemeless.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse('http://' + match[1]);
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[1] +
                                      ' ' + error.message);
        }
    }

    // match scheme:// URI
    while (match = schemed.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse(match[1]);
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[1] +
                                      ' ' + error.message);
        }
    }

    // TODO: URIHASH
    // TODO: MAILHASH

    for (var i=0,l=body.children.length; i < l; i++) {
        extract_urls(urls, body.children[i], connection, self);
    }
}
<commit_msg>Fix regex in data.uribl.js<commit_after>// Look up URLs in SURBL
var url       = require('url');
var dns       = require('dns');
var isIPv4    = require('net').isIPv4;
var net_utils = require('./net_utils.js');

// Default regexps to extract the URIs from the message
var numeric_ip = /\w{3,16}:\/+(\S+@)?(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)\.(\d+|0[xX][0-9A-Fa-f]+)/gi;
var schemeless = /((?:www\.)?[a-zA-Z0-9][a-zA-Z0-9\-.]{0,250}\.(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-zA-Z]{2}))(?!\w)/gi;
var schemed    = /(\w{3,16}:\/+(?:\S+@)?([a-zA-Z0-9][a-zA-Z0-9\-.]+\.(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-zA-Z]{2})))(?!\w)/gi;

var lists;
var zones;
var excludes = {};

function check_excludes_list(host) {
    host = host.toLowerCase().split('.').reverse();
    for (var i=0; i < host.length; i++) {
        if (i === 0) {
            var check = host[i];
        }
        else {
            check = [ host[i], check ].join('.');
        }
        if (excludes[check]) {
            return true;
        }
    }
    return false;
}

exports.register = function() {
    // Override regexps if top_level_tlds file is present
    if (net_utils.top_level_tlds && Object.keys(net_utils.top_level_tlds).length) {
        this.logdebug('Building new regexps from TLD file');
        var re_schemeless = '((?:www\\.)?[a-zA-Z0-9][a-zA-Z0-9\\-.]{0,250}\\.(?:' +
            Object.keys(net_utils.top_level_tlds).join('|') + '))(?!\\w)';
        schemeless = new RegExp(re_schemeless, 'gi');
        var re_schemed = '(\\w{3,16}:\\/+(?:\\S+@)?([a-zA-Z0-9][a-zA-Z0-9\\-.]+\\.(?:' +
            Object.keys(net_utils.top_level_tlds).join('|') + ')))(?!\\w)';
        schemed = new RegExp(re_schemed, 'gi');
    }
}

exports.load_uri_config = function (next) {
    lists = this.config.get('data.uribl.ini');
    zones = Object.keys(lists);
    if (!zones || !zones.length > 1) {
        this.logerr('aborting: no zones configured');
        return next();
    }
    // Load excludes
    this.config.get('data.uribl.excludes', 'list').forEach(function (domain) {
        excludes[domain.toLowerCase()] = 1;
    });
    // Set defaults
    if (lists.main && !lists.main.max_uris_per_list) {
        lists.main.max_uris_per_list = 20;
    }
}

exports.do_lookups = function (connection, next, hosts, type) {
    var plugin = this;

    if (typeof hosts === 'string') {
        hosts = [ hosts ];
    }
    if (!hosts || (hosts && !hosts.length)) {
        connection.logdebug(plugin, '(' + type + ') no items found for lookup');
        return next();
    }
    else {
        connection.logdebug(plugin, '(' + type + ') found ' + hosts.length + ' items for lookup');
    }
    var queries = {};
    for (var i=0; i < hosts.length; i++) {
        var host = hosts[i].toLowerCase();
        connection.logdebug(plugin, '(' + type + ') checking: ' + host);
        // Make sure we have a valid TLD
        if (!isIPv4(host) && !net_utils.top_level_tlds[(host.split('\.').reverse())[0]]) {
            continue;
        }
        // Check the exclusion list
        if (check_excludes_list(host)) {
            connection.logdebug(plugin, 'skipping excluded domain:' + host);
            continue;
        }
        // Loop through the zones
        for (var j=0; j < zones.length; j++) {
            var zone = zones[j];
            if (zone === 'main') continue;  // skip config
            if (!lists[zone] || (lists[zone] && !/^(?:1|true|yes|enabled|on)$/i.test(lists[zone][type]))) {
                connection.logdebug(plugin, 'skipping zone ' + zone + ' as it does not support lookup type ' + type);
                continue;
            }
            // Convert in-addr.arpa into bare IPv4 lookup
            var arpa = host.split(/\./).reverse();
            if (arpa.shift() === 'arpa' && arpa.shift() === 'in-addr') {
                if (arpa.length < 4) continue; // Only full IP addresses
                host = arpa.join('.');
            }
            var lookup;
            // Handle zones that do not allow IP queries (e.g. Spamhaus DBL)
            if (isIPv4(host)) {
                if (/^(?:1|true|yes|enabled|on)$/i.test(lists[zone].no_ip_lookups)) {
                    connection.logdebug(plugin, 'skipping IP lookup (' + host + ') for zone ' + zone);
                    continue;
                }
                // Skip any private IPs
                if (net_utils.is_rfc1918(host)) continue;
                // Reverse IP for lookup
                lookup = host.split(/\./).reverse().join('.');
            }
            // Handle zones that require host to be stripped to a domain boundary
            else if (/^(?:1|true|yes|enabled|on)$/i.test(lists[zone].strip_to_domain)) {
                lookup = (net_utils.split_hostname(host, 3))[1];
            }
            // Anything else..
            else {
                lookup = host;
            }
            if (!lookup) continue;
            if (!queries[zone]) queries[zone] = {};
            if (Object.keys(queries[zone]).length > lists.main.max_uris_per_list) {
                connection.logwarn(plugin, 'discarding lookup ' + lookup + ' for zone ' +
                              zone + ' maximum query limit reached');
                continue;
            }
            queries[zone][lookup] = 1;
        }
    }

    // Flatten object into array for easier querying
    var queries_to_run = [];
    for (var j=0; j < Object.keys(queries).length; j++) {
        for (var k=0; k < Object.keys(queries[Object.keys(queries)[j]]).length; k++) {
            // host/domain, zone
            queries_to_run.push( [ Object.keys(queries[Object.keys(queries)[j]])[k], Object.keys(queries)[j] ] );
        }
    }
    // Randomize the order a bit
    queries_to_run.sort(Math.round(Math.random())-0.25);

    if(!queries_to_run.length) {
        return next();
    }

    // Perform the lookups
    var plugin = this;
    var pending_queries = 0;
    var called_next = false;

    var timer = setTimeout(function () {
        connection.logdebug(plugin, 'timeout');
        if (!called_next) {
            called_next = true;
            return next();
        }
    }, ((lists.main && lists.main.timeout) ?
        lists.main.timeout : 30) * 1000);

    queries_to_run.forEach(function (query) {
        var lookup = query.join('.');
        // Add root dot if necessary
        if (lookup[lookup.length-1] !== '.') {
            lookup = lookup + '.';
        }
        pending_queries++;
        dns.resolve4(lookup, function(err, addrs) {
            pending_queries--;
            connection.logdebug(plugin, lookup + ' => ' + ((err) ? err : addrs.join(', ')));
            if (!err && !called_next) {
                var skip = false;
                var do_reject = function (msg) {
                    if (!skip && !called_next) {
                        if (!msg) {
                            msg = query[0] + ' blacklisted in ' + query[1];
                        }
                        // Check for custom message
                        if (lists[query[1]] && lists[query[1]].custom_msg) {
                            msg = lists[query[1]].custom_msg.replace(/\{uri\}/g, query[0]).replace(/\{zone\}/g, query[1]);
                        }
                        clearTimeout(timer);
                        called_next = true;
                        return next(DENY, msg);
                    }
                }
                // Optionally validate first result against a regexp
                if (lists[query[1]] && lists[query[1]].validate) {
                    var re = new RegExp(lists[query[1]].validate);
                    if (!re.test(addrs[0])) {
                        connection.logdebug(plugin, 'ignoring result (' + addrs[0] + ') for: ' +
                                lookup + ' as it did not match validation rule');
                        var skip = true;
                    }
                }
                // Check for optional bitmask
                if (lists[query[1]] && lists[query[1]].bitmask) {
                    // A bitmask zone should only return a single result
                    // We only support a bitmask of up to 128 in a single octet
                    var last_octet = new Number((addrs[0].split('.'))[3]);
                    var bitmask = new Number(lists[query[1]].bitmask);
                    if ((last_octet & bitmask) > 0) {
                        connection.loginfo(plugin, 'found ' + query[0] + ' in zone ' + query[1] +
                            ' (' + addrs.join(',') + '; bitmask=' + bitmask + ')');
                        do_reject();
                    } else {
                        connection.logdebug(plugin, 'ignoring result (' + addrs[0] + ') for: ' +
                                lookup + ' as the bitmask did not match');
                        var skip = true;
                    }
                }
                else {
                    connection.loginfo(plugin, 'found ' + query[0] + ' in zone ' + query[1] +
                        ' (' + addrs.join(',') + ')');
                    do_reject();
                }
            }
            if (!called_next && pending_queries === 0) {
                clearTimeout(timer);
                return next();
            }
        });
    });

    if (pending_queries === 0) {
        return next();
    }
}

exports.hook_lookup_rdns = function (next, connection) {
    this.load_uri_config(next);
    var plugin = this;
    dns.reverse(connection.remote_ip, function (err, rdns) {
        if (err) return next();
        plugin.do_lookups(connection, next, rdns, 'rdns');
    });
}

exports.hook_ehlo = function (next, connection, helo) {
    this.load_uri_config(next);
    // Handle IP literals
    var literal;
    if ((literal = /^\[(\d+\.\d+\.\d+\.\d+)\]$/.exec(helo))) {
        this.do_lookups(connection, next, literal[1], 'helo');
    } else {
        this.do_lookups(connection, next, helo, 'helo');
    }
}
exports.hook_helo = exports.hook_ehlo;

exports.hook_mail = function (next, connection, params) {
    this.load_uri_config(next);
    this.do_lookups(connection, next, params[0].host, 'envfrom');
}

exports.hook_data = function (next, connection) {
    // enable mail body parsing
    connection.transaction.parse_body = 1;
    return next();
}

exports.hook_data_post = function (next, connection) {
    this.load_uri_config(next);
    var email_re = /<?[^@]+@([^> ]+)>?/;
    var plugin = this;
    var trans = connection.transaction;

    // From header
    var do_from_header = function (cb) {
        var from = trans.header.get('from');
        var fmatch;
        if (fmatch = email_re.exec(from)) {
            return plugin.do_lookups(connection, cb, fmatch[1], 'from');
        }
        cb();
    }

    // Reply-To header
    var do_replyto_header = function (cb) {
        var replyto = trans.header.get('reply-to');
        var rmatch;
        if (rmatch = email_re.exec(replyto)) {
            return plugin.do_lookups(connection, cb, rmatch[1], 'replyto');
        }
        cb();
    }

    // Message-Id header
    var do_msgid_header = function (cb) {
        var msgid = trans.header.get('message-id');
        var mmatch;
        if (mmatch = /@([^>]+)>/.exec(msgid)) {
            return plugin.do_lookups(connection, cb, mmatch[1], 'msgid');
        }
        cb();
    }

    // Body
    var do_body = function (cb) {
        var urls = {};
        extract_urls(urls, trans.body, connection, plugin);
        return plugin.do_lookups(connection, cb, Object.keys(urls), 'body');
    }

    var chain = [ do_from_header, do_replyto_header, do_msgid_header, do_body ];
    var chain_caller = function (code, msg) {
        if (code) {
            return next(code, msg);
        }
        if (!chain.length) {
            return next();
        }
        var next_in_chain = chain.shift();
        next_in_chain(chain_caller);
    }
    chain_caller();
}

function extract_urls (urls, body, connection, self) {
    // extract from body.bodytext
    var match;

    // extract numeric URIs
    while (match = numeric_ip.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse(match[0]);
            // Don't reverse the IPs here; we do it in the lookup
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[0] +
                                      ' ' + error.message);
        }
    }

    // match plain hostname.tld
    while (match = schemeless.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse('http://' + match[1]);
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[1] +
                                      ' ' + error.message);
        }
    }

    // match scheme:// URI
    while (match = schemed.exec(body.bodytext)) {
        var uri;
        try {
            uri = url.parse(match[1]);
            urls[uri.hostname] = uri;
        }
        catch (error) {
            connection.logerror(self, 'parse error: ' + match[1] +
                                      ' ' + error.message);
        }
    }

    // TODO: URIHASH
    // TODO: MAILHASH

    for (var i=0,l=body.children.length; i < l; i++) {
        extract_urls(urls, body.children[i], connection, self);
    }
}
<|endoftext|>


<commit_before>window.onscroll = scrollheader;

function scrollheader() {
    var scrollx = document.body.scrollLeft
    var header = document.getElementById('topHeader')
    header.style.left = 0-scrollx+'px'
}

function selectResult(item, val, text) {
	window.location.href = ("http://www.thebluealliance.com" + val);

}

$(function() {
	// Fancybox
	$(".fancybox").fancybox();

	// Typeahead for search
	// Currently does a one-time JSON get that returns
	// the entire list of teams and events.
	// Can be optimized.
	$.getJSON('/_/typeahead', function(data) {
		$('.search-query').typeahead({
			// Used for when we implement a better typeahead solution
	    	/*ajax: {
		    	    url: '/typeahead',
		    	    method: 'get',
		    	    triggerLength: 3,
		    },*/
			source: data,
	    	itemSelected: selectResult
	    });
	});
});<commit_msg>only get json on focus<commit_after>window.onscroll = scrollheader;

function scrollheader() {
    var scrollx = document.body.scrollLeft
    var header = document.getElementById('topHeader')
    header.style.left = 0-scrollx+'px'
}

function selectResult(item, val, text) {
	window.location.href = ("http://www.thebluealliance.com" + val);

}

$(function() {
	// Fancybox
	$(".fancybox").fancybox();

	// Typeahead for search
	// Currently does a one-time JSON get that returns
	// the entire list of teams and events.
	// Can be optimized.
	$('.search-query').focus(function() {
		$.getJSON('/_/typeahead', function(data) {
			$('.search-query').typeahead({
				// Used for when we implement a better typeahead solution
		    	/*ajax: {
			    	    url: '/typeahead',
			    	    method: 'get',
			    	    triggerLength: 3,
			    },*/
				source: data,
		    	itemSelected: selectResult
		    });
		});
	});
});<|endoftext|>