<commit_before>var assert = require('assert');
var syntax = require('../lib');
var parse = require('../lib').parse;
var TYPE = require('../lib').Tokenizer.TYPE;
var toPlainObject = require('../lib').toPlainObject;
var walk = require('../lib').walk;
var lexer = require('../lib').lexer;
var translate = require('../lib').translate;
var List = require('../lib').List;
var forEachParseTest = require('./fixture/parse').forEachTest;
var stringify = require('./helpers/stringify');
var merge = require('./helpers').merge;

function repeat(str, count) {
    return new Array(count + 1).join(str);
}

function createParseErrorTest(name, test, options) {
    (test.skip ? it.skip : it)(name + ' ' + JSON.stringify(test.source), function() {
        var error;

        assert.throws(function() {
            parse(test.source, options);
        }, function(e) {
            error = e;
            if (e.parseError) {
                return true;
            }
        }, 'Should be a CSS parse error');

        assert.equal(error.message, test.error);
        assert.deepEqual(error.parseError, test.position);
    });
}

describe('parse', function() {
    describe('basic', function() {
        forEachParseTest(function createParseTest(name, test) {
            (test.skip ? it.skip : it)(name, function() {
                var ast = parse(test.source, test.options);

                // AST should be equal
                assert.equal(stringify(ast), stringify(test.ast));

                // translated AST should be equal to original source
                assert.equal(translate(ast), 'translate' in test ? test.translate : test.source);

                // structure should be ok
                assert.equal(lexer.checkStructure(ast), false);
            });
        });
    });

    describe('context', function() {
        it('should take parse context', function() {
            assert.throws(function() {
                parse('property: value');
            }, /Identifier is expected/);

            assert.deepEqual(parse('property: value', {
                context: 'declaration'
            }), {
                type: 'Declaration',
                loc: null,
                important: false,
                property: 'property',
                value: {
                    type: 'Value',
                    loc: null,
                    children: new List().appendData({
                        type: 'Identifier',
                        loc: null,
                        name: 'value'
                    })
                }
            });
        });

        it('wrong context', function() {
            assert.throws(function() {
                parse('a{}', { context: 'unknown' });
            }, /Unknown context `unknown`/);
        });
    });

    describe('tolerant', function() {
        it('should not fail on parse', function() {
            assert.throws(function() {
                parse('{ foo }', {
                    context: 'block'
                });
            }, /Colon is expected/);

            assert.deepEqual(parse('{ foo }', {
                context: 'block',
                tolerant: true
            }), {
                type: 'Block',
                loc: null,
                children: new List().appendData({
                    type: 'Raw',
                    loc: null,
                    value: 'foo'
                })
            });
        });

        it('should call onParseError when handler is passed', function() {
            var errors = [];
            var ast = parse('{ a: 1!; foo; b: 2 }', {
                context: 'block',
                tolerant: true,
                onParseError: function(error) {
                    errors.push(error);
                }
            });

            assert.equal(ast.children.getSize(), 3);
            assert.equal(errors.length, 2);
            assert.equal(errors[0].message, 'Identifier is expected');
            assert.equal(errors[1].message, 'Colon is expected');
        });
    });

    describe('errors', function() {
        forEachParseTest(function(name, test) {
            createParseErrorTest(name, test, merge(test.options, {
                positions: false
            }));
            createParseErrorTest(name + ' (with positions)', test, merge(test.options, {
                positions: true
            }));
        }, true);

        it('formattedMessage', function() {
            try {
                parse('/**/\n.\nfoo');
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Identifier is expected\n' +
                    '    1 |/**/\n' +
                    '    2 |.\n' +
                    '--------^\n' +
                    '    3 |foo'
                );
                assert.equal(e.sourceFragment(),
                    '    2 |.\n' +
                    '--------^\n'
                );
                assert.equal(e.sourceFragment(3),
                    '    1 |/**/\n' +
                    '    2 |.\n' +
                    '--------^\n' +
                    '    3 |foo'
                );
            }
        });

        it('formattedMessage with tabs', function() {
            try {
                parse('a {\n\tb:\tc#\t\n}');
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Number or identifier is expected\n' +
                    '    1 |a {\n' +
                    '    2 |    b:    c#    \n' +
                    '-------------------^\n' +
                    '    3 |}'
                );
            }
        });

        it('formattedMessage for source with long lines', function() {
            try {
                parse(
                    '/*' + repeat('1234567890', 20) + '*/\n' +
                    repeat(' ', 117) + '.\n' +
                    'foo\n' +
                    repeat(' ', 120) + 'bar'
                );
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Identifier is expected\n' +
                    '    1 |…12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678…\n' +
                    '    2 |…                                                       .\n' +
                    '----------------------------------------------------------------^\n' +
                    '    3 |\n' +
                    '    4 |…                                                          bar'
                );
            }
        });
    });

    describe('positions', function() {
        it('should start with line 1 column 1 by default', function() {
            var ast = parse('.foo.bar {\n  property: value 123 123.4 .123 123px 99% #fff url( a ) / var( --a ), "test" \'test\';\n}', {
                positions: true
            });
            var positions = [];

            walk(ast, function(node) {
                if (node.loc) {
                    positions.push([
                        node.loc.start.offset,
                        node.loc.start.line,
                        node.loc.start.column,
                        node.type
                    ]);
                }
            });

            assert.equal(lexer.checkStructure(ast), false);
            assert.deepEqual(positions, [
                [0, 1, 1, 'StyleSheet'],
                [0, 1, 1, 'Rule'],
                [0, 1, 1, 'SelectorList'],
                [0, 1, 1, 'Selector'],
                [0, 1, 1, 'ClassSelector'],
                [4, 1, 5, 'ClassSelector'],
                [9, 1, 10, 'Block'],
                [13, 2, 3, 'Declaration'],
                [22, 2, 12, 'Value'],
                [23, 2, 13, 'Identifier'],
                [29, 2, 19, 'Number'],
                [33, 2, 23, 'Number'],
                [39, 2, 29, 'Number'],
                [44, 2, 34, 'Dimension'],
                [50, 2, 40, 'Percentage'],
                [54, 2, 44, 'HexColor'],
                [59, 2, 49, 'Url'],
                [64, 2, 54, 'Raw'],
                [68, 2, 58, 'Operator'],
                [70, 2, 60, 'Function'],
                [75, 2, 65, 'Identifier'],
                [80, 2, 70, 'Operator'],
                [82, 2, 72, 'String'],
                [89, 2, 79, 'String']
            ]);
        });

        it('should start with specified offset, line and column', function() {
            var ast = parse('.foo.bar {\n  property: value 123 123.4 .123 123px 99% #fff url( a ) / var( --a ), "test" \'test\';\n}', {
                positions: true,
                offset: 100,
                line: 3,
                column: 5
            });
            var positions = [];

            walk(ast, function(node) {
                if (node.loc) {
                    positions.push([
                        node.loc.start.offset,
                        node.loc.start.line,
                        node.loc.start.column,
                        node.type
                    ]);
                }
            });

            assert.equal(lexer.checkStructure(ast), false);
            assert.deepEqual(positions, [
                [100, 3, 5, 'StyleSheet'],
                [100, 3, 5, 'Rule'],
                [100, 3, 5, 'SelectorList'],
                [100, 3, 5, 'Selector'],
                [100, 3, 5, 'ClassSelector'],
                [104, 3, 9, 'ClassSelector'],
                [109, 3, 14, 'Block'],
                [113, 4, 3, 'Declaration'],
                [122, 4, 12, 'Value'],
                [123, 4, 13, 'Identifier'],
                [129, 4, 19, 'Number'],
                [133, 4, 23, 'Number'],
                [139, 4, 29, 'Number'],
                [144, 4, 34, 'Dimension'],
                [150, 4, 40, 'Percentage'],
                [154, 4, 44, 'HexColor'],
                [159, 4, 49, 'Url'],
                [164, 4, 54, 'Raw'],
                [168, 4, 58, 'Operator'],
                [170, 4, 60, 'Function'],
                [175, 4, 65, 'Identifier'],
                [180, 4, 70, 'Operator'],
                [182, 4, 72, 'String'],
                [189, 4, 79, 'String']
            ]);
        });
    });

    describe('extension', function() {
        describe('value', function() {
            var extended = syntax.fork(function(syntaxConfig) {
                var defaultGetNode = syntaxConfig.scope.Value.getNode;

                syntaxConfig.scope.Value.getNode = function(context) {
                    if (this.scanner.tokenType === TYPE.DollarSign) {
                        var start = this.scanner.tokenStart;
                        this.scanner.next();

                        return {
                            type: 'Variable',
                            loc: this.getLocation(start, this.scanner.tokenEnd),
                            name: this.scanner.consume(TYPE.Identifier)
                        };
                    }

                    return defaultGetNode.call(this, context);
                };

                return syntaxConfig;
            });

            it('should not affect base syntax', function() {
                assert.throws(function() {
                    parse('$a', {
                        context: 'value'
                    });
                }, /Unexpected input/);
            });

            it('should parse according new rules', function() {
                var ast = extended.parse('$a', {
                    context: 'value'
                });

                assert.deepEqual(toPlainObject(ast), {
                    type: 'Value',
                    loc: null,
                    children: [
                        {
                            type: 'Variable',
                            loc: null,
                            name: 'a'
                        }
                    ]
                });
            });

            it('should fail on unknown', function() {
                assert.throws(function() {
                    extended.parse('@a', {
                        context: 'value'
                    });
                }, /Unexpected input/);
            });
        });

        describe('selector', function() {
            var extended = syntax.fork(function(syntaxConfig) {
                var defaultGetNode = syntaxConfig.scope.Selector.getNode;

                syntaxConfig.scope.Selector.getNode = function(context) {
                    if (this.scanner.tokenType === TYPE.Ampersand) {
                        var start = this.scanner.tokenStart;
                        this.scanner.next();

                        return {
                            type: 'Nested',
                            loc: this.getLocation(start, this.scanner.tokenEnd)
                        };
                    }

                    return defaultGetNode.call(this, context);
                };

                return syntaxConfig;
            });

            it('should not affect base syntax', function() {
                assert.throws(function() {
                    parse('a &', {
                        context: 'selector'
                    });
                }, /Unexpected input/);
            });

            it('should parse according new rules', function() {
                var ast = extended.parse('a &', {
                    context: 'selector'
                });

                assert.deepEqual(toPlainObject(ast), {
                    type: 'Selector',
                    loc: null,
                    children: [
                        {
                            type: 'TypeSelector',
                            loc: null,
                            name: 'a'
                        },
                        {
                            type: 'WhiteSpace',
                            loc: null,
                            value: ' '
                        },
                        {
                            type: 'Nested',
                            loc: null
                        }
                    ]
                });
            });

            it('should fail on unknown', function() {
                assert.throws(function() {
                    extended.parse('@a', {
                        context: 'selector'
                    });
                }, /Selector is expected/);
            });
        });
    });
});
<commit_msg>remove redundant translate check in parser tests<commit_after>var assert = require('assert');
var syntax = require('../lib');
var parse = require('../lib').parse;
var TYPE = require('../lib').Tokenizer.TYPE;
var toPlainObject = require('../lib').toPlainObject;
var walk = require('../lib').walk;
var lexer = require('../lib').lexer;
var translate = require('../lib').translate;
var List = require('../lib').List;
var forEachParseTest = require('./fixture/parse').forEachTest;
var stringify = require('./helpers/stringify');
var merge = require('./helpers').merge;

