Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

unexpected

Package Overview
Dependencies
Maintainers
1
Versions
330
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unexpected - npm Package Compare versions

Comparing version 1.0.1 to 1.0.2

254

lib/unexpected.js

@@ -56,22 +56,58 @@ // Copyright (c) 2013 Sune Simonsen <sune@we-knowhow.dk>

var assertions = {};
function truncateStack(err, fn) {
if (Error.captureStackTrace) {
Error.captureStackTrace(err, fn);
} else if ('stack' in err) {
// Excludes IE<10, and fn cannot be anonymous for this backup plan to work:
var stackEntries = err.stack.split(/\r\n?|\n\r?/),
needle = 'at ' + fn.name + ' ';
for (var i = 0 ; i < stackEntries.length ; i += 1) {
if (stackEntries[i].indexOf(needle) !== -1) {
stackEntries.splice(1, i);
err.stack = stackEntries.join("\n");
}
}
}
function Unexpected(assertions) {
this.assertions = assertions || {};
}
function expect(subject, testDescriptionString) {
var assertionRule = assertions[testDescriptionString];
Unexpected.prototype.format = function (message, args) {
args = map(args, function (arg) {
return inspect(arg);
});
message = message.replace(/\{(\d+)\}/g, function (match, n) {
return args[n] || match;
});
return message;
};
Unexpected.prototype.fail = function (message) {
message = message || "explicit failure";
var args = Array.prototype.slice.call(arguments, 1);
throw new Error(this.format(message, args));
};
Unexpected.prototype.findAssertionSimilarTo = function (text) {
var editDistrances = [];
forEach(getKeys(this.assertions), function (assertion) {
var distance = levenshteinDistance(text, assertion);
editDistrances.push({
assertion: assertion,
distance: distance
});
});
editDistrances.sort(function (x, y) {
return x.distance - y.distance;
});
return map(editDistrances.slice(0, 5), function (editDistrance) {
return editDistrance.assertion;
});
};
Unexpected.prototype.addAssertion = function () {
var assertions = this.assertions;
var patterns = Array.prototype.slice.call(arguments, 0, -1);
var handler = Array.prototype.slice.call(arguments, -1)[0];
forEach(patterns, function (pattern) {
ensureValidPattern(pattern);
forEach(expandPattern(pattern), function (expandedPattern) {
assertions[expandedPattern.text] = {
handler: handler,
flags: expandedPattern.flags
};
});
});
return this; // for chaining
};
Unexpected.prototype.expect = function (subject, testDescriptionString) {
var assertionRule = this.assertions[testDescriptionString];
if (assertionRule) {

@@ -88,7 +124,7 @@ var flags = reduce(assertionRule.flags, function (flags, flag) {

} catch (e) {
truncateStack(e, expect);
truncateStack(e, this.expect);
throw e;
}
} else {
var similarAssertions = expect.findAssertionSimilarTo(testDescriptionString);
var similarAssertions = this.findAssertionSimilarTo(testDescriptionString);
var message =

@@ -98,11 +134,49 @@ 'Unknown assertion "' + testDescriptionString + '", ' +

var err = new Error(message);
truncateStack(err, expect);
truncateStack(err, this.expect);
throw err;
}
};
Unexpected.prototype.inspect = inspect;
Unexpected.prototype.eql = eql;
function makeExpectFunction(unexpected) {
var expect = bind(unexpected.expect, unexpected);
unexpected.expect = expect;
expect.fail = bind(unexpected.fail, unexpected);
expect.addAssertion = bind(unexpected.addAssertion, unexpected);
expect.clone = bind(unexpected.clone, unexpected);
expect.assertions = unexpected.assertions;
return expect;
}
expect.internal = {};
Unexpected.prototype.clone = function () {
var unexpected = new Unexpected(objectCreate(this.assertions));
return makeExpectFunction(unexpected);
};
// TODO refactor this method into the assertion rule
expect.internal.expandPattern = (function () {
Unexpected.create = function () {
var unexpected = new Unexpected();
return makeExpectFunction(unexpected);
};
var expect = Unexpected.create();
function truncateStack(err, fn) {
if (Error.captureStackTrace) {
Error.captureStackTrace(err, fn);
} else if ('stack' in err) {
// Excludes IE<10, and fn cannot be anonymous for this backup plan to work:
var stackEntries = err.stack.split(/\r\n?|\n\r?/),
needle = 'at ' + fn.name + ' ';
for (var i = 0 ; i < stackEntries.length ; i += 1) {
if (stackEntries[i].indexOf(needle) !== -1) {
stackEntries.splice(1, i);
err.stack = stackEntries.join("\n");
}
}
}
}
var expandPattern = (function () {
function isFlag(token) {

@@ -172,2 +246,6 @@ return token.slice(0, 1) === '[' && token.slice(-1) === ']';

permutation.text = trim(permutation.text);
if (permutation.text === '') {
// This can only happen if the pattern only contains flags
throw new Error("Assertion patterns must not only contain flags");
}
});

@@ -178,33 +256,64 @@ return permutations;

expect.format = function (message, args) {
args = map(args, function (arg) {
return inspect(arg);
});
message = message.replace(/\{(\d+)\}/g, function (match, n) {
return args[n] || match;
});
return message;
};
expect.fail = function (message) {
message = message || "explicit failure";
var args = Array.prototype.slice.call(arguments, 1);
throw new Error(expect.format(message, args));
};
function ensureValidUseOfParenthesisOrBrackets(pattern) {
var counts = {
'[': 0,
']': 0,
'(': 0,
')': 0
};
for (var i = 0; i < pattern.length; i += 1) {
var c = pattern[i];
if (c in counts) {
counts[c] += 1;
}
if (c === ']' && counts['['] >= counts[']']) {
if (counts['['] === counts[']'] + 1) {
throw new Error("Assertion patterns must not contain flags with brackets: '" + pattern + "'");
}
expect.assertions = assertions;
if (counts['('] !== counts[')']) {
throw new Error("Assertion patterns must not contain flags with parenthesis: '" + pattern + "'");
}
expect.addAssertion = function () {
var patterns = Array.prototype.slice.call(arguments, 0, -1);
var handler = Array.prototype.slice.call(arguments, -1)[0];
forEach(patterns, function (pattern) {
forEach(expect.internal.expandPattern(pattern), function (expandedPattern) {
assertions[expandedPattern.text] = {
handler: handler,
flags: expandedPattern.flags
};
});
});
};
if (pattern[i-1] === '[') {
throw new Error("Assertion patterns must not contain empty flags: '" + pattern + "'");
}
} else if (c === ')' && counts['('] >= counts[')']) {
if (counts['('] === counts[')'] + 1) {
throw new Error("Assertion patterns must not contain alternations with parenthesis: '" + pattern + "'");
}
if (counts['['] !== counts[']']) {
throw new Error("Assertion patterns must not contain alternations with brackets: '" + pattern + "'");
}
}
if ((c === ')' || c === '|') && counts['('] >= counts[')']) {
if (pattern[i-1] === '(' || pattern[i-1] === '|') {
throw new Error("Assertion patterns must not contain empty alternations: '" + pattern + "'");
}
}
}
if (counts['['] !== counts[']']) {
throw new Error("Assertion patterns must not contain unbalanced brackets: '" + pattern + "'");
}
if (counts['('] !== counts[')']) {
throw new Error("Assertion patterns must not contain unbalanced parenthesis: '" + pattern + "'");
}
}
function ensureValidPattern(pattern) {
if (typeof pattern !== 'string' || pattern === '') {
throw new Error("Assertion patterns must be a non empty string");
}
if (pattern.match(/^\s|\s$/)) {
throw new Error("Assertion patterns can't start or end with whitespace");
}
ensureValidUseOfParenthesisOrBrackets(pattern);
}
/**

@@ -248,18 +357,2 @@ * Levenshtein distance algorithm from wikipedia

expect.findAssertionSimilarTo = function (text) {
var editDistrances = [];
forEach(getKeys(assertions), function (assertion) {
var distance = levenshteinDistance(text, assertion);
editDistrances.push({
assertion: assertion,
distance: distance
});
});
editDistrances.sort(function (x, y) {
return x.distance - y.distance;
});
return map(editDistrances.slice(0, 5), function (editDistrance) {
return editDistrance.assertion;
});
};

@@ -430,3 +523,3 @@ expect.addAssertion('[not] to be', function (value) {

try {
this.assert(expect.eql(value, this.obj));
this.assert(this.eql(value, this.obj));
} catch (e) {

@@ -441,3 +534,3 @@ if (!this.flags.not) {

expect.addAssertion('[not] to throw', '[not] to throw (error|exception)', function (fn) {
expect.addAssertion('[not] to (throw|throw error|throw exception)', function (fn) {
if (typeof this.obj !== 'function') {

@@ -483,5 +576,3 @@ throw new Error("Assertion '" + this.testDescription +

Assertion.prototype.inspect = inspect;
expect.inspect = inspect;
Assertion.prototype.eql = eql;
expect.eql = eql;

@@ -847,2 +938,8 @@ ///////////////////////// Helper functions ///////////////////////////////

function objectCreate(parent) {
function F() {}
F.prototype = parent;
return new F();
}
function reduce(arr, fun) {

@@ -889,2 +986,15 @@ if (Array.prototype.reduce) {

function extend(target) {
var extensions = Array.prototype.slice.call(arguments, 1);
return reduce(extensions, function (result, extension) {
for(var prop in extension) {
if(hasOwnProperty(extension, prop)) {
target[prop] = extension[prop];
}
}
return target;
}, target);
}
/**

@@ -957,3 +1067,3 @@ * Asserts deep equality

b = pSlice.call(b);
return expect.eql(a, b);
return eql(a, b);
}

@@ -960,0 +1070,0 @@ var ka, kb, key, i;

{
"name": "unexpected",
"version": "1.0.1",
"version": "1.0.2",
"author": "Sune Sloth Simonsen <sune@we-knowhow.dk>",

@@ -5,0 +5,0 @@ "keywords": [

/*global describe, it, expect*/
// use this instead of Object.create in order to make the tests run in
// es5 compatible browsers
// browsers that are not es5 compatible.
function create(o) {

@@ -577,30 +577,166 @@ function F() {}

describe('internal', function () {
describe('expandPattern', function () {
it('expands patterns containing multiple flags', function () {
var expanded = expect.internal.expandPattern('foo [not] [only] bar');
sortBy(expanded, 'text');
describe('addAssertion', function () {
it('is chainable', function () {
expect.addAssertion('foo', function () {})
.addAssertion('bar', function () {});
expect(expanded, 'to equal', [
{ text: 'foo bar', flags: []},
{ text: 'foo not bar', flags: ['not']},
{ text: 'foo not only bar', flags: ['not', 'only']},
{ text: 'foo only bar', flags: ['only']}
]);
expect(expanded.length, 'to be', 4);
expect(expect.assertions, 'to have keys',
'foo',
'bar');
});
describe('pattern', function () {
it("must be a string", function () {
expect(function () {
expect.addAssertion(null, function () {});
}, 'to throw', "Assertion patterns must be a non empty string");
});
it('expands patterns alternations', function () {
var expanded = expect.internal.expandPattern('foo (bar|bar baz) (qux|quux)');
sortBy(expanded, 'text');
expect(expanded, 'to equal', [
{ text: 'foo bar baz quux', flags: []},
{ text: 'foo bar baz qux', flags: []},
{ text: 'foo bar quux', flags: []},
{ text: 'foo bar qux', flags: []}
]);
expect(expanded.length, 'to be', 4);
it("must be a non empty", function () {
expect(function () {
expect.addAssertion('', function () {});
}, 'to throw', "Assertion patterns must be a non empty string");
});
it("can't start or end with whitespace", function () {
expect(function () {
expect.addAssertion(' ', function () {});
}, 'to throw', "Assertion patterns can't start or end with whitespace");
});
it("can't start with whitespace", function () {
expect(function () {
expect.addAssertion(' foo', function () {});
}, 'to throw', "Assertion patterns can't start or end with whitespace");
});
it("can't end with whitespace", function () {
expect(function () {
expect.addAssertion('foo ', function () {});
}, 'to throw', "Assertion patterns can't start or end with whitespace");
});
it("must not contain unbalanced brackets", function () {
expect(function () {
expect.addAssertion('foo [', function () {});
}, 'to throw', "Assertion patterns must not contain unbalanced brackets: 'foo ['");
expect(function () {
expect.addAssertion('foo ]', function () {});
}, 'to throw', "Assertion patterns must not contain unbalanced brackets: 'foo ]'");
});
it("must not contain unbalanced parenthesis", function () {
expect(function () {
expect.addAssertion('foo (', function () {});
}, 'to throw', "Assertion patterns must not contain unbalanced parenthesis: 'foo ('");
expect(function () {
expect.addAssertion('foo )', function () {});
}, 'to throw', "Assertion patterns must not contain unbalanced parenthesis: 'foo )'");
});
it("must not only contain flags", function () {
expect(function () {
expect.addAssertion('[foo] [bar]', function () {});
}, 'to throw', "Assertion patterns must not only contain flags");
});
describe('flags', function () {
it("must not be empty", function () {
expect(function () {
expect.addAssertion('foo []', function () {});
}, 'to throw', "Assertion patterns must not contain empty flags: 'foo []'");
});
it("must not contain brackets", function () {
expect(function () {
expect.addAssertion('foo [[bar]', function () {});
}, 'to throw', "Assertion patterns must not contain flags with brackets: 'foo [[bar]'");
expect(function () {
expect.addAssertion('foo [[bar]]', function () {});
}, 'to throw', "Assertion patterns must not contain flags with brackets: 'foo [[bar]]'");
});
it("must not contain parenthesis", function () {
expect(function () {
expect.addAssertion('foo [(bar]', function () {});
}, 'to throw', "Assertion patterns must not contain flags with parenthesis: 'foo [(bar]'");
expect(function () {
expect.addAssertion('foo [bar)]', function () {});
}, 'to throw', "Assertion patterns must not contain flags with parenthesis: 'foo [bar)]'");
});
});
describe('alternations', function () {
it("must not be empty", function () {
expect(function () {
expect.addAssertion('foo ()', function () {});
}, 'to throw', "Assertion patterns must not contain empty alternations: 'foo ()'");
expect(function () {
expect.addAssertion('foo (bar|)', function () {});
}, 'to throw', "Assertion patterns must not contain empty alternations: 'foo (bar|)'");
expect(function () {
expect.addAssertion('foo (||)', function () {});
}, 'to throw', "Assertion patterns must not contain empty alternations: 'foo (||)'");
expect(function () {
expect.addAssertion('foo (|bar|)', function () {});
}, 'to throw', "Assertion patterns must not contain empty alternations: 'foo (|bar|)'");
});
it("must not contain brackets", function () {
expect(function () {
expect.addAssertion('foo ([bar)', function () {});
}, 'to throw', "Assertion patterns must not contain alternations with brackets: 'foo ([bar)'");
expect(function () {
expect.addAssertion('foo (bar])', function () {});
}, 'to throw', "Assertion patterns must not contain alternations with brackets: 'foo (bar])'");
});
it("must not contain parenthesis", function () {
expect(function () {
expect.addAssertion('foo ((bar)', function () {});
}, 'to throw', "Assertion patterns must not contain alternations with parenthesis: 'foo ((bar)'");
expect(function () {
expect.addAssertion('foo ((bar))', function () {});
}, 'to throw', "Assertion patterns must not contain alternations with parenthesis: 'foo ((bar))'");
});
});
});
});
describe('clone', function () {
var clonedExpect;
beforeEach(function () {
clonedExpect = expect.clone();
clonedExpect.addAssertion('[not] to be answer to the Ultimate Question of Life, the Universe, and Everything', function () {
this.assert(this.obj === 42);
});
});
it('changes to the clone does not affect the orignal instance', function () {
expect(expect.assertions, 'not to have keys',
'to be answer to the Ultimate Question of Life, the Universe, and Everything',
'not to be answer to the Ultimate Question of Life, the Universe, and Everything');
});
it('assertions can be added to the clone', function () {
expect(clonedExpect.assertions, 'to have keys',
'to be answer to the Ultimate Question of Life, the Universe, and Everything',
'not to be answer to the Ultimate Question of Life, the Universe, and Everything');
clonedExpect(42, 'to be answer to the Ultimate Question of Life, the Universe, and Everything');
clonedExpect(41, 'not to be answer to the Ultimate Question of Life, the Universe, and Everything');
expect(function () {
clonedExpect(41, 'to be answer to the Ultimate Question of Life, the Universe, and Everything');
}, 'to throw');
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc