<commit_before>"use strict";

var utils = require("../lib/utils");
var Workbook = require("../lib/Workbook");

var proxyquire = require("proxyquire").noCallThru();
var DOMParser = require("xmldom").DOMParser;
var parser = new DOMParser();

var findChildNodes = function (node, tag) {
    var result = [];
    for (var childNodeIndex in node.childNodes) {
        if (node.childNodes.hasOwnProperty(childNodeIndex)) {
            var childNode = node.childNodes[childNodeIndex];
            if (childNode.tagName === tag) {
                result.push(childNode);
            }
        }
    }
    return result;
};

var getNodeText = function (node) {
    if (node.childNodes.length === 1) {
        return node.childNodes[0].nodeValue;
    }
    return null;
};

var getNodeAttribute = function (node, attribute) {
    return node.getAttribute(attribute);
};

describe("Sheet", function () {
    var Row, Sheet, workbook, sheetNode, sheetXML, sheet;

    beforeEach(function () {
        Row = jasmine.createSpy("Row");
        Sheet = proxyquire("../lib/Sheet", { "./Row": Row });
        workbook = {};
        sheetNode = parser.parseFromString('<sheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="Sheet1" sheetId="1"/>').documentElement;
        sheetXML = parser.parseFromString('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/></sheetData></worksheet>').documentElement;
        sheet = new Sheet(workbook, sheetNode, sheetXML);
    });

    describe("getWorkbook", function () {
        it("should return the workbook", function () {
            expect(sheet.getWorkbook()).toBe(workbook);
        });
    });

    describe("getName", function () {
        it("should return the sheet name", function () {
            expect(sheet.getName()).toBe("Sheet1");
        });
    });

    describe("getName", function () {
        it("should set the sheet name", function () {
            sheet.setName("some name");
            expect(sheetNode.toString()).toBe('<sheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="some name" sheetId="1"/>');
        });
    });

    describe("getRow", function () {
        it("should create a new row node if it doesn't exist", function () {
            sheet.getRow(3);
            expect(Row).toHaveBeenCalledWith(sheet, sheetXML.firstChild.lastChild);
            expect(sheetXML.toString()).toBe('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/><row r="3"/></sheetData></worksheet>');
        });

        it("should use an existing row node if it does exist", function () {
            sheet.getRow(1);
            expect(Row).toHaveBeenCalledWith(sheet, sheetXML.firstChild.firstChild);
            expect(sheetXML.toString()).toBe('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/></sheetData></worksheet>');
        });
    });

    describe("getCell (basic test)", function () {
        var getCell;
        beforeEach(function () {
            getCell = jasmine.createSpy("getCell");
            sheet.getRow = jasmine.createSpy("getRow").and.returnValue({ getCell: getCell });
        });

        it("should call getRow and getCell with the given row and column", function () {
            sheet.getCell(5, 7);
            expect(sheet.getRow).toHaveBeenCalledWith(5);
            expect(getCell).toHaveBeenCalledWith(7);
        });

        it("should call getRow and getCell with the row and column corresponding to the given address", function () {
            sheet.getCell("H11");
            expect(sheet.getRow).toHaveBeenCalledWith(11);
            expect(getCell).toHaveBeenCalledWith(8);
        });
    });

    describe("getCell (advanced test)", function () {
        var workbook, sheet;
        beforeEach(function () {
            workbook = Workbook.fromBlankSync();
            sheet = workbook.getSheet(0);
        });

        describe("deterministic access", function () {
            it("correctly maps to the same cell", function () {
                var upperCaseCell = sheet.getCell("A1");
                var lowerCaseCell = sheet.getCell("a1");
                var rowAndColumnCell = sheet.getCell(1, 1);
                expect(upperCaseCell.getFullAddress()).toBe(lowerCaseCell.getFullAddress());
                expect(upperCaseCell.getFullAddress()).toBe(rowAndColumnCell.getFullAddress());
                var num = Math.random();
                upperCaseCell.setValue(num);
                var upperCaseVNode = findChildNodes(upperCaseCell._cellNode, "v")[0];
                var lowerCaseVNode = findChildNodes(lowerCaseCell._cellNode, "v")[0];
                var rowAndColumnVNode = findChildNodes(rowAndColumnCell._cellNode, "v")[0];
                expect(upperCaseVNode).not.toBeNull("A1 value node should not be null");
                expect(lowerCaseVNode).not.toBeNull("a1 value node should not be null");
                expect(rowAndColumnVNode).not.toBeNull("1,1 value node should not be null");
                expect(getNodeText(upperCaseVNode)).toBe(getNodeText(lowerCaseVNode));
                expect(getNodeText(upperCaseVNode)).toBe(getNodeText(rowAndColumnVNode));
                expect(parseFloat(getNodeText(upperCaseVNode))).toBe(num, "A1 value set must match value generated");
                expect(parseFloat(getNodeText(lowerCaseVNode))).toBe(num, "a1 value set must match value generated");
                expect(parseFloat(getNodeText(rowAndColumnVNode))).toBe(num, "1,1 value set must match value generated");
            });
        });

        describe("stochastic access", function () {
            var MAX_ROW = 100;
            var MAX_COLUMN = 100;
            var MAX_EDIT = 1000;

            beforeEach(function () {
                // Make random edits to the sheet
                for (var i = 0; i < MAX_EDIT; i++) {
                    var rowNumber = 1 + Math.floor(MAX_ROW * Math.random());
                    var columnNumber = 1 + Math.floor(MAX_COLUMN * Math.random());
                    var cell = sheet.getCell(rowNumber, columnNumber);
                    cell.setValue(Math.random());
                }
            });

            it("is stored in order", function () {
                // Reload workbook and sheet
                workbook = new Workbook(workbook.output());
                sheet = workbook.getSheet(0);

                // Check order
                var lastRowNumber = 0;
                var sheetDataNode = findChildNodes(sheet._sheetXML, "sheetData")[0];
                var rowNodes = findChildNodes(sheetDataNode, "row");
                expect(rowNodes.length).toBeGreaterThan(0, "Rows must exist after workbook reload");
                rowNodes.forEach(function (rowNode) {
                    var rowNumber = parseInt(getNodeAttribute(rowNode, "r"));
                    expect(isNaN(rowNumber)).toBe(false);
                    expect(rowNumber).toBeGreaterThan(lastRowNumber);
                    lastRowNumber = rowNumber;
                    var lastColumnNumber = 0;
                    var cNodes = findChildNodes(rowNode, "c");
                    cNodes.forEach(function (cNode) {
                        var address = getNodeAttribute(cNode, "r");
                        expect(address).toBeDefined();
                        var ref = utils.addressToRowAndColumn(address);
                        expect(ref.row).toBe(rowNumber);
                        expect(ref.column).toBeGreaterThan(lastColumnNumber);
                        lastColumnNumber = ref.column;
                    });
                });
            });

            it("does not contain duplicates", function () {
                var addressCounter = {};
                var sheetDataNode = findChildNodes(sheet._sheetXML, "sheetData")[0];
                var rowNodes = findChildNodes(sheetDataNode, "row");
                expect(rowNodes.length).toBeGreaterThan(0, "Rows must exist");
                rowNodes.forEach(function (rowNode) {
                    var cNodes = findChildNodes(rowNode, "c");
                    cNodes.forEach(function (cNode) {
                        var address = getNodeAttribute(cNode, "r");
                        expect(address).not.toBeNull();
                        expect(address).toBeDefined();
                        if (address in addressCounter === false) {
                            addressCounter[address] = 0;
                        }
                        addressCounter[address]++;
                    });
                });
                for (var address in addressCounter) {
                    if (addressCounter.hasOwnProperty(address)) {
                        expect(addressCounter[address]).toBeLessThan(2);
                    }
                }
            });
        });
    });
});
<commit_msg>Added case-insensitive test for address. Added failing test for row creation bug. Disabled advanced getCell tests for the moment.<commit_after>"use strict";

var utils = require("../lib/utils");
var Workbook = require("../lib/Workbook");

var proxyquire = require("proxyquire").noCallThru();
var DOMParser = require("xmldom").DOMParser;
var parser = new DOMParser();

var findChildNodes = function (node, tag) {
    var result = [];
    for (var childNodeIndex in node.childNodes) {
        if (node.childNodes.hasOwnProperty(childNodeIndex)) {
            var childNode = node.childNodes[childNodeIndex];
            if (childNode.tagName === tag) {
                result.push(childNode);
            }
        }
    }
    return result;
};

var getNodeText = function (node) {
    if (node.childNodes.length === 1) {
        return node.childNodes[0].nodeValue;
    }
    return null;
};

var getNodeAttribute = function (node, attribute) {
    return node.getAttribute(attribute);
};