function repeat(str, count) {
    return new Array(count + 1).join(str);
}

function createParseErrorTest(name, test, options) {
    (test.skip ? it.skip : it)(name + ' ' + JSON.stringify(test.source), function() {
        var error;

        assert.throws(function() {
            parse(test.source, options);
        }, function(e) {
            error = e;
            if (e.parseError) {
                return true;
            }
        }, 'Should be a CSS parse error');

        assert.equal(error.message, test.error);
        assert.deepEqual(error.parseError, test.position);
    });
}

describe('parse', function() {
    describe('basic', function() {
        forEachParseTest(function createParseTest(name, test) {
            (test.skip ? it.skip : it)(name, function() {
                var ast = parse(test.source, test.options);

                // AST should be equal
                assert.equal(stringify(ast), stringify(test.ast));

                // structure should be correct
                assert.equal(lexer.checkStructure(ast), false);
            });
        });
    });

    describe('context', function() {
        it('should take parse context', function() {
            assert.throws(function() {
                parse('property: value');
            }, /Identifier is expected/);

            assert.deepEqual(parse('property: value', {
                context: 'declaration'
            }), {
                type: 'Declaration',
                loc: null,
                important: false,
                property: 'property',
                value: {
                    type: 'Value',
                    loc: null,
                    children: new List().appendData({
                        type: 'Identifier',
                        loc: null,
                        name: 'value'
                    })
                }
            });
        });

        it('wrong context', function() {
            assert.throws(function() {
                parse('a{}', { context: 'unknown' });
            }, /Unknown context `unknown`/);
        });
    });

    describe('tolerant', function() {
        it('should not fail on parse', function() {
            assert.throws(function() {
                parse('{ foo }', {
                    context: 'block'
                });
            }, /Colon is expected/);

            assert.deepEqual(parse('{ foo }', {
                context: 'block',
                tolerant: true
            }), {
                type: 'Block',
                loc: null,
                children: new List().appendData({
                    type: 'Raw',
                    loc: null,
                    value: 'foo'
                })
            });
        });

        it('should call onParseError when handler is passed', function() {
            var errors = [];
            var ast = parse('{ a: 1!; foo; b: 2 }', {
                context: 'block',
                tolerant: true,
                onParseError: function(error) {
                    errors.push(error);
                }
            });

            assert.equal(ast.children.getSize(), 3);
            assert.equal(errors.length, 2);
            assert.equal(errors[0].message, 'Identifier is expected');
            assert.equal(errors[1].message, 'Colon is expected');
        });
    });

    describe('errors', function() {
        forEachParseTest(function(name, test) {
            createParseErrorTest(name, test, merge(test.options, {
                positions: false
            }));
            createParseErrorTest(name + ' (with positions)', test, merge(test.options, {
                positions: true
            }));
        }, true);

        it('formattedMessage', function() {
            try {
                parse('/**/\n.\nfoo');
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Identifier is expected\n' +
                    '    1 |/**/\n' +
                    '    2 |.\n' +
                    '--------^\n' +
                    '    3 |foo'
                );
                assert.equal(e.sourceFragment(),
                    '    2 |.\n' +
                    '--------^\n'
                );
                assert.equal(e.sourceFragment(3),
                    '    1 |/**/\n' +
                    '    2 |.\n' +
                    '--------^\n' +
                    '    3 |foo'
                );
            }
        });

        it('formattedMessage with tabs', function() {
            try {
                parse('a {\n\tb:\tc#\t\n}');
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Number or identifier is expected\n' +
                    '    1 |a {\n' +
                    '    2 |    b:    c#    \n' +
                    '-------------------^\n' +
                    '    3 |}'
                );
            }
        });

        it('formattedMessage for source with long lines', function() {
            try {
                parse(
                    '/*' + repeat('1234567890', 20) + '*/\n' +
                    repeat(' ', 117) + '.\n' +
                    'foo\n' +
                    repeat(' ', 120) + 'bar'
                );
            } catch (e) {
                assert.equal(e.formattedMessage,
                    'Parse error: Identifier is expected\n' +
                    '    1 |…12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678…\n' +
                    '    2 |…                                                       .\n' +
                    '----------------------------------------------------------------^\n' +
                    '    3 |\n' +
                    '    4 |…                                                          bar'
                );
            }
        });
    });

    describe('positions', function() {
        it('should start with line 1 column 1 by default', function() {
            var ast = parse('.foo.bar {\n  property: value 123 123.4 .123 123px 99% #fff url( a ) / var( --a ), "test" \'test\';\n}', {
                positions: true
            });
            var positions = [];

            walk(ast, function(node) {
                if (node.loc) {
                    positions.push([
                        node.loc.start.offset,
                        node.loc.start.line,
                        node.loc.start.column,
                        node.type
                    ]);
                }
            });

            assert.equal(lexer.checkStructure(ast), false);
            assert.deepEqual(positions, [
                [0, 1, 1, 'StyleSheet'],
                [0, 1, 1, 'Rule'],
                [0, 1, 1, 'SelectorList'],
                [0, 1, 1, 'Selector'],
                [0, 1, 1, 'ClassSelector'],
                [4, 1, 5, 'ClassSelector'],
                [9, 1, 10, 'Block'],
                [13, 2, 3, 'Declaration'],
                [22, 2, 12, 'Value'],
                [23, 2, 13, 'Identifier'],
                [29, 2, 19, 'Number'],
                [33, 2, 23, 'Number'],
                [39, 2, 29, 'Number'],
                [44, 2, 34, 'Dimension'],
                [50, 2, 40, 'Percentage'],
                [54, 2, 44, 'HexColor'],
                [59, 2, 49, 'Url'],
                [64, 2, 54, 'Raw'],
                [68, 2, 58, 'Operator'],
                [70, 2, 60, 'Function'],
                [75, 2, 65, 'Identifier'],
                [80, 2, 70, 'Operator'],
                [82, 2, 72, 'String'],
                [89, 2, 79, 'String']
            ]);
        });

        it('should start with specified offset, line and column', function() {
            var ast = parse('.foo.bar {\n  property: value 123 123.4 .123 123px 99% #fff url( a ) / var( --a ), "test" \'test\';\n}', {
                positions: true,
                offset: 100,
                line: 3,
                column: 5
            });
            var positions = [];

            walk(ast, function(node) {
                if (node.loc) {
                    positions.push([
                        node.loc.start.offset,
                        node.loc.start.line,
                        node.loc.start.column,
                        node.type
                    ]);
                }
            });

            assert.equal(lexer.checkStructure(ast), false);
            assert.deepEqual(positions, [
                [100, 3, 5, 'StyleSheet'],
                [100, 3, 5, 'Rule'],
                [100, 3, 5, 'SelectorList'],
                [100, 3, 5, 'Selector'],
                [100, 3, 5, 'ClassSelector'],
                [104, 3, 9, 'ClassSelector'],
                [109, 3, 14, 'Block'],
                [113, 4, 3, 'Declaration'],
                [122, 4, 12, 'Value'],
                [123, 4, 13, 'Identifier'],
                [129, 4, 19, 'Number'],
                [133, 4, 23, 'Number'],
                [139, 4, 29, 'Number'],
                [144, 4, 34, 'Dimension'],
                [150, 4, 40, 'Percentage'],
                [154, 4, 44, 'HexColor'],
                [159, 4, 49, 'Url'],
                [164, 4, 54, 'Raw'],
                [168, 4, 58, 'Operator'],
                [170, 4, 60, 'Function'],
                [175, 4, 65, 'Identifier'],
                [180, 4, 70, 'Operator'],
                [182, 4, 72, 'String'],
                [189, 4, 79, 'String']
            ]);
        });
    });

    describe('extension', function() {
        describe('value', function() {
            var extended = syntax.fork(function(syntaxConfig) {
                var defaultGetNode = syntaxConfig.scope.Value.getNode;

                syntaxConfig.scope.Value.getNode = function(context) {
                    if (this.scanner.tokenType === TYPE.DollarSign) {
                        var start = this.scanner.tokenStart;
                        this.scanner.next();

                        return {
                            type: 'Variable',
                            loc: this.getLocation(start, this.scanner.tokenEnd),
                            name: this.scanner.consume(TYPE.Identifier)
                        };
                    }

                    return defaultGetNode.call(this, context);
                };

                return syntaxConfig;
            });

            it('should not affect base syntax', function() {
                assert.throws(function() {
                    parse('$a', {
                        context: 'value'
                    });
                }, /Unexpected input/);
            });

            it('should parse according new rules', function() {
                var ast = extended.parse('$a', {
                    context: 'value'
                });

                assert.deepEqual(toPlainObject(ast), {
                    type: 'Value',
                    loc: null,
                    children: [
                        {
                            type: 'Variable',
                            loc: null,
                            name: 'a'
                        }
                    ]
                });
            });

            it('should fail on unknown', function() {
                assert.throws(function() {
                    extended.parse('@a', {
                        context: 'value'
                    });
                }, /Unexpected input/);
            });
        });

        describe('selector', function() {
            var extended = syntax.fork(function(syntaxConfig) {
                var defaultGetNode = syntaxConfig.scope.Selector.getNode;

                syntaxConfig.scope.Selector.getNode = function(context) {
                    if (this.scanner.tokenType === TYPE.Ampersand) {
                        var start = this.scanner.tokenStart;
                        this.scanner.next();

                        return {
                            type: 'Nested',
                            loc: this.getLocation(start, this.scanner.tokenEnd)
                        };
                    }

                    return defaultGetNode.call(this, context);
                };

                return syntaxConfig;
            });

            it('should not affect base syntax', function() {
                assert.throws(function() {
                    parse('a &', {
                        context: 'selector'
                    });
                }, /Unexpected input/);
            });

            it('should parse according new rules', function() {
                var ast = extended.parse('a &', {
                    context: 'selector'
                });

                assert.deepEqual(toPlainObject(ast), {
                    type: 'Selector',
                    loc: null,
                    children: [
                        {
                            type: 'TypeSelector',
                            loc: null,
                            name: 'a'
                        },
                        {
                            type: 'WhiteSpace',
                            loc: null,
                            value: ' '
                        },
                        {
                            type: 'Nested',
                            loc: null
                        }
                    ]
                });
            });

            it('should fail on unknown', function() {
                assert.throws(function() {
                    extended.parse('@a', {
                        context: 'selector'
                    });
                }, /Selector is expected/);
            });
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

require('should');

var CluestrClient = require('../lib/cluestr.js/index.js');

/**
 * Check environment is set up.
 */
before(function() {
  var keys = ['CLUESTR_ID', 'CLUESTR_SECRET', 'ACCESS_TOKEN'];
  keys.forEach(function(key) {
    if(!process.env[key]) {
      process.env[key] = 'fake';
      //throw new Error("To run this test suite, you need to specify environment variable " + key);
    }
  });
});

describe('getAccessToken()', function() {
  var cluestrClient = new CluestrClient(process.env.CLUESTR_ID, process.env.CLUESTR_SECRET);
  it('should crash on invalid values', function(done) {

    cluestrClient.getAccessToken("fake_code", "fake_uri",   function(err) {
      err.toString().should.include('401');
      err.toString().should.include('Client authentication failed');

      done();
    });
  });
});

describe('sendDocument()', function() {
  var cluestrClient = new CluestrClient(process.env.CLUESTR_ID, process.env.CLUESTR_SECRET);

  it('should require an accessToken', function(done) {
    cluestrClient.sendDocument({}, function(err) {
      err.toString().should.include('accessToken');
      done();
    });
  });

  it('should require an identifier', function(done) {
    cluestrClient.setAccessToken(process.env.ACCESS_TOKEN);
    cluestrClient.sendDocument({}, function(err) {
      err.toString().should.include('identifier');
      done();
    });
  });

  it('should allow for noHydrate parameter', function(done) {
    cluestrClient.setAccessToken(process.env.ACCESS_TOKEN);
    cluestrClient.sendDocument({}, false, function(err) {
      err.toString().should.include('identifier');
      done();
    });
  });

});
<commit_msg>Correct send<commit_after>'use strict';

require('should');

var CluestrClient = require('../lib/cluestr.js/index.js');

/**
 * Check environment is set up.
 */
before(function() {
  var keys = ['CLUESTR_ID', 'CLUESTR_SECRET', 'ACCESS_TOKEN'];
  keys.forEach(function(key) {
    if(!process.env[key]) {
      throw new Error("To run this test suite, you need to specify environment variable " + key);
    }
  });
});

describe('getAccessToken()', function() {
  var cluestrClient = new CluestrClient(process.env.CLUESTR_ID, process.env.CLUESTR_SECRET);
  it('should crash on invalid values', function(done) {

    cluestrClient.getAccessToken("fake_code", "fake_uri",   function(err) {
      err.toString().should.include('401');
      err.toString().should.include('The provided authorization grant is invalid');

      done();
    });
  });
});

describe('sendDocument()', function() {
  it('should require an accessToken', function(done) {
    var rawCluestrClient = new CluestrClient(process.env.CLUESTR_ID, process.env.CLUESTR_SECRET);
    rawCluestrClient.sendDocument({}, function(err) {
      err.toString().should.include('accessToken');
      done();
    });
  });

  var cluestrClient = new CluestrClient(process.env.CLUESTR_ID, process.env.CLUESTR_SECRET);
  cluestrClient.setAccessToken(process.env.ACCESS_TOKEN);

  it('should require an identifier', function(done) {
    cluestrClient.sendDocument({}, function(err) {
      err.toString().should.include('identifier');
      done();
    });
  });

  it('should allow for noHydrate parameter', function(done) {
    cluestrClient.setAccessToken(process.env.ACCESS_TOKEN);
    cluestrClient.sendDocument({}, false, function(err) {
      err.toString().should.include('identifier');
      done();
    });
  });

  it('should work as documented', function(done) {
    cluestrClient.setAccessToken(process.env.ACCESS_TOKEN);

    var datas = {
      identifier: 'test-identifier',
      binary_document_type: 'file',
      metadatas: {
        'foo': 'bar'
      },
    };

    cluestrClient.sendDocument(datas, function(err, document) {
      if(err) {
        throw err;
      }
      document.should.have.property('_type', 'Document');
      document.should.have.property('binary_document_type', '5252ce4ce4cfcd16f55cfa3b');
      document.should.have.property('metadatas');
      document.metadatas.should.eql(datas.metadatas);

      done();
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert');
var Response = require('../');

var res = new Response(
  200,
  {
    'Foo-Bar': 'baz-Bosh',
    'bar-foo': 'bish-Bosh',
  },
  'foo bar baz',
  'http://example.com'
);
assert((res.statusCode = 200));
assert(res.headers['foo-bar'] === 'baz-Bosh');
assert(res.headers['bar-foo'] === 'bish-Bosh');
assert(res.body === 'foo bar baz');
assert(res.url === 'http://example.com');
assert(res.getBody() === 'foo bar baz');

res = new Response(
  404,
  {
    'Foo-Bar': 'baz-Bosh',
  },
  'Could not find page',
  'http://example.com'
);
assert((res.statusCode = 404));
assert(res.headers['foo-bar'] === 'baz-Bosh');
assert(res.body === 'Could not find page');
assert(res.url === 'http://example.com');
var errored = false;
try {
  res.getBody();
} catch (ex) {
  assert(ex.statusCode === 404);
  assert(ex.headers['foo-bar'] === 'baz-Bosh');
  assert(ex.body === 'Could not find page');
  assert(ex.url === 'http://example.com');
  errored = true;
}
if (!errored) {
  throw new Error(
    'res.getBody() should throw an error when the status code is 404'
  );
}

res = new Response(0, {}, '', 'http://example.com');
assert((res.statusCode = 0));
assert(res.body === '');
assert(res.url === 'http://example.com');
var errored = false;
try {
  res.getBody();
} catch (ex) {
  assert(ex.statusCode === 0);
  assert(ex.body === '');
  assert(ex.url === 'http://example.com');
  errored = true;
}
if (!errored) {
  throw new Error(
    'res.getBody() should throw an error when the status code is 404'
  );
}
console.log('tests passed');
<commit_msg>Fix tests<commit_after>'use strict';

var assert = require('assert');
var Response = require('../');

var res = new Response(
  200,
  {
    'Foo-Bar': 'baz-Bosh',
    'bar-foo': 'bish-Bosh',
  },
  'foo bar baz',
  'http://example.com'
);
assert((res.statusCode = 200));
assert(res.headers['foo-bar'] === 'baz-Bosh');
assert(res.headers['bar-foo'] === 'bish-Bosh');
assert(res.body === 'foo bar baz');
assert(res.url === 'http://example.com');
assert(res.getBody() === 'foo bar baz');

res = new Response(
  404,
  {
    'Foo-Bar': 'baz-Bosh',
  },
  'Could not find page',
  'http://example.com'
);
assert((res.statusCode = 404));
assert(res.headers['foo-bar'] === 'baz-Bosh');
assert(res.body === 'Could not find page');
assert(res.url === 'http://example.com');
var errored = false;
try {
  res.getBody();
} catch (ex) {
  assert(ex.statusCode === 404);
  assert(ex.headers['foo-bar'] === 'baz-Bosh');
  assert(ex.body === 'Could not find page');
  assert(ex.url === 'http://example.com');
  errored = true;
}
if (!errored) {
  throw new Error(
    'res.getBody() should throw an error when the status code is 404'
  );
}

res = new Response(0, {}, '', 'http://example.com');
assert(res.statusCode === 0);
assert(res.body === '');
assert(res.url === 'http://example.com');
var errored = false;
try {
  res.getBody();
} catch (ex) {
  assert(ex.statusCode === 0);
  assert(ex.body === '');
  assert(ex.url === 'http://example.com');
  errored = true;
}
if (!errored) {
  throw new Error(
    'res.getBody() should throw an error when the status code is 404'
  );
}
console.log('tests passed');
<|endoftext|>


<commit_before>var should = require('chai').should();
var Point = require('../lib/point');
var BN = require('../lib/bn');

describe('Point', function() {

  it('should create a point', function() {
    var p = Point();
    should.exist(p);
    p = new Point();
    should.exist(p);
    (p instanceof Point).should.equal(true);
  });

  it('should have the standard properties for a point', function() {
    var p = Point();
    var props = ['curve', 'type', 'precomputed', 'x', 'y', 'inf'];
    var a = [];

    //all enumerable, own properties should be in prop
    for (var k in p) {
      if (p.hasOwnProperty(k)) {
        props.indexOf(k).should.not.equal(-1);
      }
    }

    //all props should be properties of a point
    props.forEach(function(k) {
      (typeof p[k] === 'undefined').should.equal(false);
    });
  });

  describe('#copy', function() {

    it('should copy G', function() {
      var point = Point.getG();
      var point2;
      (function() {
        point.copy(point2);
      }).should.throw(); //point2 is not a Point yet
      var point2 = Point();
      point.copy(point2);
      point2.toString().should.equal(point.toString());
    });

  });

  describe('#toJSON', function() {

    it('should print G to JSON', function() {
      var G = Point.getG();
      var json = G.toJSON();
      json.isOdd.should.equal(G.x.isOdd());
      json.x.should.equal(G.x.toString());
    });

  });

  describe('#fromJSON', function() {

    it('should recover G', function() {
      Point().fromJSON(Point.getG().toJSON()).eq(Point.getG()).should.equal(true);
    });

  });

  describe('#toString', function() {

    it('should convert G to a string', function() {
      var G = Point.getG();
      G.toString().should.equal(JSON.stringify(G.toJSON()));
    });

  });

  describe('#fromString', function() {

    it('should convert a json string to G', function() {
      var G = Point.getG();
      Point().fromString(G.toString()).eq(G).should.equal(true);
    });

  });

  describe('#getX', function() {

    it('should return 0', function() {
      var p = Point();
      p.getX().toString().should.equal('0');
    });

    it('should be convertable to a buffer', function() {
      var p = Point();
      p.getX().toBuffer({size: 32}).length.should.equal(32);
    });

  });

  describe('#getY', function() {

    it('should return 0', function() {
      var p = Point();
      p.getY().toString().should.equal('0');
    });

    it('should be convertable to a buffer', function() {
      var p = Point();
      p.getY().toBuffer({size: 32}).length.should.equal(32);
    });

  });

  describe('#add', function() {

    it('should accurately add g to itself', function() {
      var p1 = Point.getG();
      var p2 = Point.getG();
      var p3 = p1.add(p2);
      p3.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597');
      p3.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930');
    });

  });

  describe('#mul', function() {

    it('should accurately multiply g by 2', function() {
      var g = Point.getG();
      var b = g.mul(BN(2));
      b.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597');
      b.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930');
    });

    it('should accurately multiply g by n-1', function() {
      var g = Point.getG();
      var n = Point.getN();
      var b = g.mul(n.sub(1));
      b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240');
      b.getY().toString().should.equal('83121579216557378445487899878180864668798711284981320763518679672151497189239');
    });

    //not sure if this is technically accurate or not...
    //normally, you should always multiply g by something less than n
    //but it is the same result in OpenSSL
    it('should accurately multiply g by n+1', function() {
      var g = Point.getG();
      var n = Point.getN();
      var b = g.mul(n.add(1));
      b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240');
      b.getY().toString().should.equal('32670510020758816978083085130507043184471273380659243275938904335757337482424');
    });

    it('should accurate multiply this problematic value related to a bug in bn.js', function() {
      // see these discussions:
      // https://github.com/bitpay/bitcore/pull/894
      // https://github.com/indutny/elliptic/issues/17
      // https://github.com/indutny/elliptic/pull/18
      // https://github.com/indutny/elliptic/pull/19
      // https://github.com/indutny/bn.js/commit/3557d780b07ed0ed301e128f326f83c2226fb679
      var nhex = '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846';
      var n = BN(nhex, 16);
      var g1 = Point.getG(); // precomputed g
      var g2 = Point().fromX(false, BN('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16)); //non-precomputed g
      var p1 = g1.mul(n);
      var p2 = g2.mul(n);
      var pxhex = 'd6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01';
      var pyhex = 'e05fb262e64b108991a29979809fcef9d3e70cafceb3248c922c17d83d66bc9d';
      p1.getX().toBuffer().toString('hex').should.equal(pxhex);
      p1.getY().toBuffer().toString('hex').should.equal(pyhex);
      p2.getX().toBuffer().toString('hex').should.equal(pxhex);
      p2.getY().toBuffer().toString('hex').should.equal(pyhex);
    });

  });

  describe('@fromX', function() {

    it('should return g', function() {
      var g = Point.getG();
      var p = Point.fromX(false, g.getX());
      g.eq(p).should.equal(true);
    });

  });

  describe('#fromX', function() {

    it('should return g', function() {
      var g = Point.getG();
      var p = Point().fromX(false, g.getX());
      g.eq(p).should.equal(true);
    });

  });

  describe('#validate', function() {

    it('should validate this valid point', function() {
      var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
      var y = BN().fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex'));
      var p = Point(x, y);
      should.exist(p.validate());
    });

    it('should invalidate this invalid point', function() {
      var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
      var y = BN().fromBuffer(new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'));
      var p = Point(x, y);
      (function() {
        p.validate();
      }).should.throw('Invalid y value of public key');
    });

  });

});
<commit_msg>add one more test vector related to the bn.js bug<commit_after>var should = require('chai').should();
var Point = require('../lib/point');
var BN = require('../lib/bn');

describe('Point', function() {

  it('should create a point', function() {
    var p = Point();
    should.exist(p);
    p = new Point();
    should.exist(p);
    (p instanceof Point).should.equal(true);
  });

  it('should have the standard properties for a point', function() {
    var p = Point();
    var props = ['curve', 'type', 'precomputed', 'x', 'y', 'inf'];
    var a = [];

    //all enumerable, own properties should be in prop
    for (var k in p) {
      if (p.hasOwnProperty(k)) {
        props.indexOf(k).should.not.equal(-1);
      }
    }

    //all props should be properties of a point
    props.forEach(function(k) {
      (typeof p[k] === 'undefined').should.equal(false);
    });
  });

  describe('#copy', function() {

    it('should copy G', function() {
      var point = Point.getG();
      var point2;
      (function() {
        point.copy(point2);
      }).should.throw(); //point2 is not a Point yet
      var point2 = Point();
      point.copy(point2);
      point2.toString().should.equal(point.toString());
    });

  });

  describe('#toJSON', function() {

    it('should print G to JSON', function() {
      var G = Point.getG();
      var json = G.toJSON();
      json.isOdd.should.equal(G.x.isOdd());
      json.x.should.equal(G.x.toString());
    });

  });

  describe('#fromJSON', function() {

    it('should recover G', function() {
      Point().fromJSON(Point.getG().toJSON()).eq(Point.getG()).should.equal(true);
    });

  });

  describe('#toString', function() {

    it('should convert G to a string', function() {
      var G = Point.getG();
      G.toString().should.equal(JSON.stringify(G.toJSON()));
    });

  });

  describe('#fromString', function() {

    it('should convert a json string to G', function() {
      var G = Point.getG();
      Point().fromString(G.toString()).eq(G).should.equal(true);
    });

  });

  describe('#getX', function() {

    it('should return 0', function() {
      var p = Point();
      p.getX().toString().should.equal('0');
    });

    it('should be convertable to a buffer', function() {
      var p = Point();
      p.getX().toBuffer({size: 32}).length.should.equal(32);
    });

  });

  describe('#getY', function() {

    it('should return 0', function() {
      var p = Point();
      p.getY().toString().should.equal('0');
    });

    it('should be convertable to a buffer', function() {
      var p = Point();
      p.getY().toBuffer({size: 32}).length.should.equal(32);
    });

  });

  describe('#add', function() {

    it('should accurately add g to itself', function() {
      var p1 = Point.getG();
      var p2 = Point.getG();
      var p3 = p1.add(p2);
      p3.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597');
      p3.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930');
    });

  });

  describe('#mul', function() {

    it('should accurately multiply g by 2', function() {
      var g = Point.getG();
      var b = g.mul(BN(2));
      b.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597');
      b.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930');
    });

    it('should accurately multiply g by n-1', function() {
      var g = Point.getG();
      var n = Point.getN();
      var b = g.mul(n.sub(1));
      b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240');
      b.getY().toString().should.equal('83121579216557378445487899878180864668798711284981320763518679672151497189239');
    });

    //not sure if this is technically accurate or not...
    //normally, you should always multiply g by something less than n
    //but it is the same result in OpenSSL
    it('should accurately multiply g by n+1', function() {
      var g = Point.getG();
      var n = Point.getN();
      var b = g.mul(n.add(1));
      b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240');
      b.getY().toString().should.equal('32670510020758816978083085130507043184471273380659243275938904335757337482424');
    });

    it('should accurate multiply these problematic values related to a bug in bn.js', function() {
      // see these discussions:
      // https://github.com/bitpay/bitcore/pull/894
      // https://github.com/indutny/elliptic/issues/17
      // https://github.com/indutny/elliptic/pull/18
      // https://github.com/indutny/elliptic/pull/19
      // https://github.com/indutny/bn.js/commit/3557d780b07ed0ed301e128f326f83c2226fb679
      var nhex = '6d1229a6b24c2e775c062870ad26bc261051e0198c67203167273c7c62538846';
      var n = BN(nhex, 16);
      var g1 = Point.getG(); // precomputed g
      var g2 = Point().fromX(false, BN('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16)); //non-precomputed g
      var p1 = g1.mul(n);
      var p2 = g2.mul(n);
      var pxhex = 'd6106302d2698d6a41e9c9a114269e7be7c6a0081317de444bb2980bf9265a01';
      var pyhex = 'e05fb262e64b108991a29979809fcef9d3e70cafceb3248c922c17d83d66bc9d';
      p1.getX().toBuffer().toString('hex').should.equal(pxhex);
      p1.getY().toBuffer().toString('hex').should.equal(pyhex);
      p2.getX().toBuffer().toString('hex').should.equal(pxhex);
      p2.getY().toBuffer().toString('hex').should.equal(pyhex);

      var nhex = 'f2cc9d2b008927db94b89e04e2f6e70c180e547b3e5e564b06b8215d1c264b53';
      var n = BN(nhex, 16);
      var g1 = Point.getG(); // precomputed g
      var g2 = Point().fromX(false, BN('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16)); //non-precomputed g
      var p1 = g1.mul(n);
      var p2 = g2.mul(n);
      var pxhex = 'e275faa35bd1e88f5df6e8f9f6edb93bdf1d65f4915efc79fd7a726ec0c21700';
      var pyhex = '367216cb35b086e6686d69dddd822a8f4d52eb82ac5d9de18fdcd9bf44fa7df7';
      p1.getX().toBuffer().toString('hex').should.equal(pxhex);
      p1.getY().toBuffer().toString('hex').should.equal(pyhex);
      p2.getX().toBuffer().toString('hex').should.equal(pxhex);
      p2.getY().toBuffer().toString('hex').should.equal(pyhex);
    });

  });

  describe('@fromX', function() {

    it('should return g', function() {
      var g = Point.getG();
      var p = Point.fromX(false, g.getX());
      g.eq(p).should.equal(true);
    });

  });

  describe('#fromX', function() {

    it('should return g', function() {
      var g = Point.getG();
      var p = Point().fromX(false, g.getX());
      g.eq(p).should.equal(true);
    });

  });

  describe('#validate', function() {

    it('should validate this valid point', function() {
      var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
      var y = BN().fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex'));
      var p = Point(x, y);
      should.exist(p.validate());
    });

    it('should invalidate this invalid point', function() {
      var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex'));
      var y = BN().fromBuffer(new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'));
      var p = Point(x, y);
      (function() {
        p.validate();
      }).should.throw('Invalid y value of public key');
    });

  });

});
<|endoftext|>


<commit_before>/* global suite: false, test: false */
var assert = require('assert');
var request = require('supertest');

var app = require('../');
var appConfig = app.get('config');

suite('OPTIONS /', function () {
  test('return CORS headers', function (done) {
    request(app)
      .options('/')
      .expect('Access-Control-Allow-Origin', '*')
      .expect('Access-Control-Allow-Headers', 'X-Requested-With')
      .expect('Access-Control-Allow-Methods', 'GET')
      .expect('Access-Control-Max-Age', '86400')
      .expect(200, done);
  });
});

suite('GET /shorten', function () {
  test('checks for valid URL format', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2F')
      .expect(400, done);
  });

  test('checks for valid protocol', function (done) {
    request(app)
      .get('/shorten/ftp%3A%2F%2Fwww.test.de%2Ffoo%2Fbar%2Fbaz')
      .expect(403, done);
  });

  test('refuses to shorten too short URLs', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Ffoo.bar')
      .expect(403, done);
  });

  test('refuses request hashes when forbidden', function (done) {
    var requestHash = 'test';
    appConfig.hash.allowRequest = false;
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(403)
      .end(function (err, res) {
        appConfig.hash.allowRequest = true;
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses bad request hashes', function (done) {
    var requestHash = 'this%20is%20a%20malformed%20hash';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses forbidden request hashes', function (done) {
    var requestHash = 'shorten';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses URL with hostname on blacklist', function (done) {
    appConfig.urlLimit.hostnameBlacklist = ['a-bad-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fa-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameBlacklist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses URL with hostname not on whitelist', function (done) {
    appConfig.urlLimit.hostnameWhitelist = ['a-known-good-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fanother-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameWhitelist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('performs shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert(appConfig.hash._regex.test(res.body.hash));
          assert.strictEqual(res.body.longUrl,
            'http://a-very-long-domain.name/with/an/even/longer/path');
          assert.strictEqual(res.body.url, appConfig.hash.urlPrefix +
            res.body.hash);
          return done();
        }
      });
  });

  test('performs normalization during shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var hashCanonicalUrl = res.body.hash;
          request(app)
            .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%3A80' +
                '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%23')
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function (err, res) {
              if (err) {
                return done(err);
              } else {
                assert.strictEqual(hashCanonicalUrl, res.body.hash);
                request(app)
                  .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .end(function (err, res) {
                    if (err) {
                      return done(err);
                    } else {
                      assert.strictEqual(hashCanonicalUrl, res.body.hash);
                      return done();
                    }
                  });
              }
            });
        }
      });
  });

  test('accepts request hashes when allowed', function (done) {
    var requestHash = 'test';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert.strictEqual(requestHash, res.body.hash);
          return done();
        }
      });
  });

  test('returns text/plain (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(new RegExp('^' + appConfig.hash.urlPrefix))
      .expect(200, done);
  });

  test('returns qrcode (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=qrcode')
      .expect('Content-Type', /image\/png/)
      .expect('Content-Length', /[0-9]{3,4}/)
      .expect(200, done);
  });
});

suite('GET|HEAD /[hash]', function () {
  var hash;

  test('GET returns 404 for unknown hash', function (done) {
    request(app)
      .get('/unkno')
      .expect(404, done);
  });

  test('GET returns permanent redirect for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/' + hash)
            .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
                '/longer/path')
            .expect(301, done);
        }
      });
  });

  test('HEAD returns 404 for unknown hash', function (done) {
    request(app)
      .head('/unkno')
      .expect(404, done);
  });

  test('HEAD returns permanent redirect for known hash', function (done) {
    request(app)
      .head('/' + hash)
      .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
          '/longer/path')
      .expect(301, done);
  });
});

