Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package node-url-parse Hi all, node-parse-url is vulnerable to CVE-2018-3737 (#906058). I imported upstream patch and enable upstream tests. The debdiff is quite big due to test modules import, however the change on installed files is only (see CVE-2018-3737.diff patch): --- a/index.js +++ b/index.js @@ -20,6 +20,9 @@ var rules = [ ['#', 'hash'], // Extract from the back. ['?', 'query'], // Extract from the back. + function sanitize(address) { // Sanitize what is left of the address + return address.replace('\\', '/'); + }, ['/', 'pathname'], // Extract from the back. ['@', 'auth', 1], // Extract from the front. [NaN, 'host', undefined, 1, 1], // Set left over value. @@ -189,10 +192,14 @@ // When the authority component is absent the URL starts with a path // component. // - if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname']; + if (!extracted.slashes) instructions[3] = [/(.*)/, 'pathname']; for (; i < instructions.length; i++) { instruction = instructions[i]; + if (typeof instruction === 'function') { + address = instruction(address); + continue; + } parse = instruction[0]; key = instruction[1]; Full changes: * Declare compliance with policy 4.3.0 * Add patch to fix bad URL parsing (Closes: #906058, CVE-2018-3774) * Enable upstream tests using pkg-js-tools. This adds node-deep-eql, node-object-inspect and node-pathval in build dependencies * Fix VCS fields * Fix debian/copyright format URL * Fix description (trailing whitespaces) * Add upstream/metadata Reverse dependencies: node-url-parse +-> node-original +-> node-eventsource No end-user package depends on node-url-parse, so I think it is low risky to upgrade node-url-parse. Cheers, Xavier unblock node-url-parse/1.2.0-2
diff --git a/debian/changelog b/debian/changelog index 5531fe2..04127dd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +node-url-parse (1.2.0-2) unstable; urgency=medium + + * Team upload + * Bump debhelper compatibility level to 11 + * Declare compliance with policy 4.3.0 + * Add patch to fix bad URL parsing (Closes: #906058, CVE-2018-3774) + * Enable upstream tests using pkg-js-tools. This adds node-deep-eql, + node-object-inspect and node-pathval in build dependencies + * Fix VCS fields + * Fix debian/copyright format URL + * Fix description (trailing whitespaces) + * Add upstream/metadata + + -- Xavier Guimard <y...@debian.org> Tue, 16 Apr 2019 10:18:36 +0200 + node-url-parse (1.2.0-1) unstable; urgency=medium * Team upload @@ -27,4 +42,3 @@ node-url-parse (1.0.2-1) unstable; urgency=low * Initial release -- Thorsten Alteholz <deb...@alteholz.de> Wed, 02 Sep 2015 18:07:46 +0200 - diff --git a/debian/control b/debian/control index f46f9e2..2c683c6 100644 --- a/debian/control +++ b/debian/control @@ -3,17 +3,22 @@ Section: javascript Priority: optional Maintainer: Debian Javascript Maintainers <pkg-javascript-de...@lists.alioth.debian.org> Uploaders: Thorsten Alteholz <deb...@alteholz.de> +Testsuite: autopkgtest-pkg-nodejs Build-Depends: debhelper (>= 9) , dh-buildinfo , nodejs , webpack + , node-deep-eql <!nocheck> , node-requires-port (>= 0.0.1) + , node-object-inspect <!nocheck> , node-querystringify (>= 0.0.3) -Standards-Version: 4.1.3 + , node-pathval <!nocheck> + , pkg-js-tools +Standards-Version: 4.3.0 Homepage: https://github.com/unshiftio/url-parse#readme -Vcs-Git: https://anonscm.debian.org/git/pkg-javascript/node-url-parse.git -Vcs-Browser: https://anonscm.debian.org/gitweb/?p=pkg-javascript/node-url-parse.git +Vcs-Browser: https://salsa.debian.org/js-team/node-url-parse +Vcs-Git: https://salsa.debian.org/js-team/node-url-parse.git Package: node-url-parse Architecture: all @@ -23,19 +28,19 @@ Depends: , node-requires-port (>= 0.0.1) , node-querystringify (>= 0.0.3) Description: Parse URL in node using the URL module and in the browser using the DOM - The url-parse method exposes two different API interfaces. The url interface - that you know from Node.js and the new URL interface that is available in + The url-parse method exposes two different API interfaces. The url interface + that you know from Node.js and the new URL interface that is available in the latest browsers. . - Since 0.1 we've moved away from using the DOM's <a> element for URL parsing - and moving to a full Regular Expression solution. The main reason for this - change is to make the URL parser available in different JavaScript - environments as you don't always have access to the DOM like Worker - environments. This module still have a really small foot print as this - module's main intention is to be bundled with client-side code. The only - problem however with a RegExp based solution is that it required a lot of - lookups causing major problems in FireFox. So the last and the current - solution was a pure string parsing solution which chops up the URL in + Since 0.1 we've moved away from using the DOM's <a> element for URL parsing + and moving to a full Regular Expression solution. The main reason for this + change is to make the URL parser available in different JavaScript + environments as you don't always have access to the DOM like Worker + environments. This module still have a really small foot print as this + module's main intention is to be bundled with client-side code. The only + problem however with a RegExp based solution is that it required a lot of + lookups causing major problems in FireFox. So the last and the current + solution was a pure string parsing solution which chops up the URL in smaller pieces. . Node.js is an event-based server-side JavaScript engine. diff --git a/debian/copyright b/debian/copyright index 490b21b..94bfaf0 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,16 +1,58 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: url-parse Upstream-Contact: https://github.com/unshiftio/url-parse/issues Source: https://github.com/unshiftio/url-parse#readme Files: * -Copyright: 2015 Arnout Kazemier +Copyright: 2015 Arnout Kazemier <https://github.com/3rd-Eden> License: Expat Files: debian/* Copyright: 2015 Thorsten Alteholz <deb...@alteholz.de> License: Expat +Files: debian/tests/test-modules/assume/* +Copyright: 2015 Arnout Kazemier <https://github.com/3rd-Eden> + 2015 Martijn Swaagman +License: Expat + +Files: debian/tests/test-modules/fn.name/* +Copyright: Arnout Kazemier <https://github.com/3rd-Eden> +License: Expat +Comment: The upstream distribution does not contain an explicit statement of + copyright ownership. Pursuant to the Berne Convention for the Protection of + Literary and Artistic Works, it is assumed that all content is copyright by + its respective authors unless otherwise stated. + +Files: debian/tests/test-modules/pruddy-error/* +Copyright: 1998 Regents of the University of California +License: BSD-3-Clause + +License: BSD-3-Clause + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the University of California, Berkeley nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -31,4 +73,3 @@ License: Expat ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/debian/patches/CVE-2018-3774.diff b/debian/patches/CVE-2018-3774.diff new file mode 100644 index 0000000..bfc6e6a --- /dev/null +++ b/debian/patches/CVE-2018-3774.diff @@ -0,0 +1,67 @@ +Description: Fix for CVE-2018-3774 +Author: Xavier Guimard <y...@debian.org> +Origin: https://github.com/unshiftio/url-parse/commit/53b1794e54d0711ceb52505e0f74145270570d5a +Bug: https://security-tracker.debian.org/tracker/CVE-2018-3774 +Bug-Debian: https://bugs.debian.org/906058 +Forwarded: //github.com/unshiftio/url-parse/commit/53b1794e54d0711ceb52505e0f74145270570d5a +Last-Update: 2019-04-16 + +--- a/index.js ++++ b/index.js +@@ -20,6 +20,9 @@ + var rules = [ + ['#', 'hash'], // Extract from the back. + ['?', 'query'], // Extract from the back. ++ function sanitize(address) { // Sanitize what is left of the address ++ return address.replace('\\', '/'); ++ }, + ['/', 'pathname'], // Extract from the back. + ['@', 'auth', 1], // Extract from the front. + [NaN, 'host', undefined, 1, 1], // Set left over value. +@@ -189,10 +192,14 @@ + // When the authority component is absent the URL starts with a path + // component. + // +- if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname']; ++ if (!extracted.slashes) instructions[3] = [/(.*)/, 'pathname']; + + for (; i < instructions.length; i++) { + instruction = instructions[i]; ++ if (typeof instruction === 'function') { ++ address = instruction(address); ++ continue; ++ } + parse = instruction[0]; + key = instruction[1]; + +--- a/test/test.js ++++ b/test/test.js +@@ -179,6 +179,28 @@ + assume(parsed.pathname).equals('/b/c'); + }); + ++ it('ignores \\ in pathnames', function () { ++ var url = 'http://google.com:80\\@yahoo.com/#what\\is going on' ++ , parsed = parse(url); ++ ++ assume(parsed.port).equals(''); ++ assume(parsed.username).equals(''); ++ assume(parsed.password).equals(''); ++ assume(parsed.hostname).equals('google.com'); ++ assume(parsed.hash).equals('#what\\is going on'); ++ ++ parsed = parse('//\\what-is-up.com'); ++ assume(parsed.pathname).equals('/what-is-up.com'); ++ }); ++ ++ it('correctly ignores multiple slashes //', function () { ++ var url = '////what-is-up.com' ++ , parsed = parse(url); ++ ++ assume(parsed.host).equals(''); ++ assume(parsed.hostname).equals(''); ++ }); ++ + describe('origin', function () { + it('generates an origin property', function () { + var url = 'http://google.com:80/pathname' diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..1ae99bc --- /dev/null +++ b/debian/patches/series @@ -0,0 +1 @@ +CVE-2018-3774.diff diff --git a/debian/rules b/debian/rules index e969a15..63df0cc 100755 --- a/debian/rules +++ b/debian/rules @@ -5,14 +5,11 @@ #export DH_VERBOSE=1 %: - dh $@ + dh $@ --with nodejs override_dh_auto_build: webpack --config debian/webpack.config.js --output-library=URLParse index.js dist/url-parse.js uglifyjs dist/url-parse.js > dist/url-parse.min.js -#override_dh_auto_test: - override_dh_auto_clean: rm -rf dist - diff --git a/debian/tests/control b/debian/tests/control deleted file mode 100644 index b96f048..0000000 --- a/debian/tests/control +++ /dev/null @@ -1,2 +0,0 @@ -Tests: require -Depends: node-url-parse diff --git a/debian/tests/pkg-js/files b/debian/tests/pkg-js/files new file mode 100644 index 0000000..e15fb91 --- /dev/null +++ b/debian/tests/pkg-js/files @@ -0,0 +1,2 @@ +debian/tests/test-modules +test diff --git a/debian/tests/pkg-js/test b/debian/tests/pkg-js/test new file mode 100644 index 0000000..7fc49b4 --- /dev/null +++ b/debian/tests/pkg-js/test @@ -0,0 +1 @@ +NODE_PATH=debian/tests/test-modules mocha -R spec --timeout 10000 test/test.js diff --git a/debian/tests/require b/debian/tests/require deleted file mode 100644 index 2b5f6c0..0000000 --- a/debian/tests/require +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -nodejs -e "require('url-parse');" diff --git a/debian/tests/test-modules/assume/.npmignore b/debian/tests/test-modules/assume/.npmignore new file mode 100644 index 0000000..9b845b1 --- /dev/null +++ b/debian/tests/test-modules/assume/.npmignore @@ -0,0 +1,5 @@ +node_modules +coverage +test +.tern-port +npm-debug.log diff --git a/debian/tests/test-modules/assume/.travis.yml b/debian/tests/test-modules/assume/.travis.yml new file mode 100644 index 0000000..1330e28 --- /dev/null +++ b/debian/tests/test-modules/assume/.travis.yml @@ -0,0 +1,25 @@ +sudo: false +language: node_js +node_js: + - "iojs-v3" + - "iojs-v2" + - "iojs-v1" + - "0.12" + - "0.10" + - "0.8" +before_install: + - "npm install -g npm@2.1.18" +script: + - "npm run test-travis" +after_script: + - "npm install coveralls@2.11.x && cat coverage/lcov.info | coveralls" +matrix: + fast_finish: true + allow_failures: + - node_js: "0.8" +notifications: + irc: + channels: + - "irc.freenode.org#bigpipe" + on_success: change + on_failure: change diff --git a/debian/tests/test-modules/assume/LICENSE b/debian/tests/test-modules/assume/LICENSE new file mode 100644 index 0000000..b68d272 --- /dev/null +++ b/debian/tests/test-modules/assume/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Arnout Kazemier, Martijn Swaagman, the Contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/debian/tests/test-modules/assume/README.md b/debian/tests/test-modules/assume/README.md new file mode 100644 index 0000000..86f6233 --- /dev/null +++ b/debian/tests/test-modules/assume/README.md @@ -0,0 +1,842 @@ +# assume + +[![From bigpipe.io][from]](http://bigpipe.io)[![Version npm][version]](http://browsenpm.org/package/assume)[![Build Status][build]](https://travis-ci.org/bigpipe/assume)[![Dependencies][david]](https://david-dm.org/bigpipe/assume)[![Coverage Status][cover]](https://coveralls.io/r/bigpipe/assume?branch=master) + +[from]: https://img.shields.io/badge/from-bigpipe.io-9d8dff.svg?style=flat-square +[version]: http://img.shields.io/npm/v/assume.svg?style=flat-square +[build]: http://img.shields.io/travis/bigpipe/assume/master.svg?style=flat-square +[david]: https://img.shields.io/david/bigpipe/assume.svg?style=flat-square +[cover]: http://img.shields.io/coveralls/bigpipe/assume/master.svg?style=flat-square + +Assume is an `expect` inspired assertion library who's sole purpose is to create +a working and human readable assert library for browsers and node. The library +is designed to work with different assertion styles. + +I've been trying out a lot of libraries over the last couple of years and none +of the assertion libraries that I found "tickled my fancy". They either only +worked in node or had really bad browser support. I wanted something that I can +use starting from Internet Explorer 5 to the latest version while maintaining +the `expect` like API that we all know and love. Writing tests should be dead +simple and not cause any annoyances. This library attempts to achieve all of +this. + +## Installation + +Assume is written with client and server-side JavaScript in mind and uses the +commonjs module system to export it self. The library is released in the public +npm registry and can be installed using: + +``` +npm install --save-dev assume +``` + +The `--save-dev` flag tells `npm` to automatically add this `package.json` and it's +installed version to the `devDependencies` of your module. + +As code is written against the commonjs module system we also ship a standalone +version in the module which introduces an `assume` global. The standalone +version can be found in the `dist` folder after installation. The dist file is +not commited to GitHub. + +## Table of Contents + +- [Installation](#installation) +- [Syntax](#syntax) +- [Configuration](#configuration) +- [Feature Detection](#feature-detection) +- [Performance Testing](#performance-testing) +- [Assertion](#assertion) + - [Keywords](#keywords) +- [API](#api) + - [a, an](#a-an) + - [eitherOfType, oneOfType](#eitheroftype-oneoftype) + - [instanceOf, instanceof, inherits, inherit](#instanceof-instanceof-inherits-inherit) + - [include, includes, contain, contains](#include-includes-contain-contains) + - [ok, okay, truthy, truely](#ok-okay-truthy-truely) + - [falsely, falsey](#falsely-falsey) + - [true](#true) + - [false](#false) + - [exists, exist](#exists-exist) + - [length, lengthOf, size](#length-lengthof-size) + - [empty](#empty) + - [above, gt, greater, greaterThan](#above-gt-greater-greaterthan) + - [least, gte, atleast](#least-gte-atleast) + - [below, lt, less, lessThan](#below-lt-less-lessthan) + - [most, lte, atmost](#most-lte-atmost) + - [within, between](#within-between) + - [hasOwn, own, ownProperty, haveOwnProperty, property, owns, hasown](#hasown-own-ownproperty-haveownproperty-property-owns-hasown) + - [match, matches](#match-matches) + - [equal, equals, eq, eqs, exactly](#equal-equals-eq-eqs-exactly) + - [eql, eqls](#eql-eqls) + - [either](#either) + - [throw, throws, fail, fails](#throw-throws-fail-fails) + - [finite, isFinite, finiteness](#finite-isfinite-finiteness) + - [generator](#generator) + - [optimisation, optimization](#optimisation-optimization) + - [optimised, optimized](#optimised-optimized) + - [start, starts, startsWith, startWith](#start-stats-startswith-startwith) + - [end, ends, endsWith, endWith](#end-ends-endswith-endwith) + - [closeTo, close, approximately, near](#closeto-close-approximately-near) +- [i.hope](#ihope) +- [Planning](#planning) +- [Waiting](#waiting) +- [Plugins](#plugins) + - [Publishing](#publishing) + - [use](#use) + - [add](#add) + - [test](#test) + - [assign](#assign) + - [clone](#clone) + +## Syntax + +We support a lot of different syntaxes and assertion styles. The only thing we +will no (read never) support is the `should` syntax as we will never extend +build-in objects/primitives of JavaScript. + +The default syntax that we support is modeled after `expect` so you can replace +any assertion library which implements this API by simply changing the require +to: + +```js +var expect = require('assume'); + +expect('foo').equals('foo'); +expect('foo').is.a('string'); +``` + +As you can see in the example above the `is` property is used to make the +assertion more readable. We support the following aliases which allow these kind +of chains: + +- `to` +- `be` +- `been` +- `is` +- `and` +- `has` +- `with` +- `that` +- `at` +- `of` +- `some` +- `does` +- `itself` +- `which` + +So you can just write: + +```js +assume(100).is.at.most(100); +``` + +But do note that these aliases are **optionally** so the above example can also +be written as: + +```js +assume(100).most(1000); +``` + +### Configuration + +The module can be configured globally be changing the properties on the `config` +object: + +```js +var assume = require('assume'); +assume.config.includeStack = false; +``` + +Or locally for each assertions by supplying the `assume` function with an +optional configuration object: + +```js +assume('foo', { includeStack: false }).is.a('buffer'); +``` + +The following options can be configured: + +- **`includeStack`** Should we output a stack trace. Defaults to `true`. +- **`showDIff`** Show difference between the given and expected values. Defaults + to `true`. + +### Feature Detection + +Certain assertions only work in certain JavaScript/EcmaScript environments. +Things like the `generator` assertions only work in ES6 as the `function *` is +invalid syntax. The results of the feature detection is publicly stored in the +`assume.supports` object. You can use this object to add some conditional tests +to your test suite. The following features are currently detected: + +- **generators** Are generators supported in the host environment. +- **native** Is V8 native syntax supported. + +```js +if (assume.supports.native) { + it('does things', function () { + .. + }); +} +``` + +If you are a plugin author, feel free to add your own feature detections to this +object (as long as you do not override any pre-existing values). + +### Performance Testing + +The performance testing is only available for environments that use V8 and more +specifically the `--allow-natives-syntax` flags. These flags can be supplied in +[chrome before you start browser][flags]. These flags are necessary to get +access to the V8 internals which expose optimization and de-optimization +information. + +If you are running `iojs` or `node` on the server, you can pass in these flags +directly: + +``` +iojs --allow-natives-syntax +``` + +#### Mocha + +If you are using `mocha` as test runner you usually add `mocha` as executable. +But unfortunately, the `mocha` binary doesn't allow you to pass V8 flags. So +instead of using the `mocha` binary directly you can use the `node` and call the +`_mocha` binary instead: + +``` +node --allow-natives-syntax --harmony ./node_modules/mocha/bin/_mocha test/test.js +``` + +You can check if your host environment supports these performance tests by +checking the `assume.supports.native` variable. + +### Assertion + +There are various of assertions available in assume. If you want the failed +assertion to include a custom message or reason you can **always** add this as last +argument of the assertion function. + +```js +assume(true).is.false('how odd, true is not a false'); +``` + +The behaviours of the assertions can be chained using special "flags" or +"prefixes". We currently support the following prefixes. + +- `.not`, `.doesnt`, `.dont` Instead of assuming that your assertions assert to + `true` they will now assert for `false`. +- `.deep`, `.deeply`, `.strict` `.strictly` Instructs the assertions to do a + **deep** equal, so it checks if the contents match instead of an `object` it + self matches. + +For example: + +```js +assume(false).is.not.true(); +assume({foo:'bar'}).deep.equals({foo:'bar'}); +``` + +#### Keywords + +Now, a special word of caution for those of you who are using this library to +write cross browser tests. Internet Explorer has issues when you use +**keywords** as functions. Using the `true()`, `instanceof()` etc. functions to +assert you will run in to issues. So the rule of thumb here is that if you need +to do cross browser support do not assert with the keyword based names. + +## API + +Let's take a closer look to all assertions that we're supporting: + +#### a, an + +Asserts if the given value is the correct type. We need to use Object.toString +here because there are some implementation bugs the `typeof` operator: + +- Chrome <= 9: /Regular Expressions/ are evaluated to `function` + +As well as all common flaws like Arrays being seen as Objects etc. This +eliminates all these edge cases. + +```js +assume([]).is.a('array'); +``` + +[`instanceof` is a keyword and might cause cross browser issues](#keywords) + +#### eitherOfType, oneOfType + +Asserts if the given value is one of the acceptable types. + +The same caveats regarding `typeof` apply as described in [a, an](#a-an). + +```js +assume([]).is.oneOfType(['array', 'string']); +``` + +#### instanceOf, instanceof, inherits, inherit + +Asserts that the value is instanceof the given constructor. + +```js +function Classy() {} + +var classes = new Classy(); + +assume(classes).is.an.instanceOf(Classy); +``` + +#### include, includes, contain, contains + +Assert that value includes a given value. I know this sounds vague but an +example might be more useful here. It can check this for strings, objects and +arrays. + +```js +assume({foo: 'bar'}).contains('foo'); +assume('hello world').includes('world'); +assume([1,3,4]).contains(1); +``` + +#### ok, okay, truthy, truely + +Assert that the value is truthy. + +```js +assume(1).is.ok(); +assume(0).is.not.ok(); +assume(true).is.ok(); +``` + +#### falsely, falsey + +Assert that the value is falsey. + +```js +assume(0).is.falsely(); +assume(true).is.not.falsey(); +assume(null).is.falsely; +``` + +#### true + +Explicitly check that the value is the boolean `true`. + +```js +assume(true).true(); +``` + +[`true` is a keyword and might cause cross browser issues](#keywords) + +#### false + +Explicitly check that the value is the boolean `false`. + +```js +assume(false).false(); +``` + +[`false` is a keyword and might cause cross browser issues](#keywords) + +#### exists, exist + +Check if the value not not `null`. + +```js +assume('hello').exists(); +assume(undefined).exists(); // throws +``` + +#### length, lengthOf, size + +Assert if the given value has the given length. It accepts arrays, strings, +functions, object and anything else that has a `.length` property. + +```js +assume({ foo: 'bar' }).has.length(1); +assume([1,2,3,4,5,6]).is.size(6) +``` + +#### empty + +Short hand function for `assume(val).length(0)` so it can check if objects, +arrays, strings are empty. + +```js +assume([]).empty(); +assume('').empty(); +assume({}).empty(); + +// +// Also works against everything that has a `.length` property +// +localStorage.clear(); +assume(localStorage).is.empty(); +``` + +#### above, gt, greater, greaterThan + +Assert if the value is above the given value. If you need greater or equal check +out the `least` method. If value to assert is not a number we automatically +extract the length out of it so you can use it check the length of arrays etc. + +```js +assume(100).is.above(10); +``` + +#### least, gte, atleast + +Assert if the value is above or equal to the given value. If you just need +greater check out the `above` method. If value to assert is not a number we +automatically extract the length out of it so you can use it check the length of +arrays etc. + +```js +assume(100).is.least(10); +assume(100).is.least(100); +``` + +#### below, lt, less, lessThan + +Assert if the value is less than the given value. If you need less or equal +check out the `most` method. If value to assert is not a number we automatically +extract the length out of it so you can use it check the length of arrays etc. + +```js +assume(10).is.below(100); +``` + +#### most, lte, atmost + +Assert if the value is less or equal to the given value. If you just need less, +check out the `less` method. If value to assert is not a number we automatically +extract the length out of it so you can use it check the length of arrays etc. + +```js +assume(10).is.most(100); +assume(100).is.most(100); +``` + +#### within, between + +Check if the value is between or equal to a given range. If value to assert is +not a number we automatically extract the length out of it so you can use it +check the length of arrays etc. + +```js +assume(100).is.between(90, 100); +assume([1, 213, 13, 94, 5, 6, 7]).is.between(2, 10); +``` + +#### hasOwn, own, ownProperty, haveOwnProperty, property, owns, hasown + +Assert that the value has the specified property and optionally +deeply check its value. + +```js +assume({foo: 'bar'}).owns('foo'); +assume({foo: 'bar'}).owns('foo', 'bar'); +``` + +#### match, matches + +Matches the value against a given Regular Expression. If a string is given +instead of an actual Regular Expression we automatically transform it to an `new +RegExp`. + +```js +assume('hello world').matches(/world$/); +``` + +#### equal, equals, eq, eqs, exactly + +Assert that given value is strictly (===) equal to the supplied value. + +```js +assume('foo').equals('foo'); +assume(13424).equals(13424); +``` + +#### eql, eqls + +Assert that the given value deeply equals the supplied value. + +```js +assume([1,2]).eql([1,2]); +``` + +#### either + +Assert that the value is either one of the values of the given array. It can be +prefixed with `.deep` for deep assertions. + +```js +assume('foo').is.either(['bar', 'banana', 'foo']); +assume({ foo: 'bar' }).is.either(['bar', 'banana', { foo: 'bar' }]); +``` + +#### throw, throws, fail, fails + +Assert that the given function throws an error. The error can match a string, +regexp or function instance. + +```js +function arrow() { throw new Error('you have failed this city'); } + +assume(arrow).throws(/failed this city/); +assume(arrow).throws('failed this city'); +assume(arrow).does.not.throw('your mom'); +assume(function(){}).does.not.throw(); +``` + +[`throw` is a keyword and might cause cross browser issues](#keywords) + +#### finite, isFinite, finiteness + +Assert that the given value is finite. + +```js +assume(Infinity).is.finite(); +``` + +If `deep` assertion style is used it will use the much stricter +`Number.isFinite` instead of the regular `isFinite` functionality. + +#### generator + +Assert that the given value is an EcmaScript 6 based generator. + +```js +assume(function *() {}).is.generator(); +``` + +**Please note that this will only work if Generators are enabled in the host +environment or you might end up with false positives** + +#### optimisation, optimization + +**Please see the [Performance Testing](#performance-testing) section information +to enable these assertions as they require specific V8 flags to be enabled.** + +#### optimised, optimized + +**Please see the [Performance Testing](#performance-testing) section information +to enable these assertions as they require specific V8 flags to be enabled.** + +#### start, starts, startsWith, startWith + +Assert that the value starts with the given string. + +```js +assume('foobar').startWith('foo'); +``` + +#### end, ends, endsWith, endWith + +Assert that the value ends with the given string. + +```js +assume('foor bar, banana').endsWith('ana'); +``` + +#### closeTo, close, approximately, near + +Assert a float point number is near a given value within a delta margin. + +```js +assume(1.5).is.approximately(1.4, 0.2); +``` + +### i.hope + +The asserts we write are assumptions that we receive a given value. While you're +writing tests you hope that they all pass. We could write these tests using an +`i.hope.that(value)` syntax: + +```js +var i = require('assume'); + +i.hope.that('foo').is.a('string'); +i.expect.that('foo').is.a('string'); +i.assume.that('foo').equals('bar'); +i.sincerely.hope.that('foo').is.a('string'); +``` + +## Planning + +The `assume.plan` method allows you to plan the amount of assertions that should +be executed by your test suite. This method accepts 2 arguments: + +1. The amount of assertions you expect to run. This should always be an exact + number. +2. An optional async callback that should be called with error as first argument + on failure instead of throwing an error. This makes it ideal for async + testing as you can just pass your continuation function. + +The method will return a function that should be called at the end of your +tests. This method will still allow you to pass in an error as first argument so +the supplied callback in second argument will be called directly with it. + +When the method is called we will count the amount of assertions that we're +executed. If it's less or more than the supplied amount we will throw an error. + +```js +var end = assume.plan(10); + +assume(10).equals(10); +end(); // This throws an error as we only executed 1 out of the 10 asserts. +``` + +And with optional async callback: + +```js +next = assume.plan(7, next); + +for (var i = 0; i < 10; i++) { + assume(i).equqls(i); +} + +next(); // Also throws an error as we've executed 10 assertions instead of 7. +``` + +## Waiting + +Writing async tests can be hard, especially if you have to juggle with callbacks +and wait untill 2 callbacks are completed before you can continue with the test +suite. The `assume.wait` function helps you with orchestration of tests and +callbacks. The method accepts 3 arguments: + +1. The amount of times the returned callback should be called before calling the + supplied callback. +2. Optionally, the amount of assertions you expect to run. We will wrap the + returned callback with `assume.plan` this way. +3. Completion callback which is called after the callbacks have been called. + +The method will return a function that should be used as callback for your async +tests. It follows an error first callback pattern and instantly calls the +supplied callback once an error has be passed in as error argument. + +```js + it('does async things', function (next) { + next = assume.wait(2, 4, next); + + asynctask(function (err, data) { + assume(err).is.a('undefined'); + assume(data).equals('testing'); + + next(); + }); + + asynctaskfail(function (err, data) { + assume(err).is.a('undefined'); + assume(data).equals('testing'); + + next(); + }); + }); + ``` + +## Plugins + +We've done our best to include a bunch of assertions that should make it easier +to test your code but it's always possible that we're missing assertions or you +just want to eliminate repetition in your code. So we've got a plugin interface +which allows you to extend the `assume` instance with even more assertions. + +### Publishing + +For the sake of discoverablity ability of your plugins on npm we suggest to either +suffix or prefix your module with `assume` and adding the `assume` keyword in to +your keywords list. + +### use + +Let's assume that we've want to extend the library with a method for checking +the headers of a passed in HTTP request object. If it was released in npm we +could add it as following: + +```js +assume.use(require('assume-headers')); +``` + +The `use` method returns `assume` so it can be used to chain multiple plugin +calls together: + +```js +assume +.use(require('assume-headers')) +.use(require('assume-method')); +``` + +The `assume-headers` plugin/module should export a function which receives the +assume instance to extend as illustrated by the example below: + +```js +module.exports = function plugin(assume, util) { + /** + * Assert that the received HTTP request contains a given header. + * + * @param {String} name Name of the header that we should have received. + * @param {String} ms Reason of failure. + * @returns {Assume} + * @api public + */ + assume.add('header', function header(name, msg) { + var expect = '`'+ util.string(this.value.header)'` to @ have header '+ util.string(name); + + return this.test(name in this.value.headers, msg, expect); + }); +} +``` + +The plugin receives 2 arguments: + +1. A reference to the `assume` instance so it can be extended. +2. Small assertion helper library which contains all the internals we're using. + +The helper library contains the following methods: + +- **name**, Reference to the `fn.name` module so you extract names from + functions. +- **get**, Reference to the `get` method of the `pathval` module. +- **string**, Inspection function which safely transforms objects, numbers, + dates etc. to a string. +- **deep**, A deep assertion if the two argument deeply equal to each other. +- **type**, Extract the type of an object to an lowercase string. Useful for + detecting the difference between `object`, `array`, `arguments`, `date`, + `buffer` etc. +- **size**, A function which returns the size of given object or array. +- **each**, Simple iterator which accepts an array/object and calls the supplied + callback with the value and key/index. +- **nodejs**, Boolean indicating if we are running on `nodejs`. + +New flags can be introduced by adding properties to the `flags` object. The +`flags` object has the following structure: + +- `key` This is the name of the property which will be added to the `assume` + instance. The property is set to `false` by default and will be to `true` once + once of the `flags` is accessed. +- `value` These are the aliases that can be used to the set the property to + `true`. + +For our `.not` flags we've set the following key/value's: + +```js +Assert.flags.untrue = 'doesnt, not, dont'; +``` + +Please do note that you should try to limit the amount of flags that you add as +they are quite expensive to process every single time. + +Adding new assertions to assume can be done using the following methods: + +#### add + +The `assume.add` method is a convince method for adding new methods to the +assume prototype. It was created using the [`assign`](#assign) method so it can +automatically add aliases/shorthand's of the method to the prototype in one go. +The method requires 2 arguments: + +1. A string which is comma or space separated or an array which contains the + names of the methods that should be added to the prototype. +2. The function or value that is assigned for all these properties. + +```js +module.exports = function (assume, util) { + util.each(['GET', 'POST', 'PUT', 'DELETE'], function each(method) { + assume.add(method, function () { + var expect = '`'+ util.string(this.value.method)+'` to @ be '+ method; + + return this.test(this.value.method === method, msg, expect); + }); + }); +} +``` + +If you want to add more aliases for the `.function()` method you can simply do +a: + +```js +assume.add('execute, executes, exec', function () { + return this.clone().is.a('function'); +}); +``` + +The value to assert is stored in the `value` property of the instance. If the +`deep` flag is set, the `deeply` property is set to `true`. + +#### test + +This is the method that handles all the assertion passing and failing. It's +_the_ most important method of all. It accepts the following arguments: + +- `passed`, a boolean which indicates if the assertion failed or passed. +- `msg`, a string which is the reason or message provided by the users. +- `expectation`, a compiled template which explains what the assertion expected. +- `slice`, a number which slices of stacks from the stack trace. This is keeps + the stack trace clear of all references to our own assertion library and only + contains the part of the test/suite where the assertion was initiated. This + value is optional and defaults to `2` so it removes the `test` and the + `assertion` from the stack. + +If the `assertion` passes the method will return it self, or it will throw. + +```js +assume.add('true', function (msg) { + var expectation = format('value to @ be true'); + return this.test(this.value === true, msg, expectation); +}); +``` + +In example above you might have noticed the odd `@` in the `expection` value. +This is a special character and will be replaced with `not` if the `.not` flag +was used or completely removed (including an extra whitespace at the end). + +#### assign + +Assign multiple values to a given thing. This method accepts one argument which +is an object or prototype on where we should assign things. It will return a +function that is responsible for the assignment on that given thing. The return +function will require 2 arguments: + +1. A string which is comma or space separated or an array which contains the + names of the methods that should be added to the prototype. +2. The function or value that is assigned for all these properties. + +To create your own custom `add` method you could simply do: + +```js +var add = assume.assign(assign.prototype); +``` + +And the `add` function would now do exactly the same as the [`assume.add`](#add) +method. + +#### clone + +Create an exact clone of the assume instance so it all flags and options are +identical to the current assume instance. The method accepts one optional +argument which is the value it should assert. If nothing is given it uses the +current value. + +This can be helpful if you want to run assertions in your assertions so you can +assert while you assert. + +```js +// Yo dawg, I herd you like assertions so I put assertions in the assertions so +// you can assert while you assert. + +assume.add('something', function somethign(value, msg) { + this.clone().is.a('string'); + this.clone().is.endsWith('thing'); + + return this.test(this.value ==== 'something', msg, 'the value should be something'); +}); +``` + +## License + +MIT + +[flags]: http://www.chromium.org/developers/how-tos/run-chromium-with-flags diff --git a/debian/tests/test-modules/assume/index.js b/debian/tests/test-modules/assume/index.js new file mode 100644 index 0000000..4ad3ea7 --- /dev/null +++ b/debian/tests/test-modules/assume/index.js @@ -0,0 +1,1068 @@ +'use strict'; + +var stringify = require('object-inspect') + , pruddy = require('pruddy-error') + , displayName = require('fn.name') + , pathval = require('pathval') + , deep = require('deep-eql'); + +var undefined + , called = 0 + , toString = Object.prototype.toString + , hasOwn = Object.prototype.hasOwnProperty + , nodejs = !!(typeof process != 'undefined' && process.versions && process.versions.node); + +/** + * Get class information for a given type. + * + * @param {Mixed} of Type to check. + * @returns {String} The name of the type. + * @api private + */ +function type(of) { + if (Buffer.isBuffer(of)) return 'buffer'; + if (of === undefined) return 'undefined'; + if (of === null) return 'null'; + if (of !== of) return 'nan'; + + return toString.call(of).slice(8, -1).toLowerCase(); +} + +/** + * Determine the size of a collection. + * + * @param {Mixed} collection The object we want to know the size of. + * @returns {Number} The size of the collection. + * @api private + */ +function size(collection) { + var x, i = 0; + + if ('object' === type(collection)) { + if ('number' === type(collection.length)) return collection.length; + + for (x in collection) { + if (hasOwn.call(collection, x)) i++; + } + + return i; + } + + try { return +collection.length || 0; } + catch (e) { return 0; } +} + +/** + * Iterate over each item in an array. + * + * @param {Array} arr Array to iterate over. + * @param {Function} fn Callback for each item. + * @api private + */ +function each(what, fn) { + if ('array' === type(what)) { + for (var i = 0, length = what.length; i < length; i++) { + if (false === fn(what[i], i, what)) break; + } + } else { + for (var key in what) { + if (false === fn(what[key], key, what)) break; + } + } +} + +/** + * Return a formatter function which compiles the expectation message. The + * message can contain various of patterns which will be replaced with + * a stringified/parsed version of the supplied argument for that given + * placeholder pattern. The following patterns are supported: + * + * - %% : Escape the % so you can write %d in your messages as %%d + * - %d : Cast argument in to a number. + * - %s : Cast argument in to a string. + * - %f : Transform function in to the name of the function. + * - %j : Transform object to a string. + * + * @param {String} expectation The expectation message. + * @returns {Function} + * @api private + */ +function format() { + var args = Array.prototype.slice.call(arguments, 0) + , expectation = args.shift() + , length = args.length + , i = 0; + + return function compile(not) { + if (not) expectation = expectation.replace(/@/g, 'not'); + else expectation = expectation.replace(/@\s/g, ''); + + return expectation.replace(/%[sdjf%]/g, function replace(char) { + if (i >= length) return char; + + switch (char) { + case '%%': + return '%'; + + case '%s': + return String(args[i++]); + + case '%d': + return Number(args[i++]); + + case '%f': + return displayName(args[i++]); + + case '%j': + try { return stringify(args[i++]); } + catch (e) { return '<error was thrown: '+ e.message +'>'; } + + default: return char; + } + }); + }; +} + +/** + * Assert values. + * + * Flags: + * + * - **stacktrace**: Include stacktrace in the assertion. + * - **diff**: Attempt to show the difference in object/values so we know why + * the assertion failed. + * - **sliceStack**: The amount of stacks we should slice off errors messages. + * + * @constructor + * @param {Mixed} value Value we need to assert. + * @param {Object} flags Assertion flags. + * @api public + */ +function Assert(value, flags) { + if (!(this instanceof Assert)) return new Assert(value, flags); + flags = flags || {}; + + this.stacktrace = 'stacktrace' in flags ? flags.stacktrace : Assert.config.includeStack; + this.sliceStack = 'slice' in flags ? flags.slice : Assert.config.sliceStack; + this.diff = 'diff' in flags ? flags.diff : Assert.config.showDiff; + + // + // These flags are by the alias function so we can generate .not and .deep + // properties which are basically new Assert instances with these flags set. + // + for (var alias in Assert.flags) { + this[alias] = alias in flags ? flags[alias] : false; + } + + this.value = value; + + Assert.assign(this)('to, be, been, is, and, has, have, with, that, at, of, same, does, itself, which'); + Assert.alias(value, this); +} + +/** + * Attempt to mimic the configuration API of chai.js so it's dead simple to + * migrate from chai.js to assume. + * + * @type {Object} + * @public + */ +Assert.config = { + includeStack: true, // mapped to `stacktrace` as default value. + showDiff: true, // mapped to `diff` as default value. + sliceStack: 2 // Number of stacks that we should slice of the err stack.. +}; + +/** + * List of flags and properties that need to be created for chaining purposes. + * Plugins could add extra properties that needed to be chained as well. + * + * @type {Object} + * @public + */ +Assert.flags = { + _not: 'doesnt, not, dont', + _deep: 'deep, deeply, strict, strictly' +}; + +/** + * Certain assertions can be disabled based on their environment that they are + * executing in. This object allows you in spect which of these conditional + * assertions are supported. + * + * @type {Object} + * @public + */ +Assert.supports = (function detect() { + var supports = {}; + + try { + eval('(function*(){})()'); + supports.generators = true; + } catch (e) { + supports.generators = false; + } + + try { + eval('%GetV8Version()'); + supports.native = true; + } catch (e) { + supports.native = false; + } + + return supports; +}(/* Douglas Crockford wants the dog balls inside youtu.be/taaEzHI9xyY#t=2020s */)); + +/** + * Assign values to a given thing. + * + * @param {Mixed} where Where do the new properties need to be assigned on. + * @returns {Function} + * @api public + */ +Assert.assign = function assign(where) { + return function assigns(aliases, value) { + if ('string' === typeof aliases) { + if (~aliases.indexOf(',')) aliases = aliases.split(/[\s|\,]+/); + else aliases = [aliases]; + } + + for (var i = 0, length = aliases.length; i < length; i++) { + where[aliases[i]] = value || where; + } + + return where; + }; +}; + +/** + * Add aliases to the given constructed asserts. This allows us to chain + * assertion calls together. + * + * @param {Mixed} value Value that we need to assert. + * @param {Assert} assert The constructed assert instance. + * @returns {Assert} The given assert instance. + * @api private + */ +Assert.alias = function alias(value, assert) { + var assign = Assert.assign(assert) + , flags, flag, prop; + + for (prop in Assert.flags) { + if (!hasOwn.call(Assert.flags, prop)) continue; + + if (!assert[prop]) { + flags = {}; + + for (flag in Assert.flags) { + if (!hasOwn.call(Assert.flags, flag)) continue; + flags[flag] = assert[flag]; + } + + // + // Add some default values to the flags. + // + flags.stacktrace = assert.stacktrace; + flags.diff = assert.diff; + flags[prop] = true; + + assign(Assert.flags[prop], new Assert(value, flags)); + } else assign(Assert.flags); + } + + return assert; +}; + +/** + * API sugar of adding aliased prototypes to the Assert. This makes the code + * a bit more workable and human readable. + * + * @param {String|Array} aliases List of methods. + * @param {Function} fn Actual assertion function. + * @returns {Assert} + * @api public + */ +Assert.add = Assert.assign(Assert.prototype); + +/** + * Asserts if the given value is the correct type. We need to use + * Object.toString here because there are some implementation bugs the `typeof` + * operator: + * + * - Chrome <= 9: /Regular Expressions/ are evaluated to `function` + * + * As well as all common flaws like Arrays being seen as Objects etc. This + * eliminates all these edge cases. + * + * @param {String} of Type of class it should equal + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('a, an', function typecheck(of, msg) { + of = of.toString().toLowerCase(); + + var value = type(this.value) + , expect = format('`%j` (%s) to @ be a %s', this.value, value, of); + + return this.test(value === of, msg, expect); +}); + +/** + * Asserts if the given value is the correct type from a list of types. + * The same caveats regarding `typeof` apply as described in `a`, `an`. + * + * @param {String[]} ofs Acceptable types to check against + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('eitherOfType, oneOfType', function multitypecheck(ofs, msg) { + var value = type(this.value) + , expect = format('`%j` (%s) to @ be a %s', this.value, value, ofs.join(' or a ')); + + var test = false; + for (var i = 0; i < ofs.length; i++) { + if (ofs[i].toString().toLowerCase() === value) { + test = true; + break; + } + } + + return this.test(test, msg, expect); +}); + +/** + * Asserts that the value is instanceof the given constructor. + * + * @param {Function} constructor Constructur the value should inherit from. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('instanceOf, instanceof, inherits, inherit', function of(constructor, msg) { + var expect = format('%f to @ be an instanceof %f', this.value, constructor); + + return this.test(this.value instanceof constructor, msg, expect); +}); + +/** + * Assert that the value includes the given value. + * + * @param {Mixed} val Value to match. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('include, includes, contain, contains', function contain(val, msg) { + var includes = false + , of = type(this.value) + , expect = format('`%j` to @ include %j', this.value, val); + + switch (of) { + case 'array': + for (var i = 0, length = this.value.length; i < length; i++) { + if (this._deep ? deep(this.value[i], val) : this.value[i] === val) { + includes = true; + break; + } + } + break; + + case 'object': + if (val in this.value) { + includes = true; + } + break; + + case 'string': + if (~this.value.indexOf(val)) { + includes = true; + } + break; + } + + return this.test(includes === true, msg, expect); +}); + +/** + * Assert that the value is truthy. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('ok, okay, truthy, truly', function ok(msg) { + var expect = format('`%j` to @ be truthy', this.value); + + return this.test(Boolean(this.value), msg, expect); +}); + +/** + * Assert that the value is falsey. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('falsely, falsey, falsy', function nope(msg) { + var expect = format('`%j` to @ be falsely', this.value); + + return this.test(Boolean(this.value) === false, msg, expect); +}); + +/** + * Assert that the value is `true`. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('true', function ok(msg) { + var expect = format('`%j` to @ equal (===) true', this.value); + + return this.test(this.value === true, msg, expect); +}); + +/** + * Assert that the value is `true`. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('false', function nope(msg) { + var expect = format('`%j` to @ equal (===) false', this.value); + + return this.test(this.value === false, msg, expect); +}); + +/** + * Assert that the value exists. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('exists, exist', function exists(msg) { + var expect = format('`%j` to @ exist', this.value); + + return this.test(this.value != null, msg, expect); +}); + +/** + * Asserts that the value's length is the given value. + * + * @param {Number} value Size of the value. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('length, lengthOf, size', function length(value, msg) { + var actualValue = size(this.value); + var expect = format('`%j` to @ have a length of %d, found %d', this.value, value, actualValue); + + return this.test(actualValue === +value, msg, expect); +}); + +/** + * Asserts that the value's length is 0 or doesn't contain any enumerable keys. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('empty', function empty(msg) { + var expect = format('`%j` to @ be empty', this.value); + + return this.test(size(this.value) === 0, msg, expect); +}); + +/** + * Assert that the value is greater than the specified value. + * + * @param {Number} value The greater than value. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('above, gt, greater, greaterThan', function above(value, msg) { + var amount = type(this.value) !== 'number' ? size(this.value) : this.value + , expect = format('%d to @ be greater than %d', amount, value); + + return this.test(amount > value, msg, expect); +}); + +/** + * Assert that the value is equal or greater than the specified value. + * + * @param {Number} value The specified value. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('least, gte, atleast', function least(value, msg) { + var amount = type(this.value) !== 'number' ? size(this.value) : this.value + , expect = format('%d to @ be greater or equal to %d', amount, value); + + return this.test(amount >= value, msg, expect); +}); + +/** + * Assert that the value starts with the given value. + * + * @param {String|Array} value String it should start with. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('start, starts, startsWith, startWith', function start(value, msg) { + var expect = format('`%j` to @ start with %j', this.value, value); + + return this.test(0 === this.value.indexOf(value), msg, expect); +}); + +/** + * Assert that the value ends with the given value. + * + * @param {String} value String it should start with. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('end, ends, endsWith, endWith', function end(value, msg) { + var index = this.value.indexOf(value, this.value.length - value.length) + , expect = format('`%j` to @ end with %j', this.value, value); + + return this.test(index >= 0, msg, expect); +}); + +/** + * Assert a floating point number is near the give value within the delta + * margin. + * + * @param {Number} value The specified value. + * @param {Number} delta Radius. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('closeTo, close, approximately, near', function close(value, delta, msg) { + var expect = format('`%j` to @ be close to %d ± %d', this.value, value, delta); + + return this.test(Math.abs(this.value - value) <= delta, msg, expect); +}); + +/** + * Assert that the value is below the specified value. + * + * @param {Number} value The specified value. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('below, lt, less, lessThan', function below(value, msg) { + var amount = type(this.value) !== 'number' ? size(this.value) : this.value + , expect = format('%d to @ be less than %d', amount, value); + + return this.test(amount < value, msg, expect); +}); + +/** + * Assert that the value is below or equal to the specified value. + * + * @param {Number} value The specified value. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('most, lte, atmost', function most(value, msg) { + var amount = type(this.value) !== 'number' ? size(this.value) : this.value + , expect = format('%d to @ be less or equal to %d', amount, value); + + return this.test(amount <= value, msg, expect); +}); + +/** + * Assert that that value is within the given range. + * + * @param {Number} start Lower bound. + * @param {Number} finish Upper bound. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('within, between', function within(start, finish, msg) { + var amount = type(this.value) !== 'number' ? size(this.value) : this.value + , expect = format('%d to @ be greater or equal to %d and @ be less or equal to %d', amount, start, finish); + + return this.test(amount >= start && amount <= finish, msg, expect); +}); + +/** + * Assert that the value has an own property with the given prop. + * + * @param {String} prop Property name. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('hasOwn, own, ownProperty, haveOwnProperty, property, owns, hasown', function has(prop, value, msg) { + var expect = format('`%j` @ to have own property %s', this.value, prop) + , tested = this.test(hasOwn.call(this.value, prop), msg, expect); + + return arguments.length > 1 + ? this.clone(this.value[prop]).equals(value) + : tested; +}); + +/** + * Asserts that the value matches a regular expression. + * + * @param {RegExp} regex Regular expression to match against. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('match, matches', function test(regex, msg) { + if ('string' === typeof regex) regex = new RegExp(regex); + + var expect = format('`%j` to @ match %j', this.value, regex); + + return this.test(!!regex.test(this.value), msg, expect); +}); + +/** + * Assert that the value equals a given thing. + * + * @param {Mixed} thing Thing it should equal. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('equal, equals, eq, eqs, exactly', function equal(thing, msg) { + var expect = format('`%j` to @ equal (===) `%j`', this.value, thing); + + if (!this._deep) return this.test(this.value === thing, msg, expect); + + this.sliceStack++; + return this.eql(thing, msg); +}); + +/** + * Assert that the value **deeply** equals a given thing. + * + * @param {Mixed} thing Thing it should equal. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('eql, eqls', function eqls(thing, msg) { + var expect = format('`%j` to deeply equal `%j`', this.value, thing); + + return this.test(deep(this.value, thing), msg, expect); +}); + +/** + * Assert that the value is either one of the given values. + * + * @param {Array} arrgs All the values it can match. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('either', function either(args, msg) { + var expect = '`%j` to equal either `%j` ' + , i = args.length + , result = false + , values = []; + + while (i-- || result) { + if (!this._deep) result = this.value === args[i]; + else result = deep(this.value, args[i]); + if (result) break; + + values.push(args[i]); + } + + expect = format.apply(null, [expect + (new Array(values)).join('or `%j` ')].concat(values)); + return this.test(result, msg, expect); +}); + +/** + * Assert if the given function throws. + * + * @param {Mixed} thing Thing it should equal. + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('throw, throws, fails, fail', function throws(thing, msg) { + try { this.value(); } + catch (e) { + var message = 'object' === typeof e ? e.message : e; + + switch (type(thing)) { + case 'string': return this.clone(message).includes(thing, msg); + case 'regexp': return this.clone(message).matches(thing, msg); + case 'function': return this.clone(e).instanceOf(thing, msg); + case 'undefined': return this.test(true, msg, format('%f to @ throw', this.value)); + default: return this.clone(e).equals(thing); + } + } + + return this.test(false, msg, format('%f to @ throw', this.value)); +}); + +/** + * Assert if the given value is finite. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('isFinite, finite, finiteness', function finite(msg) { + var expect = format('`%j`s @ a is a finite number', this.value) + , result; + + if (this._deep) { + result = Number.isFinite + ? Number.isFinite(this.value) + : 'number' === type(this.value) && isFinite(this.value); + } else { + result = isFinite(this.value); + } + + return this.test(result, msg, expect); +}); + +/** + * Assert if the given function is an ES6 generator. + * + * @param {String} msg Reason of failure. + * @returns {Assert} + * @api public + */ +Assert.add('generator', function generators(msg) { + var expect = format('%f to @ be a generator', this.value) + , result; + + // + // Non standard function from Mozilla allows us to check if a function is + // a generator. + // + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/isGenerator + // + if ('function' === typeof this.value.isGenerator) { + result = this.value.isGenerator(); + } else if ('generatorfunction' === type(this.value)) { + result = true; + } else { + result = 'function' === type(this.value) && this.value.toString().indexOf('function*') === 0; + } + + return this.test(result, msg, expect); +}); + +// +// The following assertions require's v8's allow-natives-syntax flag to be +// enabled as this allows us to hook in to the more internal parts of the +// engine. The native syntax is wrapped in a try catch with a new Function +// construction so the rest of the code will execute when JavaScript engines do +// not understand the instructions. +// +(function v8() { + var states = 'void,yes,no,always,never,void,maybe'.split(',') + , detect; + + if (!Assert.supports.native) detect = function optimized() { return 0; }; + else detect = new Function('fn', 'args', 'selfie', [ + 'fn.apply(selfie, args);', + '%OptimizeFunctionOnNextCall(fn);', + 'fn.apply(selfie, args);', + 'return %GetOptimizationStatus(fn);' + ].join('\n')); + + /** + * Assert that a given function has reached a certain optimization level. + * + * @param {String} level Optimization level + * @param {Array} args Arguments for the function + * @param {Mixed} selfie This context for the function + * @param {String} msg Reason of failure + * @returns {Assert} + * @api public + */ + Assert.add('optimisation, optimization', function optimization(level, args, selfie, msg) { + var expect = format('%f to be optimized as %s', this.value, level) + , status = states[detect(this.value, args, selfie)]; + + return this.test(status === level, msg, expect); + }); + + /** + * Assert that the function is optimized. + * + * @param {String} msg Reason of failure + * @returns {Assert} + * @api public + */ + Assert.add('optimized, optimised', function optimized(msg) { + var expect = format('%f to be optimized', this.value) + , status = states[detect(this.value, [])]; + + return this.test(status === 'yes', msg, expect); + }); +}()); + +/** + * Create a clone of the current assertion instance which has the same + * configuration but a different value. + * + * @param {Mixed} value The new value + * @returns {Assert} + * @api public + */ +Assert.add('clone', function clone(value) { + var configuration = { + stacktrace: this.stacktrace, + slice: this.sliceStack + 1, + diff: this.diff + }; + + for (var alias in Assert.flags) { + if (!hasOwn.call(Assert.flags, alias)) continue; + configuration[alias] = this[alias]; + } + + return new Assert(arguments.length ? value : this.value, configuration); +}); + +/** + * Validate the assertion. + * + * @param {Boolean} passed Didn't the test pass or fail. + * @param {String} msg Custom message provided by users. + * @param {Function} expectation Compiled expectation template + * @param {Number} slice The amount of stack traces we need to remove. + * @returns {Assert} + * @api public + */ +Assert.add('test', function test(passed, msg, expectation, slice) { + called++; // Needed for tracking the amount of executed assertions. + + if (this._not) passed = !passed; + if (passed) return this; + + msg = msg || 'Unknown assertation failure occured'; + slice = slice || this.sliceStack; + + if (expectation) msg += ', assumed ' + expectation(this._not); + + var failure = new Error(msg) + , err = { message: failure.message, stack: '' }; + + if (this.stacktrace) { + err.stack = failure.stack || err.stack; + } + + // + // Pre-scrub, it's possible that the error message is a multi line error + // message and that really messes up the slicing of the call stack, to prevent + // this from happening, we're just going to replace the error message that is + // on the stack with a single line as we use the `err.message` instead of the + // message that is in the stack anyways. + // + err.stack = err.stack.replace(err.message, 'assume-replaced-the-err-message'); + + // + // Clean up the stack by slicing off the parts that are pointless to most + // people. (Like where it enters this assertion library). + // + err.stack = err.stack.split('\n').slice(slice).join('\n') || err.stack; + err.stack = pruddy(err); + + if ('function' !== typeof Object.create) { + if ('object' === typeof console && 'function' === typeof console.error) { + console.error(err.stack); + } + + throw failure; + } + + failure = Object.create(Error.prototype); + failure.message = err.message; + failure.stack = err.stack; + + throw failure; +}); + +/** + * Plan for the amount of assertions that needed to run. This is great way to + * figure out if you have edge cases in your code which prevented an assertion or + * callback from running. + * + * ```js + * it('run a lot of assertions', function (next) { + * next = assume.plan(10, next); + * }); + * ``` + * + * @param {Number} tests The amount of assertions you expect to run. + * @param {Function} fn Optional completion callback which receives the error. + * @returns {Function} Completion callback. + * @api public + */ +Assert.plan = function plan(tests, fn) { + fn = fn || function next(err) { + if (err) throw err; + }; + + var atm = called; + + return function validate(err) { + var ran = called - atm + , msg; + + if (err) return fn(err); + if (tests === ran) return fn(); + + msg = [ + 'We ran', + ran - tests, + ran > tests ? 'more' : 'less', + 'assertations than the expected', + tests + ]; + + fn(new Error(msg.join(' '))); + }; +}; + +/** + * Wait until the returned callback is called x times before advancing. This + * makes it a bit easier to write async tests that require multiple callbacks. + * + * ```js + * it('does async things', function (next) { + * next = assume.wait(2, 4, next); + * + * asynctask(function (err, data) { + * assume(err).is.a('undefined'); + * assume(data).equals('testing'); + * + * next(); + * }); + * + * asynctaskfail(function (err, data) { + * assume(err).is.a('undefined'); + * assume(data).equals('testing'); + * + * next(); + * }); + * }); + * ``` + * + * @param {Number} calls The amount of calls the returned callback should called. + * @param {Number} tests The amount of tests that should be completed before cb. + * @param {Function} fn Completion callback. + * @returns {Function} New function that does the counting. + * @api public + */ +Assert.wait = function wait(calls, tests, fn) { + // + // Make the `tests` argument optional by allowing callback to be used there. + // + if ('function' === typeof tests) { + fn = tests; + tests = 0; + } + + // + // If `tests` are specified, pass it directly in to the Assert.plan function + // so we can use that as given callback. + // + if (tests) fn = Assert.plan(tests, fn); + + var ignore = false; + + return function counter(err) { + if (ignore) return; + if (err || !--calls) return ignore = true, fn(err); + }; +}; + +/** + * Load/execute a new plugin. + * + * @param {Function} plugin Plugin to be executed. + * @returns {Function} Assert, for chaining purposes. + * @api public + */ +Assert.use = function use(plugin) { + plugin(this, { + name: displayName, // Extract the name of a function. + string: stringify, // Transform thing to a string. + get: pathval.get, // Get a value from an object. + format: format, // Format an expectation message. + nodejs: nodejs, // Are we running on Node.js. + deep: deep, // Deep assertion. + type: type, // Get class information. + size: size, // Get the size of an object. + each: each // Iterate over arrays. + }); + + return Assert; +}; + +// +// Create type checks for all build-in JavaScript classes. +// +each(('new String§new Number§new Array§new Date§new Error§new RegExp§new Boolean§' + + 'new Float32Array§new Float64Array§new Int16Array§new Int32Array§new Int8Array§' + + 'new Uint16Array§new Uint32Array§new Uint8Array§new Uint8ClampedArray§' + + 'new ParallelArray§new Map§new Set§new WeakMap§new WeakSet§new TypedArray(1)§' + + 'new DataView(new ArrayBuffer(1))§new ArrayBuffer(1)§new Promise(function(){})§' + + 'new Blob§arguments§null§undefined§new Buffer(1)§NaN§navigator§location§' + + 'new Function§new Proxy({}, function(){})§Symbol("assume")§Math' +).split('§'), function iterate(code) { + var name, arg; + + // + // Not all of these constructors are supported in the browser, we're going to + // compile dedicated functions that returns a new instance of the given + // constructor. If it's not supported the code will throw and we will simply + // return. + // + try { arg = (new Function('return '+ code))(); } + catch (e) { return; } + + name = type(arg); + + Assert.add(name, function typecheck(msg) { + var expect = format('`%j` to @ be an %s', this.value, name) + , of = type(this.value); + + return this.test(of === name, msg, expect, 3); + }); +}); + +// +// Introduce an alternate API: +// +// ```js +// var i = require('assume'); +// +// i.assume.that('foo').equals('bar'); +// i.sincerely.hope.that('foo').equals('bar'); +// i.expect.that('foo').equals('bar'); +// ``` +// +Assert.hope = { that: Assert }; +Assert.assign(Assert)('sincerely, expect'); +Assert.assign(Assert)('assume, expect', Assert.hope); + +// +// Expose the module. +// +module.exports = Assert; diff --git a/debian/tests/test-modules/assume/package.json b/debian/tests/test-modules/assume/package.json new file mode 100644 index 0000000..67d6048 --- /dev/null +++ b/debian/tests/test-modules/assume/package.json @@ -0,0 +1,96 @@ +{ + "_from": "assume@~1.5.0", + "_id": "assume@1.5.2", + "_inBundle": false, + "_integrity": "sha512-/IDWcpPTGjUsf4lcMi837n3xFxkEBVEfVxOvYUgdU3y6FjWSWzXiUzFAYlulr94kr79mNbiOFC5isJmaQn2C2w==", + "_location": "/assume", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "assume@~1.5.0", + "name": "assume", + "escapedName": "assume", + "rawSpec": "~1.5.0", + "saveSpec": null, + "fetchSpec": "~1.5.0" + }, + "_requiredBy": [ + "#DEV:/" + ], + "_resolved": "https://registry.npmjs.org/assume/-/assume-1.5.2.tgz", + "_shasum": "057c5a2f33ce7d1ccd8d783db2d5d098cacdd111", + "_spec": "assume@~1.5.0", + "_where": "/home/xavier/dev/debian/packages/node-url-parse", + "author": { + "name": "Arnout Kazemier" + }, + "bugs": { + "url": "https://github.com/bigpipe/assume/issues" + }, + "bundleDependencies": false, + "dependencies": { + "deep-eql": "0.1.x", + "fn.name": "1.0.x", + "object-inspect": "1.0.x", + "pathval": "0.1.x", + "pruddy-error": "1.0.x" + }, + "deprecated": false, + "description": "Expect-like assertions that works seamlessly in node and browsers", + "devDependencies": { + "browserify": "9.0.x", + "istanbul": "0.3.x", + "mocha": "2.2.x", + "mocha-phantomjs": "3.5.x", + "phantomjs": "1.9.x", + "pre-commit": "1.0.x" + }, + "homepage": "https://github.com/bigpipe/assume#readme", + "keywords": [ + "assert", + "assertion", + "asserts", + "assume", + "bdd", + "expect", + "expect.js", + "should", + "shouldjs", + "spec", + "tdd", + "test", + "testing", + "tests", + "unit testing", + "unit" + ], + "license": "MIT", + "main": "index.js", + "name": "assume", + "repository": { + "type": "git", + "url": "git://github.com/bigpipe/assume.git" + }, + "scripts": { + "browserify-tests": "browserify test/test.js -o test/phantom.js --debug", + "coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter spec --ui bdd test/test.js", + "iojs": "iojs --allow-natives-syntax --harmony ./node_modules/mocha/bin/_mocha test/test.js", + "node": "node --allow-natives-syntax --harmony ./node_modules/mocha/bin/_mocha test/test.js", + "phantom": "mocha-phantomjs test/phantom.html", + "prepublish": "mkdir -p dist && browserify index.js -o dist/assume.js --standalone assume", + "test": "npm run-script browserify-tests && npm run-script phantom", + "test-travis": "npm run node && istanbul cover node_modules/.bin/_mocha --report lcovonly -- --reporter spec --ui bdd test/test.js", + "watch": "mocha --watch --reporter spec --ui bdd test/test.js" + }, + "testling": { + "harness": "mocha-bdd", + "files": "test/test.js", + "browsers": [ + "ie/6..latest", + "chrome/latest", + "firefox/latest" + ] + }, + "version": "1.5.2" +} diff --git a/debian/tests/test-modules/fn.name/.npmignore b/debian/tests/test-modules/fn.name/.npmignore new file mode 100644 index 0000000..3d25d4e --- /dev/null +++ b/debian/tests/test-modules/fn.name/.npmignore @@ -0,0 +1,3 @@ +.tern-port +coverage +node_modules diff --git a/debian/tests/test-modules/fn.name/.travis.yml b/debian/tests/test-modules/fn.name/.travis.yml new file mode 100644 index 0000000..b532c0c --- /dev/null +++ b/debian/tests/test-modules/fn.name/.travis.yml @@ -0,0 +1,11 @@ +language: node_js +node_js: + - "0.8" + - "0.10" + - "0.11" +before_install: + - "npm install -g npm@1.4.x" +script: + - "npm run test-travis" +after_script: + - "npm install coveralls@2.11.x && cat coverage/lcov.info | coveralls" diff --git a/debian/tests/test-modules/fn.name/README.md b/debian/tests/test-modules/fn.name/README.md new file mode 100644 index 0000000..6ad12e5 --- /dev/null +++ b/debian/tests/test-modules/fn.name/README.md @@ -0,0 +1,43 @@ +# fn.name + +[![From bigpipe.io][from]](http://bigpipe.io)[![Version npm][version]](http://browsenpm.org/package/fn.name)[![Build Status][build]](https://travis-ci.org/bigpipe/fn.name)[![Dependencies][david]](https://david-dm.org/bigpipe/fn.name)[![Coverage Status][cover]](https://coveralls.io/r/bigpipe/fn.name?branch=master) + +[from]: https://img.shields.io/badge/from-bigpipe.io-9d8dff.svg?style=flat-square +[version]: http://img.shields.io/npm/v/fn.name.svg?style=flat-square +[build]: http://img.shields.io/travis/bigpipe/fn.name/master.svg?style=flat-square +[david]: https://img.shields.io/david/bigpipe/fn.name.svg?style=flat-square +[cover]: http://img.shields.io/coveralls/bigpipe/fn.name/master.svg?style=flat-square + +Extract the name of a given function. Nothing more than that. + +## Installation + +This module is compatible with Browserify and Node.js and can be installed +using: + +``` +npm install --save fn.name +``` + +## Usage + +Using this module is super simple, it exposes the function directly on the +exports so it can be required as followed: + +```js +'use strict'; + +var name = require('fn.name'); +``` + +Now that we have the `name` function we can pass it functions: + +```js +console.log(name(function foo() {})) // foo +``` + +And that's it folks! + +## License + +MIT diff --git a/debian/tests/test-modules/fn.name/index.js b/debian/tests/test-modules/fn.name/index.js new file mode 100644 index 0000000..4078bb0 --- /dev/null +++ b/debian/tests/test-modules/fn.name/index.js @@ -0,0 +1,42 @@ +'use strict'; + +var toString = Object.prototype.toString; + +/** + * Extract names from functions. + * + * @param {Function} fn The function who's name we need to extract. + * @returns {String} + * @api public + */ +module.exports = function name(fn) { + if ('string' === typeof fn.displayName && fn.constructor.name) { + return fn.displayName; + } else if ('string' === typeof fn.name && fn.name) { + return fn.name; + } + + // + // Check to see if the constructor has a name. + // + if ( + 'object' === typeof fn + && fn.constructor + && 'string' === typeof fn.constructor.name + ) return fn.constructor.name; + + // + // toString the given function and attempt to parse it out of it, or determine + // the class. + // + var named = fn.toString() + , type = toString.call(fn).slice(8, -1); + + if ('Function' === type) { + named = named.substring(named.indexOf('(') + 1, named.indexOf(')')); + } else { + named = type; + } + + return named || 'anonymous'; +}; diff --git a/debian/tests/test-modules/fn.name/package.json b/debian/tests/test-modules/fn.name/package.json new file mode 100644 index 0000000..a0c5a5e --- /dev/null +++ b/debian/tests/test-modules/fn.name/package.json @@ -0,0 +1,64 @@ +{ + "_from": "fn.name@1.0.x", + "_id": "fn.name@1.0.1", + "_inBundle": false, + "_integrity": "sha1-gBWtFJwQEaEWzbieukzBHZA5rdg=", + "_location": "/fn.name", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "fn.name@1.0.x", + "name": "fn.name", + "escapedName": "fn.name", + "rawSpec": "1.0.x", + "saveSpec": null, + "fetchSpec": "1.0.x" + }, + "_requiredBy": [ + "/assume" + ], + "_resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.0.1.tgz", + "_shasum": "8015ad149c1011a116cdb89eba4cc11d9039add8", + "_spec": "fn.name@1.0.x", + "_where": "/home/xavier/dev/debian/packages/node-url-parse/node_modules/assume", + "author": { + "name": "Arnout Kazemier" + }, + "bugs": { + "url": "https://github.com/bigpipe/fn.name/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Extract names from functions", + "devDependencies": { + "assume": "0.0.x", + "istanbul": "0.3.x", + "mocha": "2.1.x", + "pre-commit": "0.0.x" + }, + "homepage": "https://github.com/bigpipe/fn.name", + "keywords": [ + "fn.name", + "function.name", + "name", + "function", + "extract", + "parse", + "names" + ], + "license": "MIT", + "main": "index.js", + "name": "fn.name", + "repository": { + "type": "git", + "url": "git+https://github.com/bigpipe/fn.name.git" + }, + "scripts": { + "coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter spec --ui bdd test.js", + "test": "mocha --reporter spec --ui bdd test.js", + "test-travis": "istanbul cover node_modules/.bin/_mocha --report lcovonly -- --reporter spec --ui bdd test.js", + "watch": "mocha --watch --reporter spec --ui bdd test.js" + }, + "version": "1.0.1" +} diff --git a/debian/tests/test-modules/pruddy-error/LICENSE b/debian/tests/test-modules/pruddy-error/LICENSE new file mode 100644 index 0000000..cb86233 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 1998, Regents of the University of California +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the University of California, Berkeley nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/tests/test-modules/pruddy-error/README.md b/debian/tests/test-modules/pruddy-error/README.md new file mode 100644 index 0000000..5273505 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/README.md @@ -0,0 +1,31 @@ +``` +This is a clone of the `prettify-error` module which was unpublished by the +author. All dependencies have been inlined to prevent future conflicts. +``` + +## pruddy-error + +Prettify given error objects for console outputs + + + +## Install + +``bash +$ npm install pruddy-error +`` + +## Usage + +```js +var pruddy = require('pruddy-error'); +var error = new Error('lorem ipsum'); + +console.error(pruddy(error) || error); +``` + +If you'd like to skip some lines from the stack: + +```js +pruddy(error, 2) // Will start reading the stack from the third line. +``` diff --git a/debian/tests/test-modules/pruddy-error/ansi-codes.json b/debian/tests/test-modules/pruddy-error/ansi-codes.json new file mode 100644 index 0000000..9ba5377 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/ansi-codes.json @@ -0,0 +1,47 @@ +{ + "reset": "\u001b[0m", + "bold": "\u001b[1m", + "italic": "\u001b[3m", + "blink": "\u001b[5m", + "underline": "\u001b[4m", + "underlineOff": "\u001b[24m", + "inverse": "\u001b[7m", + "inverseOff": "\u001b[27m", + "strikethrough": "\u001b[9m", + "strikethroughOff": "\u001b[29m", + "def": "\u001b[39m", + "white": "\u001b[37m", + "black": "\u001b[30m", + "grey": "\u001b[90m", + "red": "\u001b[31m", + "green": "\u001b[32m", + "blue": "\u001b[34m", + "yellow": "\u001b[33m", + "magenta": "\u001b[35m", + "cyan": "\u001b[36m", + "defBg": "\u001b[49m", + "whiteBg": "\u001b[47m", + "blackBg": "\u001b[40m", + "redBg": "\u001b[41m", + "greenBg": "\u001b[42m", + "blueBg": "\u001b[44m", + "yellowBg": "\u001b[43m", + "magentaBg": "\u001b[45m", + "cyanBg": "\u001b[46m", + "brightBlack": "\u001b[90m", + "brightRed": "\u001b[91m", + "brightGreen": "\u001b[92m", + "brightYellow": "\u001b[93m", + "brightBlue": "\u001b[94m", + "brightMagenta": "\u001b[95m", + "brightCyan": "\u001b[96m", + "brightWhite": "\u001b[97m", + "brightBlackBg": "\u001b[100m", + "brightRedBg": "\u001b[101m", + "brightGreenBg": "\u001b[102m", + "brightYellowBg": "\u001b[103m", + "brightBlueBg": "\u001b[104m", + "brightMagentaBg": "\u001b[105m", + "brightCyanBg": "\u001b[106m", + "brightWhiteBg": "\u001b[107m" +} diff --git a/debian/tests/test-modules/pruddy-error/example.js b/debian/tests/test-modules/pruddy-error/example.js new file mode 100644 index 0000000..5371c53 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/example.js @@ -0,0 +1,4 @@ +var pruddy = require('./'); +var err = new Error('lorem ipsum'); + +console.error(pruddy(err) || err); diff --git a/debian/tests/test-modules/pruddy-error/failing-code.js b/debian/tests/test-modules/pruddy-error/failing-code.js new file mode 100644 index 0000000..3d6da4e --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/failing-code.js @@ -0,0 +1,52 @@ +var isNode = !!(typeof process != 'undefined' && process.versions && process.versions.node); +var failingLine = require('./failing-line'); + +var fs; +var nodeRequire; + +if (isNode) { + nodeRequire = require; + fs = nodeRequire('fs'); + nodeRequire = null; +} + +module.exports = function failingCode (error, doc, shift) { + var ln = failingLine(error, shift); + + if (!ln) return; + + if (!doc && fs) { + try { + doc = fs.readFileSync(ln.filename).toString(); + } catch (readError) { + return undefined; + } + } + + if (!doc) return undefined; + + var result = []; + var lines = doc.split('\n'); + + var i = ln.line - 3; + while (++i < ln.line + 1) { + if (i + 1 != ln.line) { + result.push({ + line: ln.line - (ln.line - i -1), + code: lines[i] + }); + continue; + } + + result.push({ + line: ln.line, + col: ln.col, + fn: ln.fn, + filename: ln.filename, + code: lines[i], + failed: true + }); + } + + return result; +}; diff --git a/debian/tests/test-modules/pruddy-error/failing-line.js b/debian/tests/test-modules/pruddy-error/failing-line.js new file mode 100644 index 0000000..56a1707 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/failing-line.js @@ -0,0 +1,91 @@ +module.exports = detect; + +function detect (error, shift) { + if (!error || !error.stack) return; + + if (/ at /.test(error.stack)) return v8(error, shift); + + if (/:\d+:\d+$/.test(error.stack)) return safari(error, shift); + + return firefox(error, shift); +} + +function safari (error, shift) { + var index = 0; + if (shift) index += shift; + + var fn, filename, line, col; + var lines = error.stack.split('\n'); + var stack = lines[index] || lines[0]; + + var fields = stack.split(/\:(\d+)\:(\d+)$/); + var numbers = fields.slice(1, 3); + fields = fields[0].split('@'); + + return { + fn: fields[0], + filename: fields[1], + line: Number(numbers[0]), + col: Number(numbers[1]) + }; +} + +function v8 (error, shift) { + if (!error || !error.stack) return; + + var index = 1; + if (shift) index += shift; + + var fn, filename, line, col; + var lines = error.stack.split('\n'); + var stack = lines[index] || lines[1]; + + if (!stack) return; + + var match = stack.match(/at ([\(\)\w\.<>\[\]\s]+) \((.+):(\d+):(\d+)/); + + if (!match) { + match = stack.match(/at (.+):(\d+):(\d+)/); + if (!match) return undefined; + + filename = match[1]; + line = Number(match[2]); + col = Number(match[3]); + } else { + fn = match[1]; + filename = match[2]; + line = Number(match[3]); + col = Number(match[4]); + } + + return { + fn: fn, + filename: filename, + line: line, + col: col + }; +} + +function firefox (error, shift) { + var index = 0; + if (shift) index += shift; + + var fn, filename, line, col; + var lines = error.stack.split('\n'); + var stack = lines[index] || lines[0]; + + var fields = stack.split(/\:(\d+)$/); + var numbers = fields.slice(1, 2); + fields = fields[0].split('@'); + + if (index == 0) { + col = error.columnNumber; + } + + return { + fn: fields[0], + filename: fields[1], + line: Number(numbers[0]), + col: col + }; +} diff --git a/debian/tests/test-modules/pruddy-error/format-text.js b/debian/tests/test-modules/pruddy-error/format-text.js new file mode 100644 index 0000000..2116910 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/format-text.js @@ -0,0 +1,31 @@ +module.exports = format; + +function format(text) { + var context; + + if (typeof arguments[1] == 'object' && arguments[1]) { + context = arguments[1]; + } else { + context = Array.prototype.slice.call(arguments, 1); + } + + return String(text).replace(/\{?\{([^{}]+)}}?/g, replace(context)); +}; + +function replace (context, nil){ + return function (tag, name) { + if (tag.substring(0, 2) == '{{' && tag.substring(tag.length - 2) == '}}') { + return '{' + name + '}'; + } + + if (!context.hasOwnProperty(name)) { + return tag; + } + + if (typeof context[name] == 'function') { + return context[name](); + } + + return context[name]; + } +} diff --git a/debian/tests/test-modules/pruddy-error/index.js b/debian/tests/test-modules/pruddy-error/index.js new file mode 100644 index 0000000..5a13d18 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/index.js @@ -0,0 +1,61 @@ +var failingCode = require('./failing-code'); +var format = require('./format-text'); +var leftpad = require('./left-pad'); +var style = require('./style-format'); + +var template = style('{bold}{red}{title} {grey}{filename}{reset}\n' + + ' {red}{v}\n' + + ' {grey}{previousLineNo}. {previousLine}\n' + + ' {reset}{failingLineNo}. {failingLine}\n' + + ' {grey}{nextLineNo}. {nextLine}\n' + + ' {red}{^}{reset}\n' + + ' {stack}\n' + + '{reset}'); + + +module.exports = function prettifyError (error, shift, code) { + if (!error || !error.stack) return; + + code || (code = failingCode(error, undefined, shift)); + + if (!code) return; + + var previousLineNo = String(code[0].line); + var failingLineNo = String(code[1].line); + var nextLineNo = String(code[2].line); + var linumlen = Math.max(previousLineNo.length, + failingLineNo.length, + nextLineNo.length); + + return format(template, { + title: error.message, + filename: code[1].filename, + previousLine: code[0].code, + previousLineNo: leftpad(previousLineNo, linumlen), + previousColNo: code[0].col, + failingLine: code[1].code, + failingLineNo: leftpad(failingLineNo, linumlen), + failingColNo: code[1].col, + nextLine: code[2].code, + nextLineNo: leftpad(nextLineNo, linumlen), + nextColNo: code[2].col, + stack: tabStack(error.stack), + '^': showColumn(code, linumlen - failingLineNo.length, '^'), + 'v': showColumn(code, linumlen - failingLineNo.length, 'v') + }); +} + +function showColumn (code, tabn, ch) { + var result = ''; + var i = String(code[1].line).length + code[1].col + 1 + tabn; + + while (i--) { + result += ' '; + } + + return result + ch; +} + +function tabStack (stack) { + return stack.replace(/\n/g, '\n '); +} diff --git a/debian/tests/test-modules/pruddy-error/left-pad.js b/debian/tests/test-modules/pruddy-error/left-pad.js new file mode 100644 index 0000000..3905bc5 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/left-pad.js @@ -0,0 +1,17 @@ +module.exports = leftpad; + +function leftpad (str, len, ch) { + str = String(str); + + var i = -1; + + if (!ch && ch !== 0) ch = ' '; + + len = len - str.length; + + while (++i < len) { + str = ch + str; + } + + return str; +} diff --git a/debian/tests/test-modules/pruddy-error/package.json b/debian/tests/test-modules/pruddy-error/package.json new file mode 100644 index 0000000..4a85113 --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/package.json @@ -0,0 +1,51 @@ +{ + "_from": "pruddy-error@1.0.x", + "_id": "pruddy-error@1.0.2", + "_inBundle": false, + "_integrity": "sha1-s37Bo4v5EHwM3FvGY9PU6ANUroA=", + "_location": "/pruddy-error", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "pruddy-error@1.0.x", + "name": "pruddy-error", + "escapedName": "pruddy-error", + "rawSpec": "1.0.x", + "saveSpec": null, + "fetchSpec": "1.0.x" + }, + "_requiredBy": [ + "/assume" + ], + "_resolved": "https://registry.npmjs.org/pruddy-error/-/pruddy-error-1.0.2.tgz", + "_shasum": "b37ec1a38bf9107c0cdc5bc663d3d4e80354ae80", + "_spec": "pruddy-error@1.0.x", + "_where": "/home/xavier/dev/debian/packages/node-url-parse/node_modules/assume", + "author": { + "name": "azer" + }, + "bugs": { + "url": "https://github.com/bigpipe/pruddy-error/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Prettify given error object", + "homepage": "https://github.com/bigpipe/pruddy-error#readme", + "keywords": [ + "error", + "pretty", + "prettify" + ], + "license": "BSD", + "main": "index.js", + "name": "pruddy-error", + "repository": { + "url": "git+ssh://g...@github.com/bigpipe/pruddy-error.git", + "type": "git" + }, + "scripts": { + "test": "node --use_strict test.js" + }, + "version": "1.0.2" +} diff --git a/debian/tests/test-modules/pruddy-error/style-format.js b/debian/tests/test-modules/pruddy-error/style-format.js new file mode 100644 index 0000000..acd810e --- /dev/null +++ b/debian/tests/test-modules/pruddy-error/style-format.js @@ -0,0 +1,8 @@ +var ansi = require('./ansi-codes.json'); +var format = require('./format-text'); + +module.exports = styleFormat; + +function styleFormat (text) { + return format(text, ansi); +} diff --git a/debian/upstream/metadata b/debian/upstream/metadata new file mode 100644 index 0000000..b2469bc --- /dev/null +++ b/debian/upstream/metadata @@ -0,0 +1,7 @@ +--- +Archive: GitHub +Bug-Database: https://github.com/unshiftio/url-parse/issues +Contact: https://github.com/unshiftio/url-parse/issues +Name: url-parse +Repository: https://github.com/unshiftio/url-parse.git +Repository-Browse: https://github.com/unshiftio/url-parse