describe("Sheet", function () {
    var Row, Sheet, workbook, sheetNode, sheetXML, sheet;

    beforeEach(function () {
        Row = jasmine.createSpy("Row");
        Sheet = proxyquire("../lib/Sheet", { "./Row": Row });
        workbook = {};
        sheetNode = parser.parseFromString('<sheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="Sheet1" sheetId="1"/>').documentElement;
        sheetXML = parser.parseFromString('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/></sheetData></worksheet>').documentElement;
        sheet = new Sheet(workbook, sheetNode, sheetXML);
    });

    describe("getWorkbook", function () {
        it("should return the workbook", function () {
            expect(sheet.getWorkbook()).toBe(workbook);
        });
    });

    describe("getName", function () {
        it("should return the sheet name", function () {
            expect(sheet.getName()).toBe("Sheet1");
        });
    });

    describe("getName", function () {
        it("should set the sheet name", function () {
            sheet.setName("some name");
            expect(sheetNode.toString()).toBe('<sheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="some name" sheetId="1"/>');
        });
    });

    describe("getRow", function () {
        it("should create a new row node if it doesn't exist", function () {
            sheet.getRow(3);
            expect(Row).toHaveBeenCalledWith(sheet, sheetXML.firstChild.lastChild);
            expect(sheetXML.toString()).toBe('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/><row r="3"/></sheetData></worksheet>');
        });

        it("should use an existing row node if it does exist", function () {
            sheet.getRow(1);
            expect(Row).toHaveBeenCalledWith(sheet, sheetXML.firstChild.firstChild);
            expect(sheetXML.toString()).toBe('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/></sheetData></worksheet>');
        });

        it("should create rows in order", function () {
            sheet.getRow(3);
            sheet.getRow(2);
            expect(sheetXML.toString()).toBe('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData><row r="1"/><row r="2"/><row r="3"/></sheetData></worksheet>');
        });
    });

    describe("getCell", function () {
        var getCell;
        beforeEach(function () {
            getCell = jasmine.createSpy("getCell");
            sheet.getRow = jasmine.createSpy("getRow").and.returnValue({ getCell: getCell });
        });

        it("should call getRow and getCell with the given row and column", function () {
            sheet.getCell(5, 7);
            expect(sheet.getRow).toHaveBeenCalledWith(5);
            expect(getCell).toHaveBeenCalledWith(7);
        });

        it("should call getRow and getCell with the row and column corresponding to the given address", function () {
            sheet.getCell("H11");
            expect(sheet.getRow).toHaveBeenCalledWith(11);
            expect(getCell).toHaveBeenCalledWith(8);
        });

        it("should call getRow and getCell with the row and column corresponding to a lowercase address", function () {
            sheet.getCell("g9");
            expect(sheet.getRow).toHaveBeenCalledWith(9);
            expect(getCell).toHaveBeenCalledWith(7);
        });
    });

    xdescribe("getCell (advanced test)", function () {
        var workbook, sheet;
        beforeEach(function () {
            workbook = Workbook.fromBlankSync();
            sheet = workbook.getSheet(0);
        });

        describe("deterministic access", function () {
            it("correctly maps to the same cell", function () {
                var upperCaseCell = sheet.getCell("A1");
                var lowerCaseCell = sheet.getCell("a1");
                var rowAndColumnCell = sheet.getCell(1, 1);
                expect(upperCaseCell.getFullAddress()).toBe(lowerCaseCell.getFullAddress());
                expect(upperCaseCell.getFullAddress()).toBe(rowAndColumnCell.getFullAddress());
                var num = Math.random();
                upperCaseCell.setValue(num);
                var upperCaseVNode = findChildNodes(upperCaseCell._cellNode, "v")[0];
                var lowerCaseVNode = findChildNodes(lowerCaseCell._cellNode, "v")[0];
                var rowAndColumnVNode = findChildNodes(rowAndColumnCell._cellNode, "v")[0];
                expect(upperCaseVNode).not.toBeNull("A1 value node should not be null");
                expect(lowerCaseVNode).not.toBeNull("a1 value node should not be null");
                expect(rowAndColumnVNode).not.toBeNull("1,1 value node should not be null");
                expect(getNodeText(upperCaseVNode)).toBe(getNodeText(lowerCaseVNode));
                expect(getNodeText(upperCaseVNode)).toBe(getNodeText(rowAndColumnVNode));
                expect(parseFloat(getNodeText(upperCaseVNode))).toBe(num, "A1 value set must match value generated");
                expect(parseFloat(getNodeText(lowerCaseVNode))).toBe(num, "a1 value set must match value generated");
                expect(parseFloat(getNodeText(rowAndColumnVNode))).toBe(num, "1,1 value set must match value generated");
            });
        });

        describe("stochastic access", function () {
            var MAX_ROW = 100;
            var MAX_COLUMN = 100;
            var MAX_EDIT = 1000;

            beforeEach(function () {
                // Make random edits to the sheet
                for (var i = 0; i < MAX_EDIT; i++) {
                    var rowNumber = 1 + Math.floor(MAX_ROW * Math.random());
                    var columnNumber = 1 + Math.floor(MAX_COLUMN * Math.random());
                    var cell = sheet.getCell(rowNumber, columnNumber);
                    cell.setValue(Math.random());
                }
            });

            it("is stored in order", function () {
                // Reload workbook and sheet
                workbook = new Workbook(workbook.output());
                sheet = workbook.getSheet(0);

                // Check order
                var lastRowNumber = 0;
                var sheetDataNode = findChildNodes(sheet._sheetXML, "sheetData")[0];
                var rowNodes = findChildNodes(sheetDataNode, "row");
                expect(rowNodes.length).toBeGreaterThan(0, "Rows must exist after workbook reload");
                rowNodes.forEach(function (rowNode) {
                    var rowNumber = parseInt(getNodeAttribute(rowNode, "r"));
                    expect(isNaN(rowNumber)).toBe(false);
                    expect(rowNumber).toBeGreaterThan(lastRowNumber);
                    lastRowNumber = rowNumber;
                    var lastColumnNumber = 0;
                    var cNodes = findChildNodes(rowNode, "c");
                    cNodes.forEach(function (cNode) {
                        var address = getNodeAttribute(cNode, "r");
                        expect(address).toBeDefined();
                        var ref = utils.addressToRowAndColumn(address);
                        expect(ref.row).toBe(rowNumber);
                        expect(ref.column).toBeGreaterThan(lastColumnNumber);
                        lastColumnNumber = ref.column;
                    });
                });
            });

            it("does not contain duplicates", function () {
                var addressCounter = {};
                var sheetDataNode = findChildNodes(sheet._sheetXML, "sheetData")[0];
                var rowNodes = findChildNodes(sheetDataNode, "row");
                expect(rowNodes.length).toBeGreaterThan(0, "Rows must exist");
                rowNodes.forEach(function (rowNode) {
                    var cNodes = findChildNodes(rowNode, "c");
                    cNodes.forEach(function (cNode) {
                        var address = getNodeAttribute(cNode, "r");
                        expect(address).not.toBeNull();
                        expect(address).toBeDefined();
                        if (address in addressCounter === false) {
                            addressCounter[address] = 0;
                        }
                        addressCounter[address]++;
                    });
                });
                for (var address in addressCounter) {
                    if (addressCounter.hasOwnProperty(address)) {
                        expect(addressCounter[address]).toBeLessThan(2);
                    }
                }
            });
        });
    });
});
<|endoftext|>


<commit_before>Parser = require('../parser.js');
var Promise = require('bluebird');

describe('Parser', function () {

  describe('matchStr', function () {
    it('should match a string', function (done) {
      var m = Parser.matchStr('Foo');
      var parsePromise = m.parse('FooBar!');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['Foo']);
        expect(res.remaining).toEqual('Bar!')
      })
      .catch(done.fail)
      .done(done);

    });

    it('should fail if no match', function (done) {
      var m = Parser.matchStr('Foo');
      var parsePromise = m.parse('BarFoo!');

      parsePromise
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Foo']);
        done();
      })

    });
  });

  describe('followedBy', function () {
    it('should match a sequsence', function (done) {
      var m = Parser.matchStr('Foo')
              .followedBy(Parser.matchStr('Bar'))
              .followedBy(Parser.matchStr('Baz'))
              .followedBy(Parser.matchStr('Spam'))
              .followedBy(Parser.matchStr('Eggs'))
              .followedBy(Parser.matchStr('Ham'));

      var parsePromise = m.parse('FooBarBazSpamEggsHam!!');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['Foo', 'Bar', 'Baz', 'Spam', 'Eggs', 'Ham']);
        expect(res.remaining).toEqual('!!')
      })
      .catch(done.fail)
      .done(done)

    });

    it('should fail not a match', function (done) {
      var m = Parser.matchStr('Foo')
              .followedBy(Parser.matchStr('Bar'))
              .followedBy(Parser.matchStr('Baz'));

      var parsePromise = m.parse('FooBarSpam');

      parsePromise
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Baz']);
        done();
      });

    });
  });

  describe('or', function () {
    it('should match', function (done) {
      var m = Parser.matchStr('Foo')
              .or(Parser.matchStr('Bar').or(Parser.matchStr('Spam')))
              .or(Parser.matchStr('Baz'));

      var parsePromise = m.parse('BarSpamHam');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['Bar']);
        expect(res.remaining).toEqual('SpamHam');
      })
      .catch(done.fail)
      .done(done);
    });

    it('should fail if no match', function (done) {
      var m = Parser.matchStr('Foo')
              .or(Parser.matchStr('Bar'));

      var parsePromise = m.parse('BazSpamHam');

      parsePromise
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Foo', 'Bar']);
        done();
      });
    });
  });

  describe('andReturn', function () {
    it('should alter the returned match', function (done) {
      var m = Parser.matchStr('Foo')
              .andReturn(99);
      var parsePromise = m.parse('FooBar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual([99]);
        expect(res.remaining).toEqual('Bar');
      })
      .catch(done.fail)
      .done(done);
    });
  });

  describe('map', function () {
    it('should alter the returned match', function (done) {
      var m = Parser.matchStr('99')
              .map(parseInt);
      var parsePromise = m.parse('99Bar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual([99]);
        expect(res.remaining).toEqual('Bar');
      })
      .catch(done.fail)
      .done(done);
    });
  });

  describe('many', function () {
    it('should match many', function (done) {
      var m = Parser.many(Parser.matchStr('Foo'));

      var parsePromise = m.parse('FooFooFooFooBar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['Foo', 'Foo', 'Foo', 'Foo']);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
    it('should not fail if no match', function (done) {
      var m = Parser.many(Parser.matchStr('Bar'));

      var parsePromise = m.parse('FooBar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('FooBar')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('alphaChar', function () {
    it('should match alpha chars', function (done) {
      /* cheating - use many */
      var m = Parser.many(Parser.alphaChar()),
          parsePromise = m.parse('alzALZ{');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['a', 'l', 'z', 'A', 'L', 'Z']);
        expect(res.remaining).toEqual('{')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('numericChar', function () {
    it('should match numeric chars', function (done) {
      /* cheating - use many */
      var m = Parser.many(Parser.numericChar()),
          parsePromise = m.parse('0123456789@');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['0', '1', '2', '3', '4',
                                     '5', '6', '7', '8', '9']);
        expect(res.remaining).toEqual('@')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('maybe', function () {
    it('matches', function (done) {
      var m = Parser.maybe(Parser.matchStr('Foo')),
          parsePromise = m.parse('FooBar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual(['Foo']);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
    it('doesn\' fail if no matches', function (done) {
      var m = Parser.maybe(Parser.matchStr('Foo')),
          parsePromise = m.parse('BarFoo');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('BarFoo')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('squash', function () {
    it('matches and squashed', function (done) {
      var m = Parser.matchStr('Foo').squash(),
          parsePromise = m.parse('FooBar');

      parsePromise.then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('sepBy', function () {
    it('should match', function (done) {
      var m = Parser.sepBy(Parser.matchStr('-'),
                           Parser.matchStr('Foo').or(Parser.matchStr('Bar')));

      m.parse('Bar-Foo-Foo-Bar-Wrong')
      .then(function (res) {
        expect(res.matched).toEqual(['Bar', 'Foo', 'Foo', 'Bar']);
        expect(res.remaining).toEqual('-Wrong')
      })
      .catch(done.fail)
      .done(done)
    });
  });
});
<commit_msg>Remove pointless vars in spec<commit_after>Parser = require('../parser.js');
var Promise = require('bluebird');

describe('Parser', function () {

  describe('matchStr', function () {
    it('should match a string', function (done) {
      var m = Parser.matchStr('Foo');

      m.parse('FooBar!').then(function (res) {
        expect(res.matched).toEqual(['Foo']);
        expect(res.remaining).toEqual('Bar!')
      })
      .catch(done.fail)
      .done(done);

    });

    it('should fail if no match', function (done) {
      var m = Parser.matchStr('Foo');

      m.parse('BarFoo!')
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Foo']);
        done();
      })

    });
  });

  describe('followedBy', function () {
    it('should match a sequsence', function (done) {
      var m = Parser.matchStr('Foo')
              .followedBy(Parser.matchStr('Bar'))
              .followedBy(Parser.matchStr('Baz'))
              .followedBy(Parser.matchStr('Spam'))
              .followedBy(Parser.matchStr('Eggs'))
              .followedBy(Parser.matchStr('Ham'));

      m.parse('FooBarBazSpamEggsHam!!').then(function (res) {
        expect(res.matched).toEqual(['Foo', 'Bar', 'Baz', 'Spam', 'Eggs', 'Ham']);
        expect(res.remaining).toEqual('!!')
      })
      .catch(done.fail)
      .done(done)

    });

    it('should fail not a match', function (done) {
      var m = Parser.matchStr('Foo')
              .followedBy(Parser.matchStr('Bar'))
              .followedBy(Parser.matchStr('Baz'));

      m.parse('FooBarSpam')
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Baz']);
        done();
      });

    });
  });

  describe('or', function () {
    it('should match', function (done) {
      var m = Parser.matchStr('Foo')
              .or(Parser.matchStr('Bar').or(Parser.matchStr('Spam')))
              .or(Parser.matchStr('Baz'));

      m.parse('BarSpamHam').then(function (res) {
        expect(res.matched).toEqual(['Bar']);
        expect(res.remaining).toEqual('SpamHam');
      })
      .catch(done.fail)
      .done(done);
    });

    it('should fail if no match', function (done) {
      var m = Parser.matchStr('Foo')
              .or(Parser.matchStr('Bar'));

      m.parse('BazSpamHam')
      .then(done.fail.bind(null, "Should not resolve"))
      .catch(function (err) {
        expect(err.expecting).toEqual(['Foo', 'Bar']);
        done();
      });
    });
  });

  describe('andReturn', function () {
    it('should alter the returned match', function (done) {
      var m = Parser.matchStr('Foo')
              .andReturn(99);

      m.parse('FooBar').then(function (res) {
        expect(res.matched).toEqual([99]);
        expect(res.remaining).toEqual('Bar');
      })
      .catch(done.fail)
      .done(done);
    });
  });

  describe('map', function () {
    it('should alter the returned match', function (done) {
      var m = Parser.matchStr('99')
              .map(parseInt);

      m.parse('99Bar').then(function (res) {
        expect(res.matched).toEqual([99]);
        expect(res.remaining).toEqual('Bar');
      })
      .catch(done.fail)
      .done(done);
    });
  });

  describe('many', function () {
    it('should match many', function (done) {
      var m = Parser.many(Parser.matchStr('Foo'));

       m.parse('FooFooFooFooBar').then(function (res) {
        expect(res.matched).toEqual(['Foo', 'Foo', 'Foo', 'Foo']);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
    it('should not fail if no match', function (done) {
      var m = Parser.many(Parser.matchStr('Bar'));

      m.parse('FooBar').then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('FooBar')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('alphaChar', function () {
    it('should match alpha chars', function (done) {
      /* cheating - use many */
      var m = Parser.many(Parser.alphaChar());

      m.parse('alzALZ{').then(function (res) {
        expect(res.matched).toEqual(['a', 'l', 'z', 'A', 'L', 'Z']);
        expect(res.remaining).toEqual('{')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('numericChar', function () {
    it('should match numeric chars', function (done) {
      /* cheating - use many */
      var m = Parser.many(Parser.numericChar());

      m.parse('0123456789@').then(function (res) {
        expect(res.matched).toEqual(['0', '1', '2', '3', '4',
                                     '5', '6', '7', '8', '9']);
        expect(res.remaining).toEqual('@')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('maybe', function () {
    it('matches', function (done) {
      var m = Parser.maybe(Parser.matchStr('Foo'));

      m.parse('FooBar').then(function (res) {
        expect(res.matched).toEqual(['Foo']);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
    it('doesn\' fail if no matches', function (done) {
      var m = Parser.maybe(Parser.matchStr('Foo'));

      m.parse('BarFoo').then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('BarFoo')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('squash', function () {
    it('matches and squashed', function (done) {
      var m = Parser.matchStr('Foo').squash();

      m.parse('FooBar').then(function (res) {
        expect(res.matched).toEqual([]);
        expect(res.remaining).toEqual('Bar')
      })
      .catch(done.fail)
      .done(done)
    });
  });
  describe('sepBy', function () {
    it('should match', function (done) {
      var m = Parser.sepBy(Parser.matchStr('-'),
                           Parser.matchStr('Foo').or(Parser.matchStr('Bar')));

      m.parse('Bar-Foo-Foo-Bar-Wrong')
      .then(function (res) {
        expect(res.matched).toEqual(['Bar', 'Foo', 'Foo', 'Bar']);
        expect(res.remaining).toEqual('-Wrong')
      })
      .catch(done.fail)
      .done(done)
    });
  });
});
<|endoftext|>


<commit_before>const sh = require('shelljs'),
      path = require('path'),
      fs = require('fs-extra'),
      basePackagePath = path.resolve(__dirname, '..'),
      fixturePath = path.resolve(__dirname, 'fixtures'),
      resultFixturePath = path.resolve(__dirname, 'fixtures', 'result'),
      readJSON = fs.readJSONSync;

let prepareInput,
    identInputForTest,
    clearInputForTest,
    runApp;
/**
 * Идентификация входных данных
 * на основе кейса определяет имена json файлов с тестовыми данными
 * @param {string} testCase - кейс использования:
 * (equal|oneMoreError|oneMoreNewError|empty)
 * @typedef {Object} testDataJSONNames имена обозначающие JSON с тестовыми
 * данными
 * @property {String} masterInputName - мастер ветку
 * @property {String} currentInputName - текущую ветку
 * @return {testDataJSONNames}
 */
identInputForTest = (testCase) => {
  let current,
      master,
      error = 'error';

  switch (testCase) {
    case 'equal':
      master = error;
      current = error;
      break;
    case 'newErrorsAndFiles':
      master = error;
      current = testCase;
      break;
    case 'onesLessErrorFile':
      master = identInputForTest('newErrorsAndFiles').masterInputName;
      current = error;
      break;
    case 'oneMoreErrorInExistErrorFile':
      master = error;
      current = testCase;
      break;
    case 'onesLessErrorInExistErrorFile':
      master = identInputForTest('oneMoreErrorInExistErrorFile').masterInputName;
      current = testCase;
      break;
    case 'empty':
      master = testCase;
      current = testCase;
      break;
    default:
      break;
  }

  console.log({
    masterInputName: master,
    currentInputName: current
  });

  return {
    masterInputName: master,
    currentInputName: current
  };
};

/**
 * функия копирует входные json в корень
 * @param {string} testCase - кейс использования:
 * (equal|oneMoreError|oneMoreNewError|empty)
 */
prepareInput = (testCase) => {
  const testDataPath = identInputForTest(testCase);

  sh.cp(`${fixturePath}/${testDataPath.masterInputName}.json`, `${basePackagePath}/fromMaster.json`);
  sh.cp(`${fixturePath}/${testDataPath.currentInputName}.json`,
    `${basePackagePath}/fromCurrent.json`);
};

/**
 * Запуск приложения
 */
runApp = () => {
  sh.exec(`cd ${basePackagePath}; node index.js -master ${basePackagePath}/fromMaster.json -current ${basePackagePath}/fromCurrent.json`);
  console.log(`cd ${basePackagePath}; node index.js -master ${basePackagePath}/fromMaster.json -current ${basePackagePath}/fromCurrent.json`);
};

/**
 * Очистить входные данные после теста
 */
clearInputForTest = () => {
  sh.rm(`${basePackagePath}/fromCurrent.json`);
  sh.rm(`${basePackagePath}/fromMaster.json`);
  sh.rm(`${basePackagePath}/result.json`);
};

describe('Смок тест модуля работы с eslint', () => {
  describe('исключающий мерж', () => {
    beforeAll(() => {
      sh.chmod('+x', `${basePackagePath}/index.js`);
    });

    afterEach(() => {
      clearInputForTest();
    });

    it('создан результирующий файл', () => {
      prepareInput('empty');
      runApp();

      expect(sh.test('-f', `${basePackagePath}/result.json`)).toBeTruthy();
    });

    describe('файлы идентичны', function () {
      let resultJSON,
          expectedJSON;

      afterEach(() => {
        resultJSON = undefined;
      });

      it('пусты', function () {
        prepareInput('empty');
        runApp();
        expectedJSON = readJSON(`${resultFixturePath}/empty.json`);
        resultJSON = readJSON(`${basePackagePath}/result.json`);
        expect(resultJSON).toEqual([]);
      });

      it('одинаковы', function () {
        let resultFixtureName = 'empty';
        prepareInput('equal');
        runApp();

        resultJSON = readJSON(`${basePackagePath}/result.json`);
        expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
        expect(resultJSON).toEqual(expectedJSON);
      });

      describe('не одинаковы', function () {
        it('новый файл с ошибками', () => {
          let resultFixtureName = 'newErrorsAndFiles';
          prepareInput(resultFixtureName);
          runApp();
          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);

          expect(resultJSON).toEqual(expectedJSON);
        });

        it('новые ошибки в файле, в котором уже были ошибки', () => {
          let resultFixtureName = 'oneMoreErrorInExistErrorFile';
          prepareInput(resultFixtureName);
          runApp();
          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);

          expect(resultJSON).toEqual(expectedJSON);
        });

        it('уменьшение количества ошибок', () => {
          let resultFixtureName = 'onesLessErrorInExistErrorFile';
          prepareInput('onesLessErrorInExistErrorFile');
          runApp();

          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);
          expect(resultJSON).toEqual(expectedJSON);
        });

        it('уменьшение количества файлов с ошибками', () => {
          let resultFixtureName = 'onesLessErrorFile';
          prepareInput('onesLessErrorFile');
          runApp();

          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);
          expect(resultJSON).toEqual(expectedJSON);
        });
      });
    });
  });
});
<commit_msg>test(*): почистил тесты<commit_after>const sh = require('shelljs'),
      path = require('path'),
      fs = require('fs-extra'),
      basePackagePath = path.resolve(__dirname, '..'),
      fixturePath = path.resolve(__dirname, 'fixtures'),
      resultFixturePath = path.resolve(__dirname, 'fixtures', 'result'),
      readJSON = fs.readJSONSync;

let prepareInput,
    identInputForTest,
    clearInputForTest,
    runApp;
/**
 * Идентификация входных данных
 * на основе кейса определяет имена json файлов с тестовыми данными
 * @param {string} testCase - кейс использования:
 * (equal|oneMoreError|oneMoreNewError|empty)
 * @typedef {Object} testDataJSONNames имена обозначающие JSON с тестовыми
 * данными
 * @property {String} masterInputName - мастер ветку
 * @property {String} currentInputName - текущую ветку
 * @return {testDataJSONNames}
 */
identInputForTest = (testCase) => {
  let current,
      master,
      error = 'error';

  switch (testCase) {
    case 'equal':
      master = error;
      current = error;
      break;
    case 'newErrorsAndFiles':
      master = error;
      current = testCase;
      break;
    case 'onesLessErrorFile':
      master = identInputForTest('newErrorsAndFiles').masterInputName;
      current = error;
      break;
    case 'oneMoreErrorInExistErrorFile':
      master = error;
      current = testCase;
      break;
    case 'onesLessErrorInExistErrorFile':
      master = identInputForTest('oneMoreErrorInExistErrorFile').masterInputName;
      current = error;
      break;
    case 'empty':
      master = testCase;
      current = testCase;
      break;
    default:
      break;
  }

  console.log({
    masterInputName: master,
    currentInputName: current
  });

  return {
    masterInputName: master,
    currentInputName: current
  };
};

/**
 * функия копирует входные json в корень
 * @param {string} testCase - кейс использования:
 * (equal|oneMoreError|oneMoreNewError|empty)
 */
prepareInput = (testCase) => {
  const testDataPath = identInputForTest(testCase);

  sh.cp(`${fixturePath}/${testDataPath.masterInputName}.json`, `${basePackagePath}/fromMaster.json`);
  sh.cp(`${fixturePath}/${testDataPath.currentInputName}.json`,
    `${basePackagePath}/fromCurrent.json`);
};

/**
 * Запуск приложения
 */
runApp = () => {
  sh.exec(`cd ${basePackagePath}; node index.js eslint -master ${basePackagePath}/fromMaster.json -current ${basePackagePath}/fromCurrent.json`);
};

/**
 * Очистить входные данные после теста
 */
clearInputForTest = () => {
  sh.rm(`${basePackagePath}/fromCurrent.json`);
  sh.rm(`${basePackagePath}/fromMaster.json`);
  sh.rm(`${basePackagePath}/result.json`);
};

describe('Смок тест модуля работы с eslint', () => {
  describe('исключающий мерж', () => {
    beforeAll(() => {
      sh.chmod('+x', `${basePackagePath}/index.js`);
    });

    afterEach(() => {
      clearInputForTest();
    });

    it('создан результирующий файл', () => {
      prepareInput('empty');
      runApp();

      expect(sh.test('-f', `${basePackagePath}/result.json`)).toBeTruthy();
    });

    describe('файлы идентичны', function () {
      let resultJSON,
          expectedJSON;

      afterEach(() => {
        resultJSON = undefined;
      });

      it('пусты', function () {
        prepareInput('empty');
        runApp();
        expectedJSON = readJSON(`${resultFixturePath}/empty.json`);
        resultJSON = readJSON(`${basePackagePath}/result.json`);
        expect(resultJSON).toEqual([]);
      });

      it('одинаковы', function () {
        let resultFixtureName = 'empty';
        prepareInput('equal');
        runApp();

        resultJSON = readJSON(`${basePackagePath}/result.json`);
        expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
        expect(resultJSON).toEqual(expectedJSON);
      });

      describe('не одинаковы', function () {
        it('новый файл с ошибками', () => {
          let resultFixtureName = 'newErrorsAndFiles';
          prepareInput(resultFixtureName);
          runApp();
          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);

          expect(resultJSON).toEqual(expectedJSON);
        });

        it('новые ошибки в файле, в котором уже были ошибки', () => {
          let resultFixtureName = 'oneMoreErrorInExistErrorFile';
          prepareInput(resultFixtureName);
          runApp();
          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);

          expect(resultJSON).toEqual(expectedJSON);
        });

        it('уменьшение количества ошибок', () => {
          let resultFixtureName = 'empty';
          prepareInput('onesLessErrorInExistErrorFile');
          runApp();

          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);
          expect(resultJSON).toEqual(expectedJSON);
        });

        it('уменьшение количества файлов с ошибками', () => {
          let resultFixtureName = 'onesLessErrorFile';
          prepareInput('onesLessErrorFile');
          runApp();

          expectedJSON = readJSON(`${resultFixturePath}/${resultFixtureName}.json`);
          resultJSON = readJSON(`${basePackagePath}/result.json`);
          expect(resultJSON).toEqual(expectedJSON);
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*jshint expr: true*/
'use strict';
require('should');

describe('Baby', function(){

  var baby = require('../classes/baby.js');

  describe('when crying', function(){
    it('should execute callback passed for each cry', function(){
      baby.awake('cry1- cry2 -cry3');

      var expected_crys = [];

      baby.each_cry(function(crying) {
        expected_crys.push(crying);
      });

      expected_crys.should.have.lengthOf(3);
      expected_crys[0].should.be.exactly('cry1');
      expected_crys[1].should.be.exactly('cry2');
      expected_crys[2].should.be.exactly('cry3');
    });
  });
});
<commit_msg>Refactor baby spec<commit_after>/*jshint expr: true*/
'use strict';
require('should');

describe('Baby', function(){

  var baby = require('../classes/baby.js');

  describe('when crying', function(){
    it('should execute callback passed for each cry', function(){
      baby.awake('cry1- cry2 -cry3-cry4');

      var expected_crys = [];

      baby.each_cry(function(crying) {
        expected_crys.push(crying);
      });

      expected_crys.should.have.lengthOf(4);
      expected_crys.should.include('cry1');
      expected_crys.should.include('cry2');
      expected_crys.should.include('cry3');
      expected_crys.should.include('cry4');
    });
  });
});
<|endoftext|>


<commit_before>describe('proxies', function(){

  describe('making proxies', function(){

    it('adds a bound() function to the global scope', function(){
      expect(bound).toEqual(any(Function));
    });

    xit('provides a helper to identify bound methods', function(){
      expect(bound.isBoundMethod(function(){}).toBe(false));
      expect(bound.isBoundMethod(bound.proxy({}).bound)).toBe(true);
    });

    it('should return the input object as a result of calling bound()', function(){
      expect(bound.proxy(alice)).toEqual(alice);
    });

    it('should augment objects passed into bound.proxy() with a .bound() method', function(){
      expect(bound.proxy({}).bound).toEqual(any(Function));
    });

    it('should throw an error if a non bound method is already stored at the key "bound" and bound.proxy() is called on it', function(){
      expect(function(){
        bound.proxy({bound:3});
      }).toThrow();
    });

    it('should not throw an error if a bound method is already stored at the key "bound" and bound is called on it', function(){
      expect(function(){
        bound.proxy(alice);
        bound.proxy(alice);
      }).not.toThrow();
    });

    // regression test
    it('should not throw an error if you try to proxy an object that has a target property', function(){
      expect(function() {
        bound.proxy({target:3});
      }).not.toThrow();
    });

    it('should put a unique bound method on each proxied object', function(){
      expect(bound.proxy({}).bound).not.toBe(bound.proxy({}).bound);
    });

    it('should provide the same method if the same object is passed in twice', function(){
      expect(bound.proxy(alice).bound).toEqual(bound.proxy(alice).bound);
    });

    it('should not provide the same bound method for a child as the one available on its prototype', function(){
      expect(bound.proxy(child).bound).not.toEqual(bound.proxy(parent).bound);
    });

    xit('should not add any properties to a object other than .bound()', function(){
      expect(_.keys(bound.proxy({}))).toEqual(['bound']);
    });

    it('should not allow proxying proxy objects', function(){
      expect(function() {
        var proxy = bound.proxy(empty).bound('proxy');
        bound.proxy(proxy);
      }).toThrow();
    });

  });

  describe('iteration', function(){

    xit('skips .bound methods');

    xit('does not skip .bound properties that are not bound methods');

    xit('does not skip bound methods stored at keys besides .bound');

  });

  describe('applying to bound method between contexts', function(){

    it('should not allow the bound method of one object to be called in the context of another object', function(){
      // todo: long term, this should actually just have the effect of calling the bound method of the target object instead
      expect(function(){
        bound.proxy(alice).bound.apply(bob);
      }).toThrow();
    });

    xit('throws an error when a .bound() method is called on its associated object, but the method is not found on the target at the key \'bound\'', function(){
      var removedMethod = bound.proxy(alice).bound;
      delete alice.bound;
      expect(function(){
        removedMethod.apply(alice);
      }).toThrow();
    });

    xit('should augment child objects with their own .bound() property when a call to .bound() delegates through to the prototype object', function(){
      expect(child.bound).toEqual(bound.proxy(parent).bound);
      child.bound(); // delegates to parent.bound()
      expect(child.bound).not.toEqual(parent.bound);
    });

  });

  describe('bound proxy object methods', function(){

    it('should allow access to a proxy object by calling the "proxy" command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      var proxy = object.bound('proxy');
      var proxyMethods = 'get set del has owns run exec pub sub proxy meta'.split(' ');
      for(var i = 0; i < proxyMethods.length; i++){
        var methodName = proxyMethods[i];
        expect(proxy[methodName]).toEqual(any(Function));
        spyOn(proxy, methodName);
        var randomNumber = Math.random();
        proxy[methodName](randomNumber);
        expect(proxy[methodName]).toHaveBeenCalledWith(randomNumber);
      }
    });

    it('should get the value of properties from the target object when you run the get command', function(){
      // todo: tursify
      var object = {thing:5};
      bound.proxy(object);
      expect(object.bound('get','thing')).toEqual(5);
    });

    it('should set the value of properties from the target object when you run the set command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      object.bound('set', 'setThing', 2);
      expect(object.bound('get','setThing')).toEqual(2);
    });

    it('should delete properties from the target object when you run the del command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      object.bound('set', 'setThing', 4);
      var trulySet = object.bound('get', 'setThing');
      object.bound('del', 'setThing');
      var trulyDel = object.bound('get', 'setThing');
      expect(trulyDel).not.toEqual(trulySet);
      expect(object.hasOwnProperty('setThing')).toBe(false);
    });

    xit('should re-run work that was dependent on calls to "has" after deleting properties that used to exist');

    xit('should re-run work that was dependent on calls to "has" after setting properties that didnt\'t used to exist');

    it('should return the presence or absence of a property on the target object when you run the has command', function(){
      bound.proxy(message);
      expect(message.bound('has', 'text')).toBe(true);
      expect(message.bound('has', 'unicorns')).toBe(false);
    });

    xit('should return the immediate presence or absence of a property (not prototype-inherited) on the target object when you run the owns command');

    xit('todo: need to provide a way for users to run a function or a method in an arbitrary context');

    xit('should run the specified method (in the context of the target object) when you run the run command, and should return the result');

    xit('should run the target function object (in the context of window) when you run the exec command, and should return the result');

    xit('todo: should provide an eventing system, including publish and subscribe');

    xit('should add meta data about the target object to the proxy object when you call the meta command');
  });

  describe('updates to depended-upon properties', function(){

    xit('should let you invalidate listeners for one key by exposing a bound() command "changed"', function(){
      var runCount = 0;
      bound.autorun(function() {
        alice.bound('get', 'name');
        runCount++;
      });
      expect(runCount).toEqual(1);
      alice.name = 'al';
      alice.bound('changed', 'name');
      Clock.tick();
      expect(runCount).toEqual(2);
      alice.age = 21;
      alice.bound('changed', 'age');
      Clock.tick();
      expect(runCount).toEqual(2);
    });

    xit('should update only the values associated with specified keys', function(){
    });

    xit('should expire all dependent computations when called with no command name', function(){
    });

    xit('should not result in re-runs of dependent contexts for setting properties to the same value they already hold', function(){
    });

    xit('should not re-run properties dependent on key inclusion when only the property value has changed, not its presence in the object', function(){
      // todo: tursify
      bound.proxy(alice);
      var runCount1 = 0;
      bound.autorun(function(){
        alice.bound('has', 'hamburger');
        runCount1 += 1;
      });
      var runCount2 = 0;
      bound.autorun(function(){
        alice.bound('get', 'name');
        runCount2 += 1;
      });
      alice.bound('set', 'name', 'al');
      Clock.tick();
      expect([runCount1, runCount2]).toEqual([1, 2]);
    });

    it('errors when passed an invalid command name', function(){
      var object = {}
      bound.proxy(object);
      var proxy = object.bound('proxy');
      var invalidCommands = ['delete', 1, true, false, ['hello','goodbye'], {thing1:"foo", thing2:"bar"}];
      for(var i = 0; i < invalidCommands.length; i++){
        var command = invalidCommands[i];
        expect(proxy[command]).not.toEqual(any(Function));
      }

    });

  });

});
<commit_msg>Testing edits<commit_after>describe('proxies', function(){

  describe('making proxies', function(){

    it('adds a bound() function to the global scope', function(){
      expect(bound).toEqual(any(Function));
    });

    xit('provides a helper to identify bound methods', function(){
      expect(bound.isBoundMethod(function(){}).toBe(false));
      expect(bound.isBoundMethod(bound.proxy({}).bound)).toBe(true);
    });

    it('should return the input object as a result of calling bound()', function(){
      expect(bound.proxy(alice)).toEqual(alice);
    });

    it('should augment objects passed into bound.proxy() with a .bound() method', function(){
      expect(bound.proxy({}).bound).toEqual(any(Function));
    });

    it('should throw an error if a non bound method is already stored at the key "bound" and bound.proxy() is called on it', function(){
      expect(function(){
        bound.proxy({bound:3});
      }).toThrow();
    });

    it('should not throw an error if a bound method is already stored at the key "bound" and bound is called on it', function(){
      expect(function(){
        bound.proxy(alice);
        bound.proxy(alice);
      }).not.toThrow();
    });

    // regression test
    it('should not throw an error if you try to proxy an object that has a target property', function(){
      expect(function() {
        bound.proxy({target:3});
      }).not.toThrow();
    });

    it('should put a unique bound method on each proxied object', function(){
      expect(bound.proxy({}).bound).not.toBe(bound.proxy({}).bound);
    });

    it('should provide the same method if the same object is passed in twice', function(){
      expect(bound.proxy(alice).bound).toEqual(bound.proxy(alice).bound);
    });

    it('should not provide the same bound method for a child as the one available on its prototype', function(){
      expect(bound.proxy(child).bound).not.toEqual(bound.proxy(parent).bound);
    });

    xit('should not add any properties to a object other than .bound()', function(){
      expect(_.keys(bound.proxy({}))).toEqual(['bound']);
    });

    it('should not allow proxying proxy objects', function(){
      expect(function() {
        var proxy = bound.proxy(empty).bound('proxy');
        bound.proxy(proxy);
      }).toThrow();
    });

  });

  describe('iteration', function(){

    xit('skips .bound methods');

    xit('does not skip .bound properties that are not bound methods');

    xit('does not skip bound methods stored at keys besides .bound');

  });

  describe('applying to bound method between contexts', function(){

    it('should not allow the bound method of one object to be called in the context of another object', function(){
      // todo: long term, this should actually just have the effect of calling the bound method of the target object instead
      expect(function(){
        bound.proxy(alice).bound.apply(bob);
      }).toThrow();
    });

    xit('throws an error when a .bound() method is called on its associated object, but the method is not found on the target at the key \'bound\'', function(){
      var removedMethod = bound.proxy(alice).bound;
      delete alice.bound;
      expect(function(){
        removedMethod.apply(alice);
      }).toThrow();
    });

    xit('should augment child objects with their own .bound() property when a call to .bound() delegates through to the prototype object', function(){
      expect(child.bound).toEqual(bound.proxy(parent).bound);
      child.bound(); // delegates to parent.bound()
      expect(child.bound).not.toEqual(parent.bound);
    });

  });

  describe('bound proxy object methods', function(){

    it('should allow access to a proxy object by calling the "proxy" command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      var proxy = object.bound('proxy');
      var proxyMethods = 'get set del has owns run exec pub sub proxy meta'.split(' ');
      for(var i = 0; i < proxyMethods.length; i++){
        var methodName = proxyMethods[i];
        expect(proxy[methodName]).toEqual(any(Function));
        spyOn(proxy, methodName);
        var randomNumber = Math.random();
        proxy[methodName](randomNumber);
        expect(proxy[methodName]).toHaveBeenCalledWith(randomNumber);
      }
    });

    it('should get the value of properties from the target object when you run the get command', function(){
      // todo: tursify
      var object = {thing:5};
      bound.proxy(object);
      expect(object.bound('get','thing')).toEqual(5);
    });

    it('should set the value of properties from the target object when you run the set command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      object.bound('set', 'setThing', 2);
      expect(object.bound('get','setThing')).toEqual(2);
    });

    it('should delete properties from the target object when you run the del command', function(){
      // todo: tursify
      var object = {};
      bound.proxy(object);
      object.bound('set', 'setThing', 4);
      var trulySet = object.bound('get', 'setThing');
      object.bound('del', 'setThing');
      var trulyDel = object.bound('get', 'setThing');
      expect(trulyDel).not.toEqual(trulySet);
      expect(object.hasOwnProperty('setThing')).toBe(false);
    });

    xit('should re-run work that was dependent on calls to "has" after deleting properties that used to exist');

    xit('should re-run work that was dependent on calls to "has" after setting properties that didnt\'t used to exist');

    it('should return the presence or absence of a property on the target object when you run the has command', function(){
      bound.proxy(message);
      expect(message.bound('has', 'text')).toBe(true);
      expect(message.bound('has', 'unicorns')).toBe(false);
    });

    xit('should return the immediate presence or absence of a property (not prototype-inherited) on the target object when you run the owns command');

    xit('todo: need to provide a way for users to run a function or a method in an arbitrary context');

    xit('should run the specified method (in the context of the target object) when you run the run command, and should return the result');

    xit('should run the target function object (in the context of window) when you run the exec command, and should return the result');

    xit('todo: should provide an eventing system, including publish and subscribe');

    xit('should add meta data about the target object to the proxy object when you call the meta command');
  });

  describe('updates to depended-upon properties', function(){

    xit('should let you invalidate listeners for one key by exposing a bound() command "changed"', function(){
      var runCount = 0;
      bound.autorun(function() {
        alice.bound('get', 'name');
        runCount++;
      });
      expect(runCount).toEqual(1);
      alice.name = 'al';
      alice.bound('changed', 'name');
      Clock.tick();
      expect(runCount).toEqual(2);
      alice.age = 21;
      alice.bound('changed', 'age');
      Clock.tick();
      expect(runCount).toEqual(2);
    });

    xit('should update only the values associated with specified keys', function(){
    });

    xit('should expire all dependent computations when called with no command name', function(){
    });

    xit('should not result in re-runs of dependent contexts for setting properties to the same value they already hold', function(){
    });

    xit('should not re-run properties dependent on key inclusion when only the property value has changed, not its presence in the object', function(){
      // todo: tursify
      bound.proxy(alice);
      var runCount1 = 0;
      bound.autorun(function(){
        alice.bound('has', 'hamburger');
        runCount1 += 1;
      });
      var runCount2 = 0;
      bound.autorun(function(){
        alice.bound('get', 'name');
        runCount2 += 1;
      });
      alice.bound('set', 'name', 'al');
      Clock.tick();
      expect([runCount1, runCount2]).toEqual([1, 2]);
    });

    it('errors when passed an invalid command name', function(){
      var object = bound.proxy({});
      expect(function(){
        object.bound('invalidCommand')
      }).toThrow();
    });

  });

});
<|endoftext|>


<commit_before>/* eslint-disable guard-for-in, no-restricted-syntax, no-prototype-builtins */
exports.run = async (client, msg, [cmd]) => {
  const method = !client.config.selfbot ? "author" : "channel";
  cmd = client.commands.get(cmd) || client.commands.get(client.aliases.get(cmd));
  if (cmd) {
    return msg[method].sendCode("asciidoc", [
      `= ${cmd.help.name} = `,
      cmd.help.description,
      `usage :: ${cmd.usage.fullUsage(msg)}`,
      "Extended Help ::",
      cmd.help.extendedHelp ? cmd.help.extendedHelp : "No extended help available.",
    ]);
  }
  const help = this.buildHelp(client, msg);
  const helpMessage = [];
  for (const key in help) {
    helpMessage.push(`**${key} Commands**: \`\`\`asciidoc`);
    for (const key2 in help[key]) helpMessage.push(`= ${key2} =`, `${help[key][key2].join("\n")}\n`);
    helpMessage.push("```\n\u200b");
  }
  return msg[method].sendMessage(helpMessage, { split: { char: "\u200b" } }).catch(err => client.emit("error", err))
    .then(() => { if (msg.channel.type.toLowerCase() !== "dm" && !client.config.selfbot) msg.sendMessage("Commands have been sent to your DMs."); });
};

exports.conf = {
  enabled: true,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 0,
  botPerms: [],
  requiredFuncs: [],
};

exports.help = {
  name: "help",
  description: "Display help for a command.",
  usage: "[command:str]",
  usageDelim: "",
};

exports.buildHelp = (client, msg) => {
  const help = {};

  const commandNames = Array.from(client.commands.keys());
  const longest = commandNames.reduce((long, str) => Math.max(long, str.length), 0);

  client.commands.forEach((command) => {
    if (this.runCommandInhibitors(client, msg, command)) {
      const cat = command.help.category;
      const subcat = command.help.subCategory;
      if (!help.hasOwnProperty(cat)) help[cat] = {};
      if (!help[cat].hasOwnProperty(subcat)) help[cat][subcat] = [];
      help[cat][subcat].push(`${msg.guildConf.prefix}${command.help.name}${" ".repeat(longest - command.help.name.length)} :: ${command.help.description}`);
    }
  });

  return help;
};

exports.runCommandInhibitors = (client, msg, command) => !client.commandInhibitors.some((inhibitor) => {
  if (!inhibitor.conf.spamProtection && inhibitor.conf.enabled) return inhibitor.run(client, msg, command);
  return false;
});
<commit_msg>Ultra Micro Help Command Optimisation (#214)<commit_after>/* eslint-disable guard-for-in, no-restricted-syntax, no-prototype-builtins */
exports.run = async (client, msg, [cmd]) => {
  const method = !client.config.selfbot ? "author" : "channel";
  cmd = client.commands.get(cmd) || client.commands.get(client.aliases.get(cmd));
  if (cmd) {
    return msg[method].sendCode("asciidoc", [
      `= ${cmd.help.name} = `,
      cmd.help.description,
      `usage :: ${cmd.usage.fullUsage(msg)}`,
      "Extended Help ::",
      cmd.help.extendedHelp ? cmd.help.extendedHelp : "No extended help available.",
    ]);
  }
  const help = this.buildHelp(client, msg);
  const helpMessage = [];
  for (const key in help) {
    helpMessage.push(`**${key} Commands**: \`\`\`asciidoc`);
    for (const key2 in help[key]) helpMessage.push(`= ${key2} =`, `${help[key][key2].join("\n")}\n`);
    helpMessage.push("```\n\u200b");
  }
  return msg[method].sendMessage(helpMessage, { split: { char: "\u200b" } }).catch(err => client.emit("error", err))
    .then(() => { if (msg.channel.type !== "dm" && !client.config.selfbot) msg.sendMessage("Commands have been sent to your DMs."); });
};

exports.conf = {
  enabled: true,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 0,
  botPerms: [],
  requiredFuncs: [],
};

exports.help = {
  name: "help",
  description: "Display help for a command.",
  usage: "[command:str]",
  usageDelim: "",
};

exports.buildHelp = (client, msg) => {
  const help = {};

  const commandNames = Array.from(client.commands.keys());
  const longest = commandNames.reduce((long, str) => Math.max(long, str.length), 0);

  client.commands.forEach((command) => {
    if (this.runCommandInhibitors(client, msg, command)) {
      const cat = command.help.category;
      const subcat = command.help.subCategory;
      if (!help.hasOwnProperty(cat)) help[cat] = {};
      if (!help[cat].hasOwnProperty(subcat)) help[cat][subcat] = [];
      help[cat][subcat].push(`${msg.guildConf.prefix}${command.help.name}${" ".repeat(longest - command.help.name.length)} :: ${command.help.description}`);
    }
  });

  return help;
};

exports.runCommandInhibitors = (client, msg, command) => !client.commandInhibitors.some((inhibitor) => {
  if (!inhibitor.conf.spamProtection && inhibitor.conf.enabled) return inhibitor.run(client, msg, command);
  return false;
});
<|endoftext|>


<commit_before>'use strict';

const smoochBot = require('smooch-bot');
const MemoryLock = smoochBot.MemoryLock;
const SmoochApiStore = smoochBot.SmoochApiStore;
const SmoochApiBot = smoochBot.SmoochApiBot;
const StateMachine = smoochBot.StateMachine;
const app = require('../app');
const script = require('../script');
const SmoochCore = require('smooch-core');
const jwt = require('../jwt');
const fs = require('fs');

class BetterSmoochApiBot extends SmoochApiBot {
    constructor(options) {
        super(options);
    }

    sendImage(imageFileName) {
        const api = this.store.getApi();
        let message = Object.assign({
            role: 'appMaker'
        }, {
            name: this.name,
            avatarUrl: this.avatarUrl
        });

        let source = fs.readFileSync(imageFileName);
        return api.conversations.uploadImage(this.userId, source);
    }
}

const name = 'SmoochBot';
const avatarUrl = 'https://s.gravatar.com/avatar/f91b04087e0125153623a3778e819c0a?s=80';
const store = new SmoochApiStore({
    jwt
});
const lock = new MemoryLock();

function createWebhook(smoochCore, target) {
    return smoochCore.webhooks.create({
            target,
            triggers: ['message:appUser']
        })
        .then((res) => {
            console.log('Smooch webhook created at target', res.webhook.target);
        })
        .catch((err) => {
            console.error('Error creating Smooch webhook:', err);
            console.error(err.stack);
        });
}

// Create a webhook if one doesn't already exist
if (process.env.SERVICE_URL) {
    const target = process.env.SERVICE_URL.replace(/\/$/, '') + '/webhook';
    const smoochCore = new SmoochCore({
        jwt
    });
    smoochCore.webhooks.list()
        .then((res) => {
            if (!res.webhooks.some((w) => w.target === target)) {
                createWebhook(smoochCore, target);
            }
        });
}

app.post('/webhook', function(req, res, next) {
    const messages = req.body.messages.reduce((prev, current) => {
        if (current.role === 'appUser') {
            prev.push(current);
        }
        return prev;
    }, []);

    if (messages.length === 0) {
        return res.end();
    }

    const appUser = req.body.appUser;
    const userId = appUser.userId || appUser._id;
    const stateMachine = new StateMachine({
        script,
        bot: new BetterSmoochApiBot({
            name,
            avatarUrl,
            lock,
            store,
            userId
        })
    });

    stateMachine.receiveMessage(messages[0])
        .then(() => res.end())
        .catch((err) => {
            console.error('SmoochBot error:', err);
            console.error(err.stack);
            res.end();
        });
});

var server = app.listen(process.env.PORT || 8000, function() {
    var host = server.address().address;
    var port = server.address().port;

    console.log('Smooch Bot listening at http://%s:%s', host, port);
});<commit_msg>debugging<commit_after>'use strict';

const smoochBot = require('smooch-bot');
const MemoryLock = smoochBot.MemoryLock;
const SmoochApiStore = smoochBot.SmoochApiStore;
const SmoochApiBot = smoochBot.SmoochApiBot;
const StateMachine = smoochBot.StateMachine;
const app = require('../app');
const script = require('../script');
const SmoochCore = require('smooch-core');
const jwt = require('../jwt');
const fs = require('fs');

class BetterSmoochApiBot extends SmoochApiBot {
    constructor(options) {
        super(options);
    }

    sendImage(imageFileName) {
        const api = this.store.getApi();
        let message = Object.assign({
            role: 'appMaker'
        }, {
            name: this.name,
            avatarUrl: this.avatarUrl
        });
        console.log(__dirname);
        let source = fs.readFileSync(imageFileName);
        return api.conversations.uploadImage(this.userId, source);
    }
}

const name = 'SmoochBot';
const avatarUrl = 'https://s.gravatar.com/avatar/f91b04087e0125153623a3778e819c0a?s=80';
const store = new SmoochApiStore({
    jwt
});
const lock = new MemoryLock();

function createWebhook(smoochCore, target) {
    return smoochCore.webhooks.create({
            target,
            triggers: ['message:appUser']
        })
        .then((res) => {
            console.log('Smooch webhook created at target', res.webhook.target);
        })
        .catch((err) => {
            console.error('Error creating Smooch webhook:', err);
            console.error(err.stack);
        });
}

// Create a webhook if one doesn't already exist
if (process.env.SERVICE_URL) {
    const target = process.env.SERVICE_URL.replace(/\/$/, '') + '/webhook';
    const smoochCore = new SmoochCore({
        jwt
    });
    smoochCore.webhooks.list()
        .then((res) => {
            if (!res.webhooks.some((w) => w.target === target)) {
                createWebhook(smoochCore, target);
            }
        });
}

app.post('/webhook', function(req, res, next) {
    const messages = req.body.messages.reduce((prev, current) => {
        if (current.role === 'appUser') {
            prev.push(current);
        }
        return prev;
    }, []);

    if (messages.length === 0) {
        return res.end();
    }

    const appUser = req.body.appUser;
    const userId = appUser.userId || appUser._id;
    const stateMachine = new StateMachine({
        script,
        bot: new BetterSmoochApiBot({
            name,
            avatarUrl,
            lock,
            store,
            userId
        })
    });

    stateMachine.receiveMessage(messages[0])
        .then(() => res.end())
        .catch((err) => {
            console.error('SmoochBot error:', err);
            console.error(err.stack);
            res.end();
        });
});

var server = app.listen(process.env.PORT || 8000, function() {
    var host = server.address().address;
    var port = server.address().port;

    console.log('Smooch Bot listening at http://%s:%s', host, port);
});<|endoftext|>


<commit_before>'use strict';

var $http = require('request'),
    $q = require('q');

module.exports = function (req, res) {
    if (req.query && req.query.url) {

        $http.get({
                url: req.query.url,
                headers: {
                    'User-Agent': 'googlebot'
                }
            },
            function (err, response, html) {
                if (!err && +response.statusCode === +200) {

                    res.json({
                        html: html
                    });

                } else {
                    res.status(404).send('error status');
                }
            }).on('error', function (err) {
                res.status(404).send('error request');
            });
    } else {
        res.status(404).send('no url');
    }
};<commit_msg>fix decoding<commit_after>'use strict';

var $http = require('request'),
    $q = require('q');

module.exports = function (req, res) {
    if (req.query && req.query.url) {

        $http.get({
                url: req.query.url,
                headers: {
                    'User-Agent': 'googlebot'
                }
            },
            function (err, response, html) {
                if (!err && +response.statusCode === +200) {

                    res.json({
                        html: html
                    });

                } else {
                    res.status(404).json({
                        err: err,
                        response: response,
                        html: html
                    });
                }
            }).on('error', function (err) {
                res.status(404).send('error request');
            });
    } else {
        res.status(404).send('error url');
    }
};<|endoftext|>


<commit_before>//cron job that deletes photos that have all been played
var CronJob = require('cron').CronJob;
var redis = require('redis');
var client = require('../systems/rediscon.js');
var async = require('async')

module.exports = new CronJob('00 00 4 * * 0-6', function () {

    client.lrange('deletion', 0, -1, function (err, reply) {

        async.each(reply, function (snap_id, cb) {

            //delete from filesystem
            //delete snap data from redis
            //call cronjob from app.js

        }, function (err) {

        })

    })
});<commit_msg>Update imagepurge.js<commit_after>//cron job that deletes photos that have all been played
var CronJob = require('cron').CronJob;
var redis = require('redis');
var client = require('../systems/rediscon.js');
var async = require('async')

module.exports = new CronJob('00 00 4 * * 0-6', function () {

    client.lrange('deletion', 0, -1, function (err, reply) {

        async.each(reply, function (snap_id, cb) {

            //delete from filesystem
            //delete snap data from redis
            //call cronjob from app.js

            //Weird, I'm pretty sure I implemented this, but for some reason it's not on Github. Will have to check where the code went

        }, function (err) {

        })

    })
});
<|endoftext|>


<commit_before>var tmpdir = require('os').tmpdir;
var path = require('path');
var fs = require('fs');
var request = require('request');
var child = require('child_process');
var Progress = require('progress');

const BOOT2DOCKER_PKG = 'https://github.com/boot2docker/osx-installer/releases/download/v1.5.0/Boot2Docker-1.5.0.pkg';
const INHERIT_STDIO = { stdio: [0, 1, 2] };
const CHUNK_SIZE = 1024 * 10;

module.exports = function(topic) {
  return {
    topic: topic,
    command: 'boot2docker',
    description: 'installs boot2docker',
    help: `help text for ${topic}:install`,
    run: function(context) {
      downloadB2D()
        .then(installB2D)
        .then(showMessage)
        .catch(onFailure);
    }
  };
};

function downloadB2D() {
  console.log('downloading...');

  return new Promise(function(resolve, reject) {
    var outPath = path.join(tmpdir(), 'boot2docker.pkg');
    var size = 0;

    request
      .get(BOOT2DOCKER_PKG, { gzip: true })
      .on('response', onResponse)
      .on('error', reject)
      .pipe(fs.createWriteStream(outPath))
      .on('error', reject)
      .on('finish', resolve.bind(this, outPath));

    function onResponse(res) {
      var len = parseInt(res.headers['content-length'], 10);
      var bar = new Progress('  boot2docker [:bar] :percent', {
        complete: '=',
        incomplete: ' ',
        width: 20,
        total: len
      });

      res.on('data', function (chunk) {
        bar.tick(chunk.length);
      });

      res.on('end', function () {
        console.log('\n');
      });
    }
  });
}

function installB2D(pkg) {
  try {
    console.log('installing...');
    child.execSync('open -W ' + pkg, INHERIT_STDIO);
    console.log('initializing boot2docker vm...');
    child.execSync('boot2docker init', INHERIT_STDIO);
    console.log('upgrading boot2docker...');
    child.execSync('boot2docker upgrade', INHERIT_STDIO);
    return Promise.resolve();
  }
  catch (e) {
    return Promise.reject(e);
  }
}

function showMessage() {
  console.log('\n\n');
  console.log('Remember to always start boot2docker before using this plugin:\n');
  console.log('boot2docker start');
  console.log('$(boot2docker shellinit)');
  return Promise.resolve();
}

function onFailure(err) {
  console.log('Installation failed:', err.stack);
}
<commit_msg>progress on b2d<commit_after>var tmpdir = require('os').tmpdir;
var path = require('path');
var fs = require('fs');
var request = require('request');
var child = require('child_process');
var Progress = require('progress');

const BOOT2DOCKER_PKG = 'https://github.com/boot2docker/osx-installer/releases/download/v1.5.0/Boot2Docker-1.5.0.pkg';
const INHERIT_STDIO = { stdio: [0, 1, 2] };
const CHUNK_SIZE = 1024 * 10;

module.exports = function(topic) {
  return {
    topic: topic,
    command: 'boot2docker',
    description: 'installs boot2docker',
    help: `help text for ${topic}:install`,
    run: function(context) {
      stopB2D();
      downloadB2D()
        .then(installB2D)
        .then(showMessage)
        .catch(onFailure);
    }
  };
};

function downloadB2D() {
  console.log('downloading...');

  return new Promise(function(resolve, reject) {
    var outPath = path.join(tmpdir(), 'boot2docker.pkg');
    var size = 0;

    request
      .get(BOOT2DOCKER_PKG, { gzip: true })
      .on('response', onResponse)
      .on('error', reject)
      .pipe(fs.createWriteStream(outPath))
      .on('error', reject)
      .on('finish', resolve.bind(this, outPath));

    function onResponse(res) {
      var len = parseInt(res.headers['content-length'], 10);
      var bar = new Progress('  boot2docker [:bar] :percent', {
        complete: '=',
        incomplete: ' ',
        width: 20,
        total: len
      });

      res.on('data', function (chunk) {
        bar.tick(chunk.length);
      });

      res.on('end', function () {
        console.log('\n');
      });
    }
  });
}

function installB2D(pkg) {
  try {
    console.log('installing...');
    child.execSync('open -W ' + pkg, INHERIT_STDIO);
    console.log('initializing boot2docker vm...');
    child.execSync('boot2docker init', INHERIT_STDIO);
    console.log('upgrading boot2docker...');
    child.execSync('boot2docker upgrade', INHERIT_STDIO);
    return Promise.resolve();
  }
  catch (e) {
    return Promise.reject(e);
  }
}

function showMessage() {
  console.log('\n\n');
  console.log('Remember to always start boot2docker before using this plugin:\n');
  console.log('boot2docker start');
  console.log('$(boot2docker shellinit)');
  return Promise.resolve();
}

function onFailure(err) {
  console.log('Installation failed:', err.stack);
}
<|endoftext|>


<commit_before>import showdown from 'showdown'
import dompurify from 'dompurify'
import hash from 'string-hash'
import ColorHash from 'color-hash'
import { escape } from './escape'

const COLOR_HASH = new ColorHash()

const MINUTE = 60
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR

const converter = new showdown.Converter()
converter.setFlavor('github')

export function range(val, min, max, def) {
    return typeof val !== 'number' ? def : Math.max(min, Math.min(val, max))
}

function resolvePostId(id) {
    if (typeof id !== 'number' || id < 1)
        id = hash(window.location.hostname + window.location.pathname)

    return id
}

function resolveWsHost(rpc_host) {
    return !rpc_host ? ('ws' + window.location.protocol.substring(4) + '//' + window.location.host) :
            ('ws' + rpc_host.substring(4))
}

function createCompatConfig(target, src) {
    var rpc_host = src['rpc_host'],
        auth_host = src['auth_host'],
        limit_depth = src['comments_max_depth'],
        collapse_depth = src['comments_collapse_depth']

    if (rpc_host) target.rpc_host = rpc_host
    if (auth_host) target.auth_host = auth_host
    if (limit_depth) target.limit_depth = limit_depth
    if (collapse_depth) target.collapse_depth = collapse_depth

    return target
}

export const CONFIG = window['comments_config'] || createCompatConfig({}, window),
    POST_ID = resolvePostId(CONFIG['post_id']),
    UI_FLAGS = range(CONFIG['ui_flags'], 0, 15, 0),
    WITH_WS = !!CONFIG['ws_enabled'],
    WS_HOST = !WITH_WS ? '' : (CONFIG['ws_host'] || resolveWsHost(CONFIG['rpc_host'])),
    WS_RECONNECT_SECS = !WITH_WS ? 0 : range(CONFIG['ws_reconnect_secs'], 1, 60*60, 10),
    AUTH_HOST = CONFIG['auth_host'],
    WITH_AUTH = !!AUTH_HOST,
    AUTH_PROXY = !WITH_AUTH ? '' : (CONFIG['auth_proxy'] || (AUTH_HOST + '/iframe/')),
    AUTH_GOOGLE = 1,
    AUTH_GITHUB = 2,
    AUTH_GITLAB = 4,
    AUTH_FLAGS = range(CONFIG['auth_flags'], 1, 0xFF, 0x07),
    AUTH_OPEN_WINDOW = 0 !== (AUTH_FLAGS & 0x80),
    LIMIT_DEPTH = range(CONFIG['limit_depth'], 0, 127, 7),
    COLLAPSE_DEPTH = range(CONFIG['collapse_depth'], -1, 127, -1),
    CONTENT_LIMIT = range(CONFIG['content_limit'], 0, 8192, 0),
    CONTENT_ERRMSG = 'The content is too long',
    NAME_ERRMSG = 'Name cannot be more than 64 characters'

export const context = {
    raw_items: [],
    items: [],
    root$: null,
    reply$: null,
    refresh$: null
}

function plural(num, unit, suffix) {
    num = ~~num
    var buf = ''
    buf += num
    buf += ' '
    buf += unit
    if (num !== 1)
        buf += 's'
    if (suffix)
        buf += suffix

    return buf
}

export function pluralize(num, str, suffix, with_num) {
    var buf = ''
    if (with_num)
        buf += num
    buf += str
    if (num > 1)
        buf += (suffix || 's')
    return buf
}

export function delayEventHandler(obj, key, timeout) {
    return function (e) {
        window.setTimeout(function () { obj[key](e) }, timeout)
    }
}

export function sanitize(str) {
    return dompurify.sanitize(str)
}

export function toHexColor(str) {
    return COLOR_HASH.hex(str)
}

export function toHTML(md) {
    return sanitize(converter.makeHtml(md))
}

export function timebetween(a, b, suffix) {
    const elapsed = b - a;

    if (elapsed === 0) {
        return 'just moments' + suffix
    } else if (elapsed < MINUTE) {
        return plural(elapsed, 'second', suffix);
    } else if (elapsed < HOUR) {
        return plural(elapsed / MINUTE, 'minute', suffix);
    } else if (elapsed < DAY) {
        return plural(elapsed / HOUR, 'hour', suffix);
    } else {
        return plural(elapsed / DAY, 'day', suffix);
    }
}

export function append() {
    return Array.prototype.slice.call(arguments).join(' ').trim()
}

export function timeago(ts) {
    return timebetween(Math.floor(ts/1000), Math.floor(Date.now()/1000), ' ago')
}

export function plus_minus(collapsed, count) {
    if (!collapsed)
        return '-'
    else if (!count)
        return '+'
    else
        return '+' + count
}

export function extractMsg(data) {
    //return Array.isArray(data) && data[1]['1'] || String(data)
    return Array.isArray(data) ? data[1]['1'] : String(data);
}

// ==================================================

export function toFetchPayload(items, parent) {
    let suffix = !items || !items.length ? '' : `,"2":"${items[items.length - 1]['1']}"`
    if (!parent)
        return `{"1":${POST_ID}${suffix}}`

    return `{"1":${POST_ID}${suffix},"3":"${parent['1']}"}`
}

export function toPayload(name, content, reply) {
    let items = !reply ? context.items : reply.children
    // lastSeenKey
    let prefix = !items.length ? '' : `"1":"${items[items.length - 1]['1']}",`
    // parentKey
    let suffix = !reply ? '' : `,"8":"${reply['1']}"`
    return `{${prefix}"4":"${escape(name)}","5":"${escape(content)}","6":${POST_ID}${suffix}}`
}

function inc(parent) {
    do {
        parent.total_child_count++
        parent = parent.parent
    } while (parent)
}

function fillItem(item, parent, fromSubmit) {
    item.collapsed = !fromSubmit && COLLAPSE_DEPTH >= 0 && item['7'] >= COLLAPSE_DEPTH
    item.parent = parent
    item.total_child_count = 0
    item.children = []
    item.map = {}
}

function addTo(parent, item, fromSubmit) {
    var key = item['1'],
        existing = parent.map[key]
    if (existing)
        return existing

    fillItem(item, parent, fromSubmit)
    item.parent = parent
    parent.children.push(item)
    parent.map[key] = item
    inc(parent)

    return existing
}

export function toTree(raw_items, items, m, parent, fromSubmit) {
    let map = !parent ? m.root_map : parent.map,
        start_depth = !parent ? 0 : 1 + parent['7'],
        last_item = !items.length ? null : items[items.length - 1],
        last_depth = !last_item ? start_depth : last_item['7'],
        count = 0,
        item,
        depth,
        key

    for (var i = 0, len = raw_items.length; i < len; i++) {
        item = raw_items[i]
        depth = item['7']
        if (start_depth === depth) {
            key = item['1']
            last_depth = depth
            if ((last_item = map[key])) continue
            last_item = item
            count++
            fillItem(item, parent, fromSubmit)
            items.push(item)
            map[key] = item
            parent && inc(parent)
            continue
        }

        if (depth === last_depth) {
            if (!(last_item = addTo(last_item.parent, item, fromSubmit))) {
                last_item = item
                count++
            }
            continue
        }
        if (depth > last_depth) {
            last_depth = depth
            if (!(last_item = addTo(last_item, item, fromSubmit))) {
                last_item = item
                count++
            }
            continue
        }

        do {
            last_item = last_item.parent
        } while (depth < last_item['7'])

        last_depth = depth
        if (!(last_item = addTo(last_item.parent, item, fromSubmit))) {
            last_item = item
            count++
        }
    }

    m.total_count += count

    return items
}

const href = window.location.href,
    fnEvent = window.addEventListener || window.attachEvent,
    keyEvent = !window.addEventListener ? 'onmessage' : 'message',
    alphanumeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

export function randomText(len) {
    var text = ''
    for(var i = 0; i < len; i++)
        text += alphanumeric.charAt(Math.floor(Math.random() * alphanumeric.length))

    return text
}

function openWindow(path) {
    var w = window.open(path, 'Login', 'width=450,height=500,location=1,status=1,resizable=yes')
    w && w.moveTo(window.innerWidth/2 - (450/2), window.innerHeight/2 - (500/2))
}

var pmpage, pmid, iframe
export function popAuth(type) {
    pmid = randomText(10)
    if (AUTH_OPEN_WINDOW) {
        openWindow(AUTH_PROXY + '#' + pmid + '~' + type + '~' + href)
        return
    }

    if (!iframe) {
        iframe = document.createElement('iframe')
        iframe.style.width = '100%'
        iframe.style.border = 'none'
        document.body.appendChild(iframe)
    }
    // always load
    pmpage = pmpage ? '' : type + '.html'

    iframe.src = AUTH_PROXY + pmpage + '#' + pmid + '~' + type + '~' + href
}

function onAuth(e) {
    var msg = e.data,
        array = typeof msg === 'string' ? JSON.parse(msg) : msg
    if (!Array.isArray(array) || array.length !== 3 || array[2] !== pmid) return

    var type = array[0], data = array[1]
    if (!type || !data || !data.es_token) {
        context.root$.auth$$F(data || 'Auth failed.')
    } else {
        context.root$.auth$$S(data)
    }
}

fnEvent(keyEvent, onAuth, false)
<commit_msg>pass auth_host to proxy<commit_after>import showdown from 'showdown'
import dompurify from 'dompurify'
import hash from 'string-hash'
import ColorHash from 'color-hash'
import { escape } from './escape'

const COLOR_HASH = new ColorHash()

const MINUTE = 60
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR

const converter = new showdown.Converter()
converter.setFlavor('github')

export function range(val, min, max, def) {
    return typeof val !== 'number' ? def : Math.max(min, Math.min(val, max))
}

function resolvePostId(id) {
    if (typeof id !== 'number' || id < 1)
        id = hash(window.location.hostname + window.location.pathname)

    return id
}

function resolveWsHost(rpc_host) {
    return !rpc_host ? ('ws' + window.location.protocol.substring(4) + '//' + window.location.host) :
            ('ws' + rpc_host.substring(4))
}

function createCompatConfig(target, src) {
    var rpc_host = src['rpc_host'],
        auth_host = src['auth_host'],
        limit_depth = src['comments_max_depth'],
        collapse_depth = src['comments_collapse_depth']

    if (rpc_host) target.rpc_host = rpc_host
    if (auth_host) target.auth_host = auth_host
    if (limit_depth) target.limit_depth = limit_depth
    if (collapse_depth) target.collapse_depth = collapse_depth

    return target
}

export const CONFIG = window['comments_config'] || createCompatConfig({}, window),
    POST_ID = resolvePostId(CONFIG['post_id']),
    UI_FLAGS = range(CONFIG['ui_flags'], 0, 15, 0),
    WITH_WS = !!CONFIG['ws_enabled'],
    WS_HOST = !WITH_WS ? '' : (CONFIG['ws_host'] || resolveWsHost(CONFIG['rpc_host'])),
    WS_RECONNECT_SECS = !WITH_WS ? 0 : range(CONFIG['ws_reconnect_secs'], 1, 60*60, 10),
    AUTH_HOST = CONFIG['auth_host'],
    WITH_AUTH = !!AUTH_HOST,
    AUTH_PROXY = !WITH_AUTH ? '' : (CONFIG['auth_proxy'] || (AUTH_HOST + '/iframe/')),
    AUTH_GOOGLE = 1,
    AUTH_GITHUB = 2,
    AUTH_GITLAB = 4,
    AUTH_FLAGS = range(CONFIG['auth_flags'], 1, 0xFF, 0x07),
    AUTH_OPEN_WINDOW = 0 !== (AUTH_FLAGS & 0x80),
    LIMIT_DEPTH = range(CONFIG['limit_depth'], 0, 127, 7),
    COLLAPSE_DEPTH = range(CONFIG['collapse_depth'], -1, 127, -1),
    CONTENT_LIMIT = range(CONFIG['content_limit'], 0, 8192, 0),
    CONTENT_ERRMSG = 'The content is too long',
    NAME_ERRMSG = 'Name cannot be more than 64 characters'

export const context = {
    raw_items: [],
    items: [],
    root$: null,
    reply$: null,
    refresh$: null
}

function plural(num, unit, suffix) {
    num = ~~num
    var buf = ''
    buf += num
    buf += ' '
    buf += unit
    if (num !== 1)
        buf += 's'
    if (suffix)
        buf += suffix

    return buf
}

export function pluralize(num, str, suffix, with_num) {
    var buf = ''
    if (with_num)
        buf += num
    buf += str
    if (num > 1)
        buf += (suffix || 's')
    return buf
}

export function delayEventHandler(obj, key, timeout) {
    return function (e) {
        window.setTimeout(function () { obj[key](e) }, timeout)
    }
}

export function sanitize(str) {
    return dompurify.sanitize(str)
}

export function toHexColor(str) {
    return COLOR_HASH.hex(str)
}

export function toHTML(md) {
    return sanitize(converter.makeHtml(md))
}

export function timebetween(a, b, suffix) {
    const elapsed = b - a;

    if (elapsed === 0) {
        return 'just moments' + suffix
    } else if (elapsed < MINUTE) {
        return plural(elapsed, 'second', suffix);
    } else if (elapsed < HOUR) {
        return plural(elapsed / MINUTE, 'minute', suffix);
    } else if (elapsed < DAY) {
        return plural(elapsed / HOUR, 'hour', suffix);
    } else {
        return plural(elapsed / DAY, 'day', suffix);
    }
}

export function append() {
    return Array.prototype.slice.call(arguments).join(' ').trim()
}

export function timeago(ts) {
    return timebetween(Math.floor(ts/1000), Math.floor(Date.now()/1000), ' ago')
}

export function plus_minus(collapsed, count) {
    if (!collapsed)
        return '-'
    else if (!count)
        return '+'
    else
        return '+' + count
}

export function extractMsg(data) {
    //return Array.isArray(data) && data[1]['1'] || String(data)
    return Array.isArray(data) ? data[1]['1'] : String(data);
}

// ==================================================

export function toFetchPayload(items, parent) {
    let suffix = !items || !items.length ? '' : `,"2":"${items[items.length - 1]['1']}"`
    if (!parent)
        return `{"1":${POST_ID}${suffix}}`

    return `{"1":${POST_ID}${suffix},"3":"${parent['1']}"}`
}

export function toPayload(name, content, reply) {
    let items = !reply ? context.items : reply.children
    // lastSeenKey
    let prefix = !items.length ? '' : `"1":"${items[items.length - 1]['1']}",`
    // parentKey
    let suffix = !reply ? '' : `,"8":"${reply['1']}"`
    return `{${prefix}"4":"${escape(name)}","5":"${escape(content)}","6":${POST_ID}${suffix}}`
}

function inc(parent) {
    do {
        parent.total_child_count++
        parent = parent.parent
    } while (parent)
}

function fillItem(item, parent, fromSubmit) {
    item.collapsed = !fromSubmit && COLLAPSE_DEPTH >= 0 && item['7'] >= COLLAPSE_DEPTH
    item.parent = parent
    item.total_child_count = 0
    item.children = []
    item.map = {}
}

function addTo(parent, item, fromSubmit) {
    var key = item['1'],
        existing = parent.map[key]
    if (existing)
        return existing

    fillItem(item, parent, fromSubmit)
    item.parent = parent
    parent.children.push(item)
    parent.map[key] = item
    inc(parent)

    return existing
}

export function toTree(raw_items, items, m, parent, fromSubmit) {
    let map = !parent ? m.root_map : parent.map,
        start_depth = !parent ? 0 : 1 + parent['7'],
        last_item = !items.length ? null : items[items.length - 1],
        last_depth = !last_item ? start_depth : last_item['7'],
        count = 0,
        item,
        depth,
        key

    for (var i = 0, len = raw_items.length; i < len; i++) {
        item = raw_items[i]
        depth = item['7']
        if (start_depth === depth) {
            key = item['1']
            last_depth = depth
            if ((last_item = map[key])) continue
            last_item = item
            count++
            fillItem(item, parent, fromSubmit)
            items.push(item)
            map[key] = item
            parent && inc(parent)
            continue
        }

        if (depth === last_depth) {
            if (!(last_item = addTo(last_item.parent, item, fromSubmit))) {
                last_item = item
                count++
            }
            continue
        }
        if (depth > last_depth) {
            last_depth = depth
            if (!(last_item = addTo(last_item, item, fromSubmit))) {
                last_item = item
                count++
            }
            continue
        }

        do {
            last_item = last_item.parent
        } while (depth < last_item['7'])

        last_depth = depth
        if (!(last_item = addTo(last_item.parent, item, fromSubmit))) {
            last_item = item
            count++
        }
    }

    m.total_count += count

    return items
}

const href = window.location.href,
    fnEvent = window.addEventListener || window.attachEvent,
    keyEvent = !window.addEventListener ? 'onmessage' : 'message',
    alphanumeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

export function randomText(len) {
    var text = ''
    for(var i = 0; i < len; i++)
        text += alphanumeric.charAt(Math.floor(Math.random() * alphanumeric.length))

    return text
}

function openWindow(path) {
    var w = window.open(path, 'Login', 'width=450,height=500,location=1,status=1,resizable=yes')
    w && w.moveTo(window.innerWidth/2 - (450/2), window.innerHeight/2 - (500/2))
}

var pmpage, pmid, iframe
export function popAuth(type) {
    pmid = randomText(10)
    if (AUTH_OPEN_WINDOW) {
        openWindow(AUTH_PROXY + '#' + pmid + '~' + type + '~' + AUTH_HOST + '~' + href)
        return
    }

    if (!iframe) {
        iframe = document.createElement('iframe')
        iframe.style.width = '100%'
        iframe.style.border = 'none'
        document.body.appendChild(iframe)
    }
    // always load
    pmpage = pmpage ? '' : type + '.html'

    iframe.src = AUTH_PROXY + pmpage + '#' + pmid + '~' + type + '~' + href
}

function onAuth(e) {
    var msg = e.data,
        array = typeof msg === 'string' ? JSON.parse(msg) : msg
    if (!Array.isArray(array) || array.length !== 3 || array[2] !== pmid) return

    var type = array[0], data = array[1]
    if (!type || !data || !data.es_token) {
        context.root$.auth$$F(data || 'Auth failed.')
    } else {
        context.root$.auth$$S(data)
    }
}

fnEvent(keyEvent, onAuth, false)
<|endoftext|>


<commit_before>var request = require('request-promise');

module.exports = function (context, message) {

    let path = '/' + message.social.facebook.id + '?fields=id,picture,place,name,comments,reactions';

    let options = {
        uri: "https://graph.facebook.com" + path,
        method: 'GET',
        headers: {
            'Authorization': 'OAuth ' + message.social.facebook.token
        }
    };

    request(options)
        .then((response) => {
            let data = message;

            data.response = {
                platform: "facebook",
                type: "media",
                data: response
            };

            context.bindings.out = data;
        })
        .catch((error) => context.log(error))
        .finally(() => context.done());
}<commit_msg>Converting response to JSON object (from string)<commit_after>var request = require('request-promise');

module.exports = function (context, message) {

    let path = '/' + message.social.facebook.id + '?fields=id,picture,place,name,comments,reactions';

    let options = {
        uri: "https://graph.facebook.com" + path,
        method: 'GET',
        headers: {
            'Authorization': 'OAuth ' + message.social.facebook.token
        }
    };

    request(options)
        .then((response) => {
            let data = message;

            data.response = {
                platform: "facebook",
                type: "media",
                data: JSON.parse(response)
            };

            context.bindings.out = data;
        })
        .catch((error) => context.log(error))
        .finally(() => context.done());
}<|endoftext|>