suite('GET /stats', function () {
  var hash;

  test('returns 404 for unknown hash', function (done) {
    request(app)
      .get('/stats/unkno')
      .expect(404, done);
  });

  test('returns stats for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/stats/' + hash)
            .expect('Content-Type', /json/)
            .expect(200, done);
        }
      });
  });

  test('returns clicks in text/plain (on demand)', function (done) {
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(/\d+/)
      .expect(200, done);
  });

  test('returns actually incremented clicks', function (done) {
    this.slow(4075);
    this.timeout(5000);
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(200)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var clicks = parseInt(res.text, 10);
          setTimeout(function () {
            request(app)
              .get('/' + hash)
              .expect(301)
              .end(function (err, res) {
                request(app)
                  .get('/stats/' + hash + '?format=txt')
                  .expect(200)
                  .expect('' + (clicks + 1), done);
              });
          }, 4000);
        }
      });
  });
});
<commit_msg>Fix line length<commit_after>/* global suite: false, test: false */
var assert = require('assert');
var request = require('supertest');

var app = require('../');
var appConfig = app.get('config');

suite('OPTIONS /', function () {
  test('return CORS headers', function (done) {
    request(app)
      .options('/')
      .expect('Access-Control-Allow-Origin', '*')
      .expect('Access-Control-Allow-Headers', 'X-Requested-With')
      .expect('Access-Control-Allow-Methods', 'GET')
      .expect('Access-Control-Max-Age', '86400')
      .expect(200, done);
  });
});

suite('GET /shorten', function () {
  test('checks for valid URL format', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2F')
      .expect(400, done);
  });

  test('checks for valid protocol', function (done) {
    request(app)
      .get('/shorten/ftp%3A%2F%2Fwww.test.de%2Ffoo%2Fbar%2Fbaz')
      .expect(403, done);
  });

  test('refuses to shorten too short URLs', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Ffoo.bar')
      .expect(403, done);
  });

  test('refuses request hashes when forbidden', function (done) {
    var requestHash = 'test';
    appConfig.hash.allowRequest = false;
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(403)
      .end(function (err, res) {
        appConfig.hash.allowRequest = true;
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses bad request hashes', function (done) {
    var requestHash = 'this%20is%20a%20malformed%20hash';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses forbidden request hashes', function (done) {
    var requestHash = 'shorten';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses URL with hostname on blacklist', function (done) {
    appConfig.urlLimit.hostnameBlacklist = ['a-bad-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fa-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameBlacklist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses URL with hostname not on whitelist', function (done) {
    appConfig.urlLimit.hostnameWhitelist = ['a-known-good-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fanother-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameWhitelist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('performs shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert(appConfig.hash._regex.test(res.body.hash));
          assert.strictEqual(res.body.longUrl,
            'http://a-very-long-domain.name/with/an/even/longer/path');
          assert.strictEqual(res.body.url, appConfig.hash.urlPrefix +
            res.body.hash);
          return done();
        }
      });
  });

  test('performs normalization during shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var hashCanonicalUrl = res.body.hash;
          request(app)
            .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%3A80' +
                '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%23')
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function (err, res) {
              if (err) {
                return done(err);
              } else {
                assert.strictEqual(hashCanonicalUrl, res.body.hash);
                request(app)
                  .get('/shorten/http%3A%2F%2Fa-very-long-domain.name' +
                      '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%3F')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .end(function (err, res) {
                    if (err) {
                      return done(err);
                    } else {
                      assert.strictEqual(hashCanonicalUrl, res.body.hash);
                      return done();
                    }
                  });
              }
            });
        }
      });
  });

  test('accepts request hashes when allowed', function (done) {
    var requestHash = 'test';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert.strictEqual(requestHash, res.body.hash);
          return done();
        }
      });
  });

  test('returns text/plain (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(new RegExp('^' + appConfig.hash.urlPrefix))
      .expect(200, done);
  });

  test('returns qrcode (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=qrcode')
      .expect('Content-Type', /image\/png/)
      .expect('Content-Length', /[0-9]{3,4}/)
      .expect(200, done);
  });
});

suite('GET|HEAD /[hash]', function () {
  var hash;

  test('GET returns 404 for unknown hash', function (done) {
    request(app)
      .get('/unkno')
      .expect(404, done);
  });

  test('GET returns permanent redirect for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/' + hash)
            .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
                '/longer/path')
            .expect(301, done);
        }
      });
  });

  test('HEAD returns 404 for unknown hash', function (done) {
    request(app)
      .head('/unkno')
      .expect(404, done);
  });

  test('HEAD returns permanent redirect for known hash', function (done) {
    request(app)
      .head('/' + hash)
      .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
          '/longer/path')
      .expect(301, done);
  });
});

suite('GET /stats', function () {
  var hash;

  test('returns 404 for unknown hash', function (done) {
    request(app)
      .get('/stats/unkno')
      .expect(404, done);
  });

  test('returns stats for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/stats/' + hash)
            .expect('Content-Type', /json/)
            .expect(200, done);
        }
      });
  });

  test('returns clicks in text/plain (on demand)', function (done) {
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(/\d+/)
      .expect(200, done);
  });

  test('returns actually incremented clicks', function (done) {
    this.slow(4075);
    this.timeout(5000);
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(200)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var clicks = parseInt(res.text, 10);
          setTimeout(function () {
            request(app)
              .get('/' + hash)
              .expect(301)
              .end(function (err, res) {
                request(app)
                  .get('/stats/' + hash + '?format=txt')
                  .expect(200)
                  .expect('' + (clicks + 1), done);
              });
          }, 4000);
        }
      });
  });
});
<|endoftext|>


<commit_before>/*global describe, it*/
var expect = require('./unexpected-with-plugins'),
    query = require('../lib').query;

describe('query', function () {
    it('it should throw on error conditions', function (done) {
        expect(function andUndefined() { query.and(); }, 'to throw');
        expect(function andSingle() { query.and({}); }, 'to throw');

        expect(function orUndefined() { query.or(); }, 'to throw');
        expect(function orSingle() { query.or({}); }, 'to throw');

        expect(function notDouble() { query.not({}, {}); }, 'to throw');

        done();
    });

    it('it should implement boolean AND correctly', function (done) {
        var andQuery = query.and({
                type: 'Html'
            },
            {
                isInline: false
            });

        expect(andQuery, 'to be a function');

        expect([
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html',
                isInline: false,
                foo: 'bar'
            },
            {
                type: 'Html',
                isInline: false,
                inline: function () { return 'foo'; }
            },
            {
                type: 'Html',
                isInline: false,
                matcher: /^http:/
            },
            {
                type: 'Html',
                isInline: false,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(andQuery(item), 'to be true');
        });

        expect([
            {
                type: 'JavaScript',
                isInline: false
            },
            {
                type: 'Css',
                isInline: false,
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                isInline: false,
                inline: function () { return 'foo'; }
            },
            {
                type: 'Html',
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(andQuery(item), 'to be false');
        });

        done();
    });

    it('it should implement boolean OR correctly', function (done) {
        var orQuery = query.or({
                type: 'Html'
            },
            {
                isInline: false
            });

        expect(orQuery, 'to be a function');

        expect([
            {
                type: 'Html',
                isInline: true
            },
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html'
            },
            {
                isInline: false
            },
            {
                type: 'Html',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(orQuery(item), 'to be true');
        });

        expect([
            {},
            {
                type: 'JavaScript',
                isInline: true
            },
            {
                type: 'Css',
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                inline: function () { return 'foo'; }
            },
            {
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(orQuery(item), 'to be false');
        });

        done();
    });

    it('it should implement boolean NOT correctly', function (done) {
        var notQuery = query.not({
                type: 'Html'
            });

        expect(notQuery, 'to be a function');

        expect([
            {},
            {
                type: 'JavaScript',
                isInline: true
            },
            {
                type: 'Css',
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                inline: function () { return 'foo'; }
            },
            {
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(notQuery(item), 'to be true');
        });

        expect([
            {
                type: 'Html',
                isInline: true
            },
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html'
            },
            {
                type: 'Html',
                isRepetitive: true
            },
            {
                type: 'Html',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(notQuery(item), 'to be false');
        });

        done();
    });
});
<commit_msg>Add tests for query prefixMatchers<commit_after>/*global describe, it*/
var expect = require('./unexpected-with-plugins'),
    query = require('../lib').query;

describe('query', function () {
    it('should throw on error conditions', function (done) {
        expect(function andUndefined() { query.and(); }, 'to throw');
        expect(function andSingle() { query.and({}); }, 'to throw');

        expect(function orUndefined() { query.or(); }, 'to throw');
        expect(function orSingle() { query.or({}); }, 'to throw');

        expect(function notDouble() { query.not({}, {}); }, 'to throw');

        done();
    });

    it('should implement boolean AND correctly', function (done) {
        var andQuery = query.and({
                type: 'Html'
            },
            {
                isInline: false
            });

        expect(andQuery, 'to be a function');

        expect([
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html',
                isInline: false,
                foo: 'bar'
            },
            {
                type: 'Html',
                isInline: false,
                inline: function () { return 'foo'; }
            },
            {
                type: 'Html',
                isInline: false,
                matcher: /^http:/
            },
            {
                type: 'Html',
                isInline: false,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(andQuery(item), 'to be true');
        });

        expect([
            {
                type: 'JavaScript',
                isInline: false
            },
            {
                type: 'Css',
                isInline: false,
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                isInline: false,
                inline: function () { return 'foo'; }
            },
            {
                type: 'Html',
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(andQuery(item), 'to be false');
        });

        done();
    });

    it('should implement boolean OR correctly', function (done) {
        var orQuery = query.or({
                type: 'Html'
            },
            {
                isInline: false
            });

        expect(orQuery, 'to be a function');

        expect([
            {
                type: 'Html',
                isInline: true
            },
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html'
            },
            {
                isInline: false
            },
            {
                type: 'Html',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(orQuery(item), 'to be true');
        });

        expect([
            {},
            {
                type: 'JavaScript',
                isInline: true
            },
            {
                type: 'Css',
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                inline: function () { return 'foo'; }
            },
            {
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(orQuery(item), 'to be false');
        });

        done();
    });

    it('should implement boolean NOT correctly', function (done) {
        var notQuery = query.not({
                type: 'Html'
            });

        expect(notQuery, 'to be a function');

        expect([
            {},
            {
                type: 'JavaScript',
                isInline: true
            },
            {
                type: 'Css',
                foo: 'bar'
            },
            {
                type: 'HtmlTemplate',
                inline: function () { return 'foo'; }
            },
            {
                isInline: true,
                matcher: /^http:/
            },
            {
                type: 'Xml',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(notQuery(item), 'to be true');
        });

        expect([
            {
                type: 'Html',
                isInline: true
            },
            {
                type: 'Html',
                isInline: false
            },
            {
                type: 'Html'
            },
            {
                type: 'Html',
                isRepetitive: true
            },
            {
                type: 'Html',
                isInline: true,
                amount: 10
            }
        ], 'to be an array whose items satisfy', function (item) {
            expect(notQuery(item), 'to be false');
        });

        done();
    });

    it('should implement string prefix matching', function (done) {
        var prefixMatcher = query.createPrefixMatcher('http');

        expect(prefixMatcher, 'to be a function');

        expect([
            'http://fisk.dk',
            'http://cnn.com',
            'http://asetgraph.org',
            'https://github.com',
            'https://twitter.com'
        ], 'to be an array whose items satisfy', function (item) {
            expect(prefixMatcher(item), 'to be true');
        });

        expect([
            ' http://fisk.dk',
            'htp://cnn.com',
            'ftp+http://asetgraph.org',
            'ftp://github.com',
            'gopher://twitter.com'
        ], 'to be an array whose items satisfy', function (item) {
            expect(prefixMatcher(item), 'to be false');
        });

        done();
    });
});
<|endoftext|>


<commit_before>const test = require('tape')
const qup = require('../')

test('runs, with N concurrent', (t) => {
  t.plan(12)

  let accum = 0

  function add (x, callback) {
    accum += x
    setTimeout(callback)
  }

  const su = qup(add, 2)

  su.push(2)
  t.equal(accum, 2) // 2 was added
  t.equal(su.running, 1) // add is now waiting on setTimeout
  t.equal(su.q.length, 0) // nothing is left in the queue

  su.push(3)
  t.equal(accum, 5) // 3 was added
  t.equal(su.running, 2) // two add's are now waiting on setTimeout
  t.equal(su.q.length, 0) // still, nothing is left in the queue

  su.push(60, () => {
    t.equal(accum, 65) // 60 was added
    t.equal(su.running, 0) // nothing is running during a callback
    t.equal(su.q.length, 0) // nothing is left in the queue
  })

  t.equal(accum, 5) // nothing was added
  t.equal(su.running, 2) // two add's are still waiting on setTimeout
  t.equal(su.q.length, 1) // 60 is now in the queue
})

test('README example as expected', (t) => {
  t.plan(8)

  const expected = [1, 2, 3, 4, 5, 6, 7, 8]
  const q = qup((x, callback) => {
    t.same(x, expected[0])
    expected.shift()

    // => in order, 1, 2, 3, 4, 5, 6, 7, then 8
    setTimeout(callback)
  }, 3)

  q.push(1)
  q.push(2)
  q.push(3)
  q.push(4)
  q.push(5)
  q.push(6)
  q.push(7)
  q.push(8)
})

test('push, with return value expected (non-batch only)', (t) => {
  const a = 9
  const su = qup((x, callback) => {
    callback(null, a + x)
  })

  t.plan(2)
  su.push(6, (err, y) => {
    t.ifErr(err)
    t.equal(y, 15)
  })
})

test('doesn\'t blow the stack', (t) => {
  const q = qup((x, callback) => {
    if (x === 0) return setTimeout(callback)
    if (x === 1e5 - 1) t.end()

    callback()
  }, 1)

  q.push(0)
  for (let i = 1; i < 1e5; ++i) q.push(i)
})

test('clear, depletes the queue', (t) => {
  t.plan(6)
  const expected = [1, 4, 5]

  const q = qup((x, callback) => {
    t.equal(x, expected[0])
    expected.shift()

    setTimeout(callback)
  }, 1)

  q.push(1)
  q.push(2)
  q.push(3)

  t.equal(q.q.length, 2)
  q.clear()
  t.equal(q.q.length, 0)

  q.push(4)
  q.push(5)
  t.equal(q.q.length, 2)
})

test('kill, depletes the queue and ignores running', (t) => {
  t.plan(5)

  let i = null
  const q = qup((x, callback) => {
    i = x
    setTimeout(callback)
  }, 1)

  q.push(1, () => {
    t.equal(i, 1)

    // delay, 2 will start, but never callback
    setTimeout(() => {
      q.kill()
      t.equal(q.q.length, 0)
    })
  })

  // NOTE: these will never happend
  q.push(2, () => t.fail()) // will set i = 2, but not fail
  q.push(3, () => t.fail())
  q.push(4, () => t.fail())
  t.equal(q.q.length, 3)

  setTimeout(() => {
    t.equal(i, 2)
    t.equal(q.q.length, 0)
  }, 100)
})
<commit_msg>test: s/deplete/empty, deplete implies usage<commit_after>const test = require('tape')
const qup = require('../')

test('runs, with N concurrent', (t) => {
  t.plan(12)

  let accum = 0

  function add (x, callback) {
    accum += x
    setTimeout(callback)
  }

  const su = qup(add, 2)

  su.push(2)
  t.equal(accum, 2) // 2 was added
  t.equal(su.running, 1) // add is now waiting on setTimeout
  t.equal(su.q.length, 0) // nothing is left in the queue

  su.push(3)
  t.equal(accum, 5) // 3 was added
  t.equal(su.running, 2) // two add's are now waiting on setTimeout
  t.equal(su.q.length, 0) // still, nothing is left in the queue

  su.push(60, () => {
    t.equal(accum, 65) // 60 was added
    t.equal(su.running, 0) // nothing is running during a callback
    t.equal(su.q.length, 0) // nothing is left in the queue
  })

  t.equal(accum, 5) // nothing was added
  t.equal(su.running, 2) // two add's are still waiting on setTimeout
  t.equal(su.q.length, 1) // 60 is now in the queue
})

test('README example as expected', (t) => {
  t.plan(8)

  const expected = [1, 2, 3, 4, 5, 6, 7, 8]
  const q = qup((x, callback) => {
    t.same(x, expected[0])
    expected.shift()

    // => in order, 1, 2, 3, 4, 5, 6, 7, then 8
    setTimeout(callback)
  }, 3)

  q.push(1)
  q.push(2)
  q.push(3)
  q.push(4)
  q.push(5)
  q.push(6)
  q.push(7)
  q.push(8)
})

test('push, with return value expected (non-batch only)', (t) => {
  const a = 9
  const su = qup((x, callback) => {
    callback(null, a + x)
  })

  t.plan(2)
  su.push(6, (err, y) => {
    t.ifErr(err)
    t.equal(y, 15)
  })
})

test('doesn\'t blow the stack', (t) => {
  const q = qup((x, callback) => {
    if (x === 0) return setTimeout(callback)
    if (x === 1e5 - 1) t.end()

    callback()
  }, 1)

  q.push(0)
  for (let i = 1; i < 1e5; ++i) q.push(i)
})

test('clear, empties the queue', (t) => {
  t.plan(6)
  const expected = [1, 4, 5]

  const q = qup((x, callback) => {
    t.equal(x, expected[0])
    expected.shift()

    setTimeout(callback)
  }, 1)

  q.push(1)
  q.push(2)
  q.push(3)

  t.equal(q.q.length, 2)
  q.clear()
  t.equal(q.q.length, 0)

  q.push(4)
  q.push(5)
  t.equal(q.q.length, 2)
})

test('kill, empties the queue and ignores running', (t) => {
  t.plan(5)

  let i = null
  const q = qup((x, callback) => {
    i = x
    setTimeout(callback)
  }, 1)

  q.push(1, () => {
    t.equal(i, 1)

    // delay, 2 will start, but never callback
    setTimeout(() => {
      q.kill()
      t.equal(q.q.length, 0)
    })
  })

  // NOTE: these will never happend
  q.push(2, () => t.fail()) // will set i = 2, but not fail
  q.push(3, () => t.fail())
  q.push(4, () => t.fail())
  t.equal(q.q.length, 3)

  setTimeout(() => {
    t.equal(i, 2)
    t.equal(q.q.length, 0)
  }, 100)
})
<|endoftext|>


<commit_before>var assert = require('assert');
var env = require('../index');

describe('validate()', function() {
    var basicSpec = { REQD: { required: true },
                      PARSED: { parse: function(x) { return x + 'foo'; } },
                      CHOICEVAR: { choices: ['one', 'two', 'three'] },
                      REGEXVAR: { regex: /number\d/ },
                      MYBOOL: { parse: env.toBoolean },
                      MYNUM: { parse: env.toNumber }
                    };
    it('throws an error if a required field is not present', function() {
        assert.throws(
            function() { env.validate({}, basicSpec); }, env.EnvError);
    });

    it('validates from a set of choices if given', function() {
        assert.throws(
            function() { env.validate({ REQD: 'asdf', CHOICEVAR: 'asdf'}, basicSpec); }, env.EnvError);

        var myEnv = env.validate({ REQD: 'asdf', CHOICEVAR: 'two'}, basicSpec);
        assert.strictEqual(myEnv.CHOICEVAR, 'two');
        assert.strictEqual(env.get('CHOICEVAR'), 'two');
    });

    it('validates against a regex if one is provided', function() {
        assert.throws(
            function() { env.validate({ REQD: 'asdf', REGEXVAR: 'fail'}, basicSpec); }, env.EnvError);

        var myEnv = env.validate({ REQD: 'asdf', REGEXVAR: 'number4'}, basicSpec);
        assert.strictEqual(myEnv.REGEXVAR, 'number4');
        assert.strictEqual(env.get('REGEXVAR'), 'number4');
    });

    it('works with a custom parse function', function() {
        var myEnv = env.validate({ REQD: 'asdf', PARSED: 'bar'}, basicSpec);
        assert.strictEqual(myEnv.PARSED, 'barfoo');
    });

    it('works with the env.toNumber() parser', function() {
        var myEnv = env.validate({ REQD: 'asdf', MYNUM: '123'}, basicSpec);
        assert.strictEqual(myEnv.MYNUM, 123);

        // If a non-number was entered, toNumber should throw:
        assert.throws(
            function() { env.validate({ REQD: 'asdf', MYNUM: 'asdf12'}, basicSpec); }, env.EnvError);
    });

    it('works with the env.toBoolean() parser', function() {
        var myEnv = env.validate({ REQD: 'asdf', MYBOOL: 'true'}, basicSpec);
        assert.strictEqual(myEnv.MYBOOL, true);
    });
});

describe('get()', function() {
    var basicSpec = { MYVAR: { required: true } };
    var randomKey = 'RANDOMKEY123456';
    process.env[randomKey] = 'HELLO MOCHA';

    it('does not work before validation has happened', function() {
        assert.strictEqual(env.get(randomKey), undefined);

        // Accepts a default argument that will still work for unvalidated vars:
        assert.strictEqual(env.get(randomKey, 'defaultStr'), 'defaultStr');
    });

    it('works after validation has occurred', function() {
        env.validate({ MYVAR: 'ASDF' }, basicSpec);
        assert.strictEqual(env.get('MYVAR'), 'ASDF');

        // We can still not access env vars that are not in the validation spec:
        assert.strictEqual(env.get(randomKey), undefined);
        assert.strictEqual(env.get(randomKey, 'defaultStr'), 'defaultStr');
    });
});

describe('set()', function() {
    var basicSpec = { SETVAR2: { required: true, parse: env.toNumber } };

    it('sets env vars that do not have validation set up', function() {
        assert.strictEqual(env.get('SET_TEST_VAR'), undefined);
        assert.strictEqual(process.env.SET_TEST_VAR, undefined);

        env.set('SET_TEST_VAR', 'asdf');
        assert.strictEqual(env.get('SET_TEST_VAR'), 'asdf');
        assert.strictEqual(process.env.SET_TEST_VAR, 'asdf');
    });

    it('ensures that variables are validated when passed in', function() {
        process.env.SETVAR2 = '23';
        env.validate(process.env, basicSpec);
        assert.strictEqual(env.get('SETVAR2'), 23);

        env.set('SETVAR2', '43');
        assert.strictEqual(env.get('SETVAR2'), 43);
        assert.strictEqual(process.env.SETVAR2, '43');  // process.env always converts to strings
    });
});

describe('NODE_ENV helpers', function() {
    it('work for "production"', function() {
        process.env.NODE_ENV = 'production';
        assert.strictEqual(env.isProduction, true);
        assert.strictEqual(env.isTesting, false);
        assert.strictEqual(env.isDev, false);
    });

    it('work for "test"', function() {
        process.env.NODE_ENV = 'test';
        assert.strictEqual(env.isProduction, false);
        assert.strictEqual(env.isTesting, true);
        assert.strictEqual(env.isDev, false);
    });

    it('work for "development"', function() {
        process.env.NODE_ENV = 'development';
        assert.strictEqual(env.isProduction, false);
        assert.strictEqual(env.isTesting, false);
        assert.strictEqual(env.isDev, true);
    });
});
<commit_msg>Add a test case for using JSON.parse as a parse function.<commit_after>var assert = require('assert');
var env = require('../index');

describe('validate()', function() {
    var basicSpec = { REQD: { required: true },
                      PARSED: { parse: function(x) { return x + 'foo'; } },
                      CHOICEVAR: { choices: ['one', 'two', 'three'] },
                      REGEXVAR: { regex: /number\d/ },
                      JSONVAR: { parse: JSON.parse },
                      MYBOOL: { parse: env.toBoolean },
                      MYNUM: { parse: env.toNumber }
                    };
    it('throws an error if a required field is not present', function() {
        assert.throws(
            function() { env.validate({}, basicSpec); }, env.EnvError);
    });

    it('validates from a set of choices if given', function() {
        assert.throws(
            function() { env.validate({ REQD: 'asdf', CHOICEVAR: 'asdf'}, basicSpec); }, env.EnvError);

        var myEnv = env.validate({ REQD: 'asdf', CHOICEVAR: 'two'}, basicSpec);
        assert.strictEqual(myEnv.CHOICEVAR, 'two');
        assert.strictEqual(env.get('CHOICEVAR'), 'two');
    });

    it('validates against a regex if one is provided', function() {
        assert.throws(
            function() { env.validate({ REQD: 'asdf', REGEXVAR: 'fail'}, basicSpec); }, env.EnvError);

        var myEnv = env.validate({ REQD: 'asdf', REGEXVAR: 'number4'}, basicSpec);
        assert.strictEqual(myEnv.REGEXVAR, 'number4');
        assert.strictEqual(env.get('REGEXVAR'), 'number4');
    });

    it('works with a custom parse function', function() {
        var myEnv = env.validate({ REQD: 'asdf', PARSED: 'bar'}, basicSpec);
        assert.strictEqual(myEnv.PARSED, 'barfoo');
    });

    it('works with JSON.parse', function() {
        var myEnv = env.validate({ REQD: 'asdf', JSONVAR: '{"foo": 123, "bar": "baz"}'}, basicSpec);
        assert.strictEqual(myEnv.JSONVAR.foo, 123);
        assert.strictEqual(myEnv.JSONVAR.bar, 'baz');
    });

    it('works with the env.toNumber() parser', function() {
        var myEnv = env.validate({ REQD: 'asdf', MYNUM: '123'}, basicSpec);
        assert.strictEqual(myEnv.MYNUM, 123);

        // If a non-number was entered, toNumber should throw:
        assert.throws(
            function() { env.validate({ REQD: 'asdf', MYNUM: 'asdf12'}, basicSpec); }, env.EnvError);
    });

    it('works with the env.toBoolean() parser', function() {
        var myEnv = env.validate({ REQD: 'asdf', MYBOOL: 'true'}, basicSpec);
        assert.strictEqual(myEnv.MYBOOL, true);
    });
});

describe('get()', function() {
    var basicSpec = { MYVAR: { required: true } };
    var randomKey = 'RANDOMKEY123456';
    process.env[randomKey] = 'HELLO MOCHA';

    it('does not work before validation has happened', function() {
        assert.strictEqual(env.get(randomKey), undefined);

        // Accepts a default argument that will still work for unvalidated vars:
        assert.strictEqual(env.get(randomKey, 'defaultStr'), 'defaultStr');
    });

    it('works after validation has occurred', function() {
        env.validate({ MYVAR: 'ASDF' }, basicSpec);
        assert.strictEqual(env.get('MYVAR'), 'ASDF');

        // We can still not access env vars that are not in the validation spec:
        assert.strictEqual(env.get(randomKey), undefined);
        assert.strictEqual(env.get(randomKey, 'defaultStr'), 'defaultStr');
    });
});

describe('set()', function() {
    var basicSpec = { SETVAR2: { required: true, parse: env.toNumber } };

    it('sets env vars that do not have validation set up', function() {
        assert.strictEqual(env.get('SET_TEST_VAR'), undefined);
        assert.strictEqual(process.env.SET_TEST_VAR, undefined);

        env.set('SET_TEST_VAR', 'asdf');
        assert.strictEqual(env.get('SET_TEST_VAR'), 'asdf');
        assert.strictEqual(process.env.SET_TEST_VAR, 'asdf');
    });

    it('ensures that variables are validated when passed in', function() {
        process.env.SETVAR2 = '23';
        env.validate(process.env, basicSpec);
        assert.strictEqual(env.get('SETVAR2'), 23);

        env.set('SETVAR2', '43');
        assert.strictEqual(env.get('SETVAR2'), 43);
        assert.strictEqual(process.env.SETVAR2, '43');  // process.env always converts to strings
    });
});

describe('NODE_ENV helpers', function() {
    it('work for "production"', function() {
        process.env.NODE_ENV = 'production';
        assert.strictEqual(env.isProduction, true);
        assert.strictEqual(env.isTesting, false);
        assert.strictEqual(env.isDev, false);
    });

    it('work for "test"', function() {
        process.env.NODE_ENV = 'test';
        assert.strictEqual(env.isProduction, false);
        assert.strictEqual(env.isTesting, true);
        assert.strictEqual(env.isDev, false);
    });

    it('work for "development"', function() {
        process.env.NODE_ENV = 'development';
        assert.strictEqual(env.isProduction, false);
        assert.strictEqual(env.isTesting, false);
        assert.strictEqual(env.isDev, true);
    });
});
<|endoftext|>