├── .travis.yml ├── css ├── gh-fork-ribbon.css ├── locations.css └── map.css ├── images ├── marker-icon-0.png ├── marker-icon-1.png ├── marker-icon-2.png ├── marker-icon-3.png └── tolkien.jpg ├── index.html ├── js ├── locations.js ├── map.js └── menu.js ├── locations.html ├── readme.md └── test ├── index.html ├── test.js └── vendors ├── chai-2.3.0 └── chai.js └── mocha-2.2.5 ├── mocha.css └── mocha.js /.travis.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - wget http://stedolan.github.io/jq/download/linux64/jq && chmod u+x jq 3 | - npm install -g mocha 4 | - npm install mocha-phantomjs-core 5 | 6 | script: 7 | - error = 0; for file in `ls locations/*json`; do ./jq '.' $file; error=$((error + $?)); done; exit $error 8 | - phantomjs node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html 9 | -------------------------------------------------------------------------------- /css/gh-fork-ribbon.css: -------------------------------------------------------------------------------- 1 | /* Left will inherit from right (so we don't need to duplicate code) */ 2 | .github-fork-ribbon { 3 | /* The right and left classes determine the side we attach our banner to */ 4 | position: absolute; 5 | 6 | /* Add a bit of padding to give some substance outside the "stitching" */ 7 | padding: 2px 0; 8 | 9 | /* Set the base colour */ 10 | background-color: #a00; 11 | 12 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ 13 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15))); 14 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 15 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 16 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 17 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 18 | background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 19 | 20 | /* Add a drop shadow */ 21 | -webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 22 | -moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 23 | box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 24 | 25 | z-index: 9999; 26 | pointer-events: auto; 27 | } 28 | 29 | .github-fork-ribbon a, 30 | .github-fork-ribbon a:hover { 31 | /* Set the font */ 32 | font: 700 13px "Helvetica Neue", Helvetica, Arial, sans-serif; 33 | color: #fff; 34 | 35 | /* Set the text properties */ 36 | text-decoration: none; 37 | text-shadow: 0 -1px rgba(0, 0, 0, 0.5); 38 | text-align: center; 39 | 40 | /* Set the geometry. If you fiddle with these you'll also need 41 | to tweak the top and right values in .github-fork-ribbon. */ 42 | width: 200px; 43 | line-height: 20px; 44 | 45 | /* Set the layout properties */ 46 | display: inline-block; 47 | padding: 2px 0; 48 | 49 | /* Add "stitching" effect */ 50 | border-width: 1px 0; 51 | border-style: dotted; 52 | border-color: #fff; 53 | border-color: rgba(255, 255, 255, 0.7); 54 | } 55 | 56 | .github-fork-ribbon-wrapper { 57 | width: 150px; 58 | height: 150px; 59 | position: absolute; 60 | overflow: hidden; 61 | top: 0; 62 | z-index: 9999; 63 | pointer-events: none; 64 | } 65 | 66 | .github-fork-ribbon-wrapper.fixed { 67 | position: fixed; 68 | } 69 | 70 | .github-fork-ribbon-wrapper.left { 71 | left: 0; 72 | } 73 | 74 | .github-fork-ribbon-wrapper.right { 75 | right: 0; 76 | } 77 | 78 | .github-fork-ribbon-wrapper.left-bottom { 79 | position: fixed; 80 | top: inherit; 81 | bottom: 0; 82 | left: 0; 83 | } 84 | 85 | .github-fork-ribbon-wrapper.right-bottom { 86 | position: fixed; 87 | top: inherit; 88 | bottom: 0; 89 | right: 0; 90 | } 91 | 92 | .github-fork-ribbon-wrapper.right .github-fork-ribbon { 93 | top: 42px; 94 | right: -43px; 95 | 96 | -webkit-transform: rotate(45deg); 97 | -moz-transform: rotate(45deg); 98 | -ms-transform: rotate(45deg); 99 | -o-transform: rotate(45deg); 100 | transform: rotate(45deg); 101 | } 102 | 103 | .github-fork-ribbon-wrapper.left .github-fork-ribbon { 104 | top: 42px; 105 | left: -43px; 106 | 107 | -webkit-transform: rotate(-45deg); 108 | -moz-transform: rotate(-45deg); 109 | -ms-transform: rotate(-45deg); 110 | -o-transform: rotate(-45deg); 111 | transform: rotate(-45deg); 112 | } 113 | 114 | 115 | .github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon { 116 | top: 80px; 117 | left: -43px; 118 | 119 | -webkit-transform: rotate(45deg); 120 | -moz-transform: rotate(45deg); 121 | -ms-transform: rotate(45deg); 122 | -o-transform: rotate(45deg); 123 | transform: rotate(45deg); 124 | } 125 | 126 | .github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon { 127 | top: 80px; 128 | right: -43px; 129 | 130 | -webkit-transform: rotate(-45deg); 131 | -moz-transform: rotate(-45deg); 132 | -ms-transform: rotate(-45deg); 133 | -o-transform: rotate(-45deg); 134 | transform: rotate(-45deg); 135 | } 136 | -------------------------------------------------------------------------------- /css/locations.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #ADE199 url('../images/tolkien.jpg'); 3 | background-size: 100%; 4 | height:100%; 5 | width: 100%; 6 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 7 | text-align: center; 8 | color: #35641E; 9 | } 10 | 11 | section.container { 12 | max-width: 300px; 13 | margin: auto; 14 | } 15 | 16 | h1 { 17 | font-size: 25px; 18 | } 19 | 20 | p { 21 | font-size: 17px; 22 | } 23 | 24 | ul { 25 | font-size: 14px; 26 | line-height: 1.42857143; 27 | padding-left: 0; 28 | } 29 | 30 | li { 31 | display: block; 32 | border-top-left-radius: 4px; 33 | border-top-right-radius: 4px; 34 | position: relative; 35 | padding: 5px 15px; 36 | margin-bottom: -1px; 37 | background-color: #fff; 38 | opacity: .5; 39 | border: 1px solid #ddd; 40 | } 41 | 42 | li:hover { 43 | background: #eee; 44 | } 45 | 46 | li a { 47 | display: block; 48 | text-decoration: none; 49 | color: #555; 50 | } 51 | -------------------------------------------------------------------------------- /css/map.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #map { 9 | height: 100%; 10 | } 11 | 12 | #home { 13 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 14 | position: absolute; 15 | padding: 5px; 16 | bottom: 0; 17 | z-index: 9999; 18 | font-weight: 800; 19 | } 20 | -------------------------------------------------------------------------------- /images/marker-icon-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avernois/devfriendlyplaces/3187980a65d1ef3c5f1ee92d05ce6fe7dd017d08/images/marker-icon-0.png -------------------------------------------------------------------------------- /images/marker-icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avernois/devfriendlyplaces/3187980a65d1ef3c5f1ee92d05ce6fe7dd017d08/images/marker-icon-1.png -------------------------------------------------------------------------------- /images/marker-icon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avernois/devfriendlyplaces/3187980a65d1ef3c5f1ee92d05ce6fe7dd017d08/images/marker-icon-2.png -------------------------------------------------------------------------------- /images/marker-icon-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avernois/devfriendlyplaces/3187980a65d1ef3c5f1ee92d05ce6fe7dd017d08/images/marker-icon-3.png -------------------------------------------------------------------------------- /images/tolkien.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/avernois/devfriendlyplaces/3187980a65d1ef3c5f1ee92d05ce6fe7dd017d08/images/tolkien.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dev Friendly Places 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | Contribute 15 |
16 |
17 | 18 |
CITIES
19 |
20 | 21 | 22 | 23 | 24 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /js/locations.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | function extractLocationFromUrl(hostname) { 5 | var split = hostname.split("."); 6 | var location = split[0]; 7 | 8 | if ((split.length < 3) || (location == "www")) { 9 | throw "No location in the url";; 10 | } 11 | 12 | return location; 13 | } 14 | 15 | 16 | function getJSON(url) { 17 | var request = new XMLHttpRequest(); 18 | request.open("GET", url, false); 19 | request.send(null); 20 | 21 | return JSON.parse(request.responseText); 22 | } 23 | 24 | 25 | function slugifyLocation(location) { 26 | return location.toUpperCase() 27 | .replace("À", "A") 28 | .replace(/[È,É]/, "E") 29 | .replace(" ", "-") 30 | .toLowerCase(); 31 | } 32 | 33 | 34 | function getLocations() { 35 | // Possible to get an absolute url : https://raw.githubusercontent.com/... 36 | return getJSON("https://raw.githubusercontent.com/devfriendlyplaces/data/data/locations/locations.json"); 37 | } 38 | 39 | 40 | function getPlaces(location) { 41 | return getJSON("https://raw.githubusercontent.com/devfriendlyplaces/data/data/locations/" + location + ".json"); 42 | } 43 | 44 | 45 | function sortKeys(locations) { 46 | return locations.map(l => l.name).sort() 47 | } 48 | 49 | 50 | function getLocationInfo(locations, location) { 51 | return locations.filter( 52 | l => slugifyLocation(l.name) === location 53 | )[0] 54 | } 55 | -------------------------------------------------------------------------------- /js/map.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var marker_icons = []; 4 | for (var i = 0; i < 4; i++) { 5 | marker_icons.push( 6 | L.icon({ 7 | iconUrl: 'images/marker-icon-' + i + '.png', 8 | iconSize: [25, 41], 9 | iconAnchor: [12, 41], 10 | popupAnchor: [0, -30] 11 | }) 12 | ); 13 | } 14 | 15 | 16 | function buildMapFor(location) { 17 | var defaultZoom = 14; 18 | var locations = getLocations(); 19 | var locationInfo = getLocationInfo(locations, location); 20 | var map = L.map('map').setView([locationInfo.lat, locationInfo.lon], locationInfo.defaultZoom); 21 | map.on('moveend', onMoveEnd(map, locations)); 22 | L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 23 | attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA' 24 | }).addTo(map); 25 | 26 | map.isDisplayedLocation = {}; 27 | 28 | displayPlacesFromLocation(map, location); 29 | } 30 | 31 | 32 | function placeToHtml(place) { 33 | return "" + place.name + "
" + 34 | optionalFieldToHtml("address", place.address) + 35 | optionalFieldToHtml("open hours", place.openHours) + 36 | optionalFieldToHtml("type", place.type) + 37 | optionalUrlToLink("website", place.url) + 38 | optionToHtml("power", place.power) + 39 | optionToHtml("wifi", place.wifi) + 40 | optionalFieldToHtml("comment", place.comment); 41 | } 42 | 43 | 44 | function iconForPlace(place) { 45 | var weights = { wifi: 1, power: 2 }; 46 | var iconIndex = 0; 47 | 48 | for (var idx in weights) { 49 | iconIndex += optionValue(place[idx]) * weights[idx]; 50 | } 51 | 52 | return marker_icons[iconIndex]; 53 | } 54 | 55 | 56 | function optionalFieldToHtml(label, value) { 57 | return value ? label + ": " + value + "
" : ""; 58 | } 59 | 60 | 61 | function optionalUrlToLink(label, value) { 62 | return value ? label + ": " + "" + value + "" + "
" : ""; 63 | } 64 | 65 | 66 | function optionToHtml(label, value) { 67 | return label + ": " + optionText(value) + "
"; 68 | } 69 | 70 | 71 | function optionText(value) { 72 | if (value !== undefined) { 73 | return boolToStr(value.available) + optionalComment(value.comment); 74 | } else { 75 | return "undefined"; 76 | } 77 | } 78 | 79 | 80 | function optionValue(value) { 81 | if (value !== undefined) { 82 | return boolToInt(value.available); 83 | } 84 | return 0; 85 | } 86 | 87 | 88 | function boolToStr(value) { 89 | if (value !== undefined) { 90 | return value ? "yes" : "no"; 91 | } else { 92 | return 'undefined'; 93 | } 94 | } 95 | 96 | 97 | function boolToInt(value) { 98 | if (value !== undefined) { 99 | return value ? 1 : 0; 100 | } else { 101 | return 0; 102 | } 103 | } 104 | 105 | 106 | function optionalComment(value) { 107 | return value ? "(" + value + ")" : ""; 108 | } 109 | 110 | 111 | function displayPlacesFromLocation(map, location) { 112 | if (isLocationDisplayedOnMap(map, location)) { return; } 113 | 114 | var places = getPlaces(location); 115 | 116 | places.forEach(function(place) { 117 | L.marker([place.lat, place.lon], { icon: iconForPlace(place) }) 118 | .bindPopup(placeToHtml(place)) 119 | .addTo(map); 120 | }); 121 | 122 | map.isDisplayedLocation[location] = true; 123 | } 124 | 125 | 126 | function onMoveEnd(map, locations) { 127 | return function() { 128 | locations.map(location => { 129 | if (map.getBounds().contains([location.lat, location.lon])) { 130 | displayPlacesFromLocation(map, slugifyLocation(location.name)); 131 | } 132 | }); 133 | } 134 | } 135 | 136 | 137 | function isLocationDisplayedOnMap(map, location) { 138 | return map.isDisplayedLocation[location]; 139 | } -------------------------------------------------------------------------------- /js/menu.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function buildLocations() { 4 | var locations = getLocations(); 5 | var listContainer = document.createElement("div"); 6 | var listElement = document.createElement("ul"); 7 | document.getElementById("locations").appendChild(listContainer); 8 | listContainer.appendChild(listElement); 9 | sortKeys(locations).map(location => { 10 | var listItem = document.createElement("li"); 11 | listItem.innerHTML = "" + location + ""; 12 | listElement.appendChild(listItem); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /locations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dev Friendly Places 5 | 6 | 7 | 8 | 9 | 10 |
11 |

DEV FRIENDLY PLACES

12 |

Pick a city and find a place for coding

13 | 14 |
15 |
16 | Contribute 17 |
18 |
19 | 20 |
21 | 22 | 23 | 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | New reposistories for devfriendlyplaces 2 | ======================================= 3 | 4 | Everything related to devfriendlyplaces has moved to a dedicated organisation [devfriendlyplaces](https://github.com/devfriendlyplaces): 5 | - code of website: https://github.com/devfriendlyplaces/elm-site 6 | - locations data: https://github.com/devfriendlyplaces/data 7 | 8 | This original repository is kept here for archive. 9 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var should = chai.should(); 2 | 3 | describe('Extract the location from the url', function() { 4 | it('should return the location from an Url', function () { 5 | var location = extractLocationFromUrl('cerclon.devfriendlyplaces.net'); 6 | location.should.equal('cerclon'); 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /test/vendors/chai-2.3.0/chai.js: -------------------------------------------------------------------------------- 1 | 2 | ;(function(){ 3 | 4 | /** 5 | * Require the module at `name`. 6 | * 7 | * @param {String} name 8 | * @return {Object} exports 9 | * @api public 10 | */ 11 | 12 | function require(name) { 13 | var module = require.modules[name]; 14 | if (!module) throw new Error('failed to require "' + name + '"'); 15 | 16 | if (!('exports' in module) && typeof module.definition === 'function') { 17 | module.client = module.component = true; 18 | module.definition.call(this, module.exports = {}, module); 19 | delete module.definition; 20 | } 21 | 22 | return module.exports; 23 | } 24 | 25 | /** 26 | * Meta info, accessible in the global scope unless you use AMD option. 27 | */ 28 | 29 | require.loader = 'component'; 30 | 31 | /** 32 | * Internal helper object, contains a sorting function for semantiv versioning 33 | */ 34 | require.helper = {}; 35 | require.helper.semVerSort = function(a, b) { 36 | var aArray = a.version.split('.'); 37 | var bArray = b.version.split('.'); 38 | for (var i=0; i bLex ? 1 : -1; 47 | continue; 48 | } else if (aInt > bInt) { 49 | return 1; 50 | } else { 51 | return -1; 52 | } 53 | } 54 | return 0; 55 | } 56 | 57 | /** 58 | * Find and require a module which name starts with the provided name. 59 | * If multiple modules exists, the highest semver is used. 60 | * This function can only be used for remote dependencies. 61 | 62 | * @param {String} name - module name: `user~repo` 63 | * @param {Boolean} returnPath - returns the canonical require path if true, 64 | * otherwise it returns the epxorted module 65 | */ 66 | require.latest = function (name, returnPath) { 67 | function showError(name) { 68 | throw new Error('failed to find latest module of "' + name + '"'); 69 | } 70 | // only remotes with semvers, ignore local files conataining a '/' 71 | var versionRegexp = /(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/; 72 | var remoteRegexp = /(.*)~(.*)/; 73 | if (!remoteRegexp.test(name)) showError(name); 74 | var moduleNames = Object.keys(require.modules); 75 | var semVerCandidates = []; 76 | var otherCandidates = []; // for instance: name of the git branch 77 | for (var i=0; i 0) { 93 | var module = semVerCandidates.sort(require.helper.semVerSort).pop().name; 94 | if (returnPath === true) { 95 | return module; 96 | } 97 | return require(module); 98 | } 99 | // if the build contains more than one branch of the same module 100 | // you should not use this funciton 101 | var module = otherCandidates.sort(function(a, b) {return a.name > b.name})[0].name; 102 | if (returnPath === true) { 103 | return module; 104 | } 105 | return require(module); 106 | } 107 | 108 | /** 109 | * Registered modules. 110 | */ 111 | 112 | require.modules = {}; 113 | 114 | /** 115 | * Register module at `name` with callback `definition`. 116 | * 117 | * @param {String} name 118 | * @param {Function} definition 119 | * @api private 120 | */ 121 | 122 | require.register = function (name, definition) { 123 | require.modules[name] = { 124 | definition: definition 125 | }; 126 | }; 127 | 128 | /** 129 | * Define a module's exports immediately with `exports`. 130 | * 131 | * @param {String} name 132 | * @param {Generic} exports 133 | * @api private 134 | */ 135 | 136 | require.define = function (name, exports) { 137 | require.modules[name] = { 138 | exports: exports 139 | }; 140 | }; 141 | require.register("chaijs~assertion-error@1.0.0", function (exports, module) { 142 | /*! 143 | * assertion-error 144 | * Copyright(c) 2013 Jake Luer 145 | * MIT Licensed 146 | */ 147 | 148 | /*! 149 | * Return a function that will copy properties from 150 | * one object to another excluding any originally 151 | * listed. Returned function will create a new `{}`. 152 | * 153 | * @param {String} excluded properties ... 154 | * @return {Function} 155 | */ 156 | 157 | function exclude () { 158 | var excludes = [].slice.call(arguments); 159 | 160 | function excludeProps (res, obj) { 161 | Object.keys(obj).forEach(function (key) { 162 | if (!~excludes.indexOf(key)) res[key] = obj[key]; 163 | }); 164 | } 165 | 166 | return function extendExclude () { 167 | var args = [].slice.call(arguments) 168 | , i = 0 169 | , res = {}; 170 | 171 | for (; i < args.length; i++) { 172 | excludeProps(res, args[i]); 173 | } 174 | 175 | return res; 176 | }; 177 | }; 178 | 179 | /*! 180 | * Primary Exports 181 | */ 182 | 183 | module.exports = AssertionError; 184 | 185 | /** 186 | * ### AssertionError 187 | * 188 | * An extension of the JavaScript `Error` constructor for 189 | * assertion and validation scenarios. 190 | * 191 | * @param {String} message 192 | * @param {Object} properties to include (optional) 193 | * @param {callee} start stack function (optional) 194 | */ 195 | 196 | function AssertionError (message, _props, ssf) { 197 | var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') 198 | , props = extend(_props || {}); 199 | 200 | // default values 201 | this.message = message || 'Unspecified AssertionError'; 202 | this.showDiff = false; 203 | 204 | // copy from properties 205 | for (var key in props) { 206 | this[key] = props[key]; 207 | } 208 | 209 | // capture stack trace 210 | ssf = ssf || arguments.callee; 211 | if (ssf && Error.captureStackTrace) { 212 | Error.captureStackTrace(this, ssf); 213 | } 214 | } 215 | 216 | /*! 217 | * Inherit from Error.prototype 218 | */ 219 | 220 | AssertionError.prototype = Object.create(Error.prototype); 221 | 222 | /*! 223 | * Statically set name 224 | */ 225 | 226 | AssertionError.prototype.name = 'AssertionError'; 227 | 228 | /*! 229 | * Ensure correct constructor 230 | */ 231 | 232 | AssertionError.prototype.constructor = AssertionError; 233 | 234 | /** 235 | * Allow errors to be converted to JSON for static transfer. 236 | * 237 | * @param {Boolean} include stack (default: `true`) 238 | * @return {Object} object that can be `JSON.stringify` 239 | */ 240 | 241 | AssertionError.prototype.toJSON = function (stack) { 242 | var extend = exclude('constructor', 'toJSON', 'stack') 243 | , props = extend({ name: this.name }, this); 244 | 245 | // include stack if exists and not turned off 246 | if (false !== stack && this.stack) { 247 | props.stack = this.stack; 248 | } 249 | 250 | return props; 251 | }; 252 | 253 | }); 254 | 255 | require.register("chaijs~type-detect@0.1.1", function (exports, module) { 256 | /*! 257 | * type-detect 258 | * Copyright(c) 2013 jake luer 259 | * MIT Licensed 260 | */ 261 | 262 | /*! 263 | * Primary Exports 264 | */ 265 | 266 | var exports = module.exports = getType; 267 | 268 | /*! 269 | * Detectable javascript natives 270 | */ 271 | 272 | var natives = { 273 | '[object Array]': 'array' 274 | , '[object RegExp]': 'regexp' 275 | , '[object Function]': 'function' 276 | , '[object Arguments]': 'arguments' 277 | , '[object Date]': 'date' 278 | }; 279 | 280 | /** 281 | * ### typeOf (obj) 282 | * 283 | * Use several different techniques to determine 284 | * the type of object being tested. 285 | * 286 | * 287 | * @param {Mixed} object 288 | * @return {String} object type 289 | * @api public 290 | */ 291 | 292 | function getType (obj) { 293 | var str = Object.prototype.toString.call(obj); 294 | if (natives[str]) return natives[str]; 295 | if (obj === null) return 'null'; 296 | if (obj === undefined) return 'undefined'; 297 | if (obj === Object(obj)) return 'object'; 298 | return typeof obj; 299 | } 300 | 301 | exports.Library = Library; 302 | 303 | /** 304 | * ### Library 305 | * 306 | * Create a repository for custom type detection. 307 | * 308 | * ```js 309 | * var lib = new type.Library; 310 | * ``` 311 | * 312 | */ 313 | 314 | function Library () { 315 | this.tests = {}; 316 | } 317 | 318 | /** 319 | * #### .of (obj) 320 | * 321 | * Expose replacement `typeof` detection to the library. 322 | * 323 | * ```js 324 | * if ('string' === lib.of('hello world')) { 325 | * // ... 326 | * } 327 | * ``` 328 | * 329 | * @param {Mixed} object to test 330 | * @return {String} type 331 | */ 332 | 333 | Library.prototype.of = getType; 334 | 335 | /** 336 | * #### .define (type, test) 337 | * 338 | * Add a test to for the `.test()` assertion. 339 | * 340 | * Can be defined as a regular expression: 341 | * 342 | * ```js 343 | * lib.define('int', /^[0-9]+$/); 344 | * ``` 345 | * 346 | * ... or as a function: 347 | * 348 | * ```js 349 | * lib.define('bln', function (obj) { 350 | * if ('boolean' === lib.of(obj)) return true; 351 | * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; 352 | * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); 353 | * return !! ~blns.indexOf(obj); 354 | * }); 355 | * ``` 356 | * 357 | * @param {String} type 358 | * @param {RegExp|Function} test 359 | * @api public 360 | */ 361 | 362 | Library.prototype.define = function (type, test) { 363 | if (arguments.length === 1) return this.tests[type]; 364 | this.tests[type] = test; 365 | return this; 366 | }; 367 | 368 | /** 369 | * #### .test (obj, test) 370 | * 371 | * Assert that an object is of type. Will first 372 | * check natives, and if that does not pass it will 373 | * use the user defined custom tests. 374 | * 375 | * ```js 376 | * assert(lib.test('1', 'int')); 377 | * assert(lib.test('yes', 'bln')); 378 | * ``` 379 | * 380 | * @param {Mixed} object 381 | * @param {String} type 382 | * @return {Boolean} result 383 | * @api public 384 | */ 385 | 386 | Library.prototype.test = function (obj, type) { 387 | if (type === getType(obj)) return true; 388 | var test = this.tests[type]; 389 | 390 | if (test && 'regexp' === getType(test)) { 391 | return test.test(obj); 392 | } else if (test && 'function' === getType(test)) { 393 | return test(obj); 394 | } else { 395 | throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); 396 | } 397 | }; 398 | 399 | }); 400 | 401 | require.register("chaijs~deep-eql@0.1.3", function (exports, module) { 402 | /*! 403 | * deep-eql 404 | * Copyright(c) 2013 Jake Luer 405 | * MIT Licensed 406 | */ 407 | 408 | /*! 409 | * Module dependencies 410 | */ 411 | 412 | var type = require('chaijs~type-detect@0.1.1'); 413 | 414 | /*! 415 | * Buffer.isBuffer browser shim 416 | */ 417 | 418 | var Buffer; 419 | try { Buffer = require('buffer').Buffer; } 420 | catch(ex) { 421 | Buffer = {}; 422 | Buffer.isBuffer = function() { return false; } 423 | } 424 | 425 | /*! 426 | * Primary Export 427 | */ 428 | 429 | module.exports = deepEqual; 430 | 431 | /** 432 | * Assert super-strict (egal) equality between 433 | * two objects of any type. 434 | * 435 | * @param {Mixed} a 436 | * @param {Mixed} b 437 | * @param {Array} memoised (optional) 438 | * @return {Boolean} equal match 439 | */ 440 | 441 | function deepEqual(a, b, m) { 442 | if (sameValue(a, b)) { 443 | return true; 444 | } else if ('date' === type(a)) { 445 | return dateEqual(a, b); 446 | } else if ('regexp' === type(a)) { 447 | return regexpEqual(a, b); 448 | } else if (Buffer.isBuffer(a)) { 449 | return bufferEqual(a, b); 450 | } else if ('arguments' === type(a)) { 451 | return argumentsEqual(a, b, m); 452 | } else if (!typeEqual(a, b)) { 453 | return false; 454 | } else if (('object' !== type(a) && 'object' !== type(b)) 455 | && ('array' !== type(a) && 'array' !== type(b))) { 456 | return sameValue(a, b); 457 | } else { 458 | return objectEqual(a, b, m); 459 | } 460 | } 461 | 462 | /*! 463 | * Strict (egal) equality test. Ensures that NaN always 464 | * equals NaN and `-0` does not equal `+0`. 465 | * 466 | * @param {Mixed} a 467 | * @param {Mixed} b 468 | * @return {Boolean} equal match 469 | */ 470 | 471 | function sameValue(a, b) { 472 | if (a === b) return a !== 0 || 1 / a === 1 / b; 473 | return a !== a && b !== b; 474 | } 475 | 476 | /*! 477 | * Compare the types of two given objects and 478 | * return if they are equal. Note that an Array 479 | * has a type of `array` (not `object`) and arguments 480 | * have a type of `arguments` (not `array`/`object`). 481 | * 482 | * @param {Mixed} a 483 | * @param {Mixed} b 484 | * @return {Boolean} result 485 | */ 486 | 487 | function typeEqual(a, b) { 488 | return type(a) === type(b); 489 | } 490 | 491 | /*! 492 | * Compare two Date objects by asserting that 493 | * the time values are equal using `saveValue`. 494 | * 495 | * @param {Date} a 496 | * @param {Date} b 497 | * @return {Boolean} result 498 | */ 499 | 500 | function dateEqual(a, b) { 501 | if ('date' !== type(b)) return false; 502 | return sameValue(a.getTime(), b.getTime()); 503 | } 504 | 505 | /*! 506 | * Compare two regular expressions by converting them 507 | * to string and checking for `sameValue`. 508 | * 509 | * @param {RegExp} a 510 | * @param {RegExp} b 511 | * @return {Boolean} result 512 | */ 513 | 514 | function regexpEqual(a, b) { 515 | if ('regexp' !== type(b)) return false; 516 | return sameValue(a.toString(), b.toString()); 517 | } 518 | 519 | /*! 520 | * Assert deep equality of two `arguments` objects. 521 | * Unfortunately, these must be sliced to arrays 522 | * prior to test to ensure no bad behavior. 523 | * 524 | * @param {Arguments} a 525 | * @param {Arguments} b 526 | * @param {Array} memoize (optional) 527 | * @return {Boolean} result 528 | */ 529 | 530 | function argumentsEqual(a, b, m) { 531 | if ('arguments' !== type(b)) return false; 532 | a = [].slice.call(a); 533 | b = [].slice.call(b); 534 | return deepEqual(a, b, m); 535 | } 536 | 537 | /*! 538 | * Get enumerable properties of a given object. 539 | * 540 | * @param {Object} a 541 | * @return {Array} property names 542 | */ 543 | 544 | function enumerable(a) { 545 | var res = []; 546 | for (var key in a) res.push(key); 547 | return res; 548 | } 549 | 550 | /*! 551 | * Simple equality for flat iterable objects 552 | * such as Arrays or Node.js buffers. 553 | * 554 | * @param {Iterable} a 555 | * @param {Iterable} b 556 | * @return {Boolean} result 557 | */ 558 | 559 | function iterableEqual(a, b) { 560 | if (a.length !== b.length) return false; 561 | 562 | var i = 0; 563 | var match = true; 564 | 565 | for (; i < a.length; i++) { 566 | if (a[i] !== b[i]) { 567 | match = false; 568 | break; 569 | } 570 | } 571 | 572 | return match; 573 | } 574 | 575 | /*! 576 | * Extension to `iterableEqual` specifically 577 | * for Node.js Buffers. 578 | * 579 | * @param {Buffer} a 580 | * @param {Mixed} b 581 | * @return {Boolean} result 582 | */ 583 | 584 | function bufferEqual(a, b) { 585 | if (!Buffer.isBuffer(b)) return false; 586 | return iterableEqual(a, b); 587 | } 588 | 589 | /*! 590 | * Block for `objectEqual` ensuring non-existing 591 | * values don't get in. 592 | * 593 | * @param {Mixed} object 594 | * @return {Boolean} result 595 | */ 596 | 597 | function isValue(a) { 598 | return a !== null && a !== undefined; 599 | } 600 | 601 | /*! 602 | * Recursively check the equality of two objects. 603 | * Once basic sameness has been established it will 604 | * defer to `deepEqual` for each enumerable key 605 | * in the object. 606 | * 607 | * @param {Mixed} a 608 | * @param {Mixed} b 609 | * @return {Boolean} result 610 | */ 611 | 612 | function objectEqual(a, b, m) { 613 | if (!isValue(a) || !isValue(b)) { 614 | return false; 615 | } 616 | 617 | if (a.prototype !== b.prototype) { 618 | return false; 619 | } 620 | 621 | var i; 622 | if (m) { 623 | for (i = 0; i < m.length; i++) { 624 | if ((m[i][0] === a && m[i][1] === b) 625 | || (m[i][0] === b && m[i][1] === a)) { 626 | return true; 627 | } 628 | } 629 | } else { 630 | m = []; 631 | } 632 | 633 | try { 634 | var ka = enumerable(a); 635 | var kb = enumerable(b); 636 | } catch (ex) { 637 | return false; 638 | } 639 | 640 | ka.sort(); 641 | kb.sort(); 642 | 643 | if (!iterableEqual(ka, kb)) { 644 | return false; 645 | } 646 | 647 | m.push([ a, b ]); 648 | 649 | var key; 650 | for (i = ka.length - 1; i >= 0; i--) { 651 | key = ka[i]; 652 | if (!deepEqual(a[key], b[key], m)) { 653 | return false; 654 | } 655 | } 656 | 657 | return true; 658 | } 659 | 660 | }); 661 | 662 | require.register("chai", function (exports, module) { 663 | module.exports = require('chai/lib/chai.js'); 664 | 665 | }); 666 | 667 | require.register("chai/lib/chai.js", function (exports, module) { 668 | /*! 669 | * chai 670 | * Copyright(c) 2011-2014 Jake Luer 671 | * MIT Licensed 672 | */ 673 | 674 | var used = [] 675 | , exports = module.exports = {}; 676 | 677 | /*! 678 | * Chai version 679 | */ 680 | 681 | exports.version = '2.3.0'; 682 | 683 | /*! 684 | * Assertion Error 685 | */ 686 | 687 | exports.AssertionError = require('chaijs~assertion-error@1.0.0'); 688 | 689 | /*! 690 | * Utils for plugins (not exported) 691 | */ 692 | 693 | var util = require('chai/lib/chai/utils/index.js'); 694 | 695 | /** 696 | * # .use(function) 697 | * 698 | * Provides a way to extend the internals of Chai 699 | * 700 | * @param {Function} 701 | * @returns {this} for chaining 702 | * @api public 703 | */ 704 | 705 | exports.use = function (fn) { 706 | if (!~used.indexOf(fn)) { 707 | fn(this, util); 708 | used.push(fn); 709 | } 710 | 711 | return this; 712 | }; 713 | 714 | /*! 715 | * Utility Functions 716 | */ 717 | 718 | exports.util = util; 719 | 720 | /*! 721 | * Configuration 722 | */ 723 | 724 | var config = require('chai/lib/chai/config.js'); 725 | exports.config = config; 726 | 727 | /*! 728 | * Primary `Assertion` prototype 729 | */ 730 | 731 | var assertion = require('chai/lib/chai/assertion.js'); 732 | exports.use(assertion); 733 | 734 | /*! 735 | * Core Assertions 736 | */ 737 | 738 | var core = require('chai/lib/chai/core/assertions.js'); 739 | exports.use(core); 740 | 741 | /*! 742 | * Expect interface 743 | */ 744 | 745 | var expect = require('chai/lib/chai/interface/expect.js'); 746 | exports.use(expect); 747 | 748 | /*! 749 | * Should interface 750 | */ 751 | 752 | var should = require('chai/lib/chai/interface/should.js'); 753 | exports.use(should); 754 | 755 | /*! 756 | * Assert interface 757 | */ 758 | 759 | var assert = require('chai/lib/chai/interface/assert.js'); 760 | exports.use(assert); 761 | 762 | }); 763 | 764 | require.register("chai/lib/chai/assertion.js", function (exports, module) { 765 | /*! 766 | * chai 767 | * http://chaijs.com 768 | * Copyright(c) 2011-2014 Jake Luer 769 | * MIT Licensed 770 | */ 771 | 772 | var config = require('chai/lib/chai/config.js'); 773 | 774 | module.exports = function (_chai, util) { 775 | /*! 776 | * Module dependencies. 777 | */ 778 | 779 | var AssertionError = _chai.AssertionError 780 | , flag = util.flag; 781 | 782 | /*! 783 | * Module export. 784 | */ 785 | 786 | _chai.Assertion = Assertion; 787 | 788 | /*! 789 | * Assertion Constructor 790 | * 791 | * Creates object for chaining. 792 | * 793 | * @api private 794 | */ 795 | 796 | function Assertion (obj, msg, stack) { 797 | flag(this, 'ssfi', stack || arguments.callee); 798 | flag(this, 'object', obj); 799 | flag(this, 'message', msg); 800 | } 801 | 802 | Object.defineProperty(Assertion, 'includeStack', { 803 | get: function() { 804 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 805 | return config.includeStack; 806 | }, 807 | set: function(value) { 808 | console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); 809 | config.includeStack = value; 810 | } 811 | }); 812 | 813 | Object.defineProperty(Assertion, 'showDiff', { 814 | get: function() { 815 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 816 | return config.showDiff; 817 | }, 818 | set: function(value) { 819 | console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); 820 | config.showDiff = value; 821 | } 822 | }); 823 | 824 | Assertion.addProperty = function (name, fn) { 825 | util.addProperty(this.prototype, name, fn); 826 | }; 827 | 828 | Assertion.addMethod = function (name, fn) { 829 | util.addMethod(this.prototype, name, fn); 830 | }; 831 | 832 | Assertion.addChainableMethod = function (name, fn, chainingBehavior) { 833 | util.addChainableMethod(this.prototype, name, fn, chainingBehavior); 834 | }; 835 | 836 | Assertion.overwriteProperty = function (name, fn) { 837 | util.overwriteProperty(this.prototype, name, fn); 838 | }; 839 | 840 | Assertion.overwriteMethod = function (name, fn) { 841 | util.overwriteMethod(this.prototype, name, fn); 842 | }; 843 | 844 | Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { 845 | util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); 846 | }; 847 | 848 | /*! 849 | * ### .assert(expression, message, negateMessage, expected, actual) 850 | * 851 | * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. 852 | * 853 | * @name assert 854 | * @param {Philosophical} expression to be tested 855 | * @param {String or Function} message or function that returns message to display if expression fails 856 | * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails 857 | * @param {Mixed} expected value (remember to check for negation) 858 | * @param {Mixed} actual (optional) will default to `this.obj` 859 | * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails 860 | * @api private 861 | */ 862 | 863 | Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { 864 | var ok = util.test(this, arguments); 865 | if (true !== showDiff) showDiff = false; 866 | if (true !== config.showDiff) showDiff = false; 867 | 868 | if (!ok) { 869 | var msg = util.getMessage(this, arguments) 870 | , actual = util.getActual(this, arguments); 871 | throw new AssertionError(msg, { 872 | actual: actual 873 | , expected: expected 874 | , showDiff: showDiff 875 | }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); 876 | } 877 | }; 878 | 879 | /*! 880 | * ### ._obj 881 | * 882 | * Quick reference to stored `actual` value for plugin developers. 883 | * 884 | * @api private 885 | */ 886 | 887 | Object.defineProperty(Assertion.prototype, '_obj', 888 | { get: function () { 889 | return flag(this, 'object'); 890 | } 891 | , set: function (val) { 892 | flag(this, 'object', val); 893 | } 894 | }); 895 | }; 896 | 897 | }); 898 | 899 | require.register("chai/lib/chai/config.js", function (exports, module) { 900 | module.exports = { 901 | 902 | /** 903 | * ### config.includeStack 904 | * 905 | * User configurable property, influences whether stack trace 906 | * is included in Assertion error message. Default of false 907 | * suppresses stack trace in the error message. 908 | * 909 | * chai.config.includeStack = true; // enable stack on error 910 | * 911 | * @param {Boolean} 912 | * @api public 913 | */ 914 | 915 | includeStack: false, 916 | 917 | /** 918 | * ### config.showDiff 919 | * 920 | * User configurable property, influences whether or not 921 | * the `showDiff` flag should be included in the thrown 922 | * AssertionErrors. `false` will always be `false`; `true` 923 | * will be true when the assertion has requested a diff 924 | * be shown. 925 | * 926 | * @param {Boolean} 927 | * @api public 928 | */ 929 | 930 | showDiff: true, 931 | 932 | /** 933 | * ### config.truncateThreshold 934 | * 935 | * User configurable property, sets length threshold for actual and 936 | * expected values in assertion errors. If this threshold is exceeded, for 937 | * example for large data structures, the value is replaced with something 938 | * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. 939 | * 940 | * Set it to zero if you want to disable truncating altogether. 941 | * 942 | * This is especially userful when doing assertions on arrays: having this 943 | * set to a reasonable large value makes the failure messages readily 944 | * inspectable. 945 | * 946 | * chai.config.truncateThreshold = 0; // disable truncating 947 | * 948 | * @param {Number} 949 | * @api public 950 | */ 951 | 952 | truncateThreshold: 40 953 | 954 | }; 955 | 956 | }); 957 | 958 | require.register("chai/lib/chai/core/assertions.js", function (exports, module) { 959 | /*! 960 | * chai 961 | * http://chaijs.com 962 | * Copyright(c) 2011-2014 Jake Luer 963 | * MIT Licensed 964 | */ 965 | 966 | module.exports = function (chai, _) { 967 | var Assertion = chai.Assertion 968 | , toString = Object.prototype.toString 969 | , flag = _.flag; 970 | 971 | /** 972 | * ### Language Chains 973 | * 974 | * The following are provided as chainable getters to 975 | * improve the readability of your assertions. They 976 | * do not provide testing capabilities unless they 977 | * have been overwritten by a plugin. 978 | * 979 | * **Chains** 980 | * 981 | * - to 982 | * - be 983 | * - been 984 | * - is 985 | * - that 986 | * - which 987 | * - and 988 | * - has 989 | * - have 990 | * - with 991 | * - at 992 | * - of 993 | * - same 994 | * 995 | * @name language chains 996 | * @api public 997 | */ 998 | 999 | [ 'to', 'be', 'been' 1000 | , 'is', 'and', 'has', 'have' 1001 | , 'with', 'that', 'which', 'at' 1002 | , 'of', 'same' ].forEach(function (chain) { 1003 | Assertion.addProperty(chain, function () { 1004 | return this; 1005 | }); 1006 | }); 1007 | 1008 | /** 1009 | * ### .not 1010 | * 1011 | * Negates any of assertions following in the chain. 1012 | * 1013 | * expect(foo).to.not.equal('bar'); 1014 | * expect(goodFn).to.not.throw(Error); 1015 | * expect({ foo: 'baz' }).to.have.property('foo') 1016 | * .and.not.equal('bar'); 1017 | * 1018 | * @name not 1019 | * @api public 1020 | */ 1021 | 1022 | Assertion.addProperty('not', function () { 1023 | flag(this, 'negate', true); 1024 | }); 1025 | 1026 | /** 1027 | * ### .deep 1028 | * 1029 | * Sets the `deep` flag, later used by the `equal` and 1030 | * `property` assertions. 1031 | * 1032 | * expect(foo).to.deep.equal({ bar: 'baz' }); 1033 | * expect({ foo: { bar: { baz: 'quux' } } }) 1034 | * .to.have.deep.property('foo.bar.baz', 'quux'); 1035 | * 1036 | * `.deep.property` special characters can be escaped 1037 | * by adding two slashes before the `.` or `[]`. 1038 | * 1039 | * var deepCss = { '.link': { '[target]': 42 }}; 1040 | * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); 1041 | * 1042 | * @name deep 1043 | * @api public 1044 | */ 1045 | 1046 | Assertion.addProperty('deep', function () { 1047 | flag(this, 'deep', true); 1048 | }); 1049 | 1050 | /** 1051 | * ### .any 1052 | * 1053 | * Sets the `any` flag, (opposite of the `all` flag) 1054 | * later used in the `keys` assertion. 1055 | * 1056 | * expect(foo).to.have.any.keys('bar', 'baz'); 1057 | * 1058 | * @name any 1059 | * @api public 1060 | */ 1061 | 1062 | Assertion.addProperty('any', function () { 1063 | flag(this, 'any', true); 1064 | flag(this, 'all', false) 1065 | }); 1066 | 1067 | 1068 | /** 1069 | * ### .all 1070 | * 1071 | * Sets the `all` flag (opposite of the `any` flag) 1072 | * later used by the `keys` assertion. 1073 | * 1074 | * expect(foo).to.have.all.keys('bar', 'baz'); 1075 | * 1076 | * @name all 1077 | * @api public 1078 | */ 1079 | 1080 | Assertion.addProperty('all', function () { 1081 | flag(this, 'all', true); 1082 | flag(this, 'any', false); 1083 | }); 1084 | 1085 | /** 1086 | * ### .a(type) 1087 | * 1088 | * The `a` and `an` assertions are aliases that can be 1089 | * used either as language chains or to assert a value's 1090 | * type. 1091 | * 1092 | * // typeof 1093 | * expect('test').to.be.a('string'); 1094 | * expect({ foo: 'bar' }).to.be.an('object'); 1095 | * expect(null).to.be.a('null'); 1096 | * expect(undefined).to.be.an('undefined'); 1097 | * 1098 | * // language chain 1099 | * expect(foo).to.be.an.instanceof(Foo); 1100 | * 1101 | * @name a 1102 | * @alias an 1103 | * @param {String} type 1104 | * @param {String} message _optional_ 1105 | * @api public 1106 | */ 1107 | 1108 | function an (type, msg) { 1109 | if (msg) flag(this, 'message', msg); 1110 | type = type.toLowerCase(); 1111 | var obj = flag(this, 'object') 1112 | , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; 1113 | 1114 | this.assert( 1115 | type === _.type(obj) 1116 | , 'expected #{this} to be ' + article + type 1117 | , 'expected #{this} not to be ' + article + type 1118 | ); 1119 | } 1120 | 1121 | Assertion.addChainableMethod('an', an); 1122 | Assertion.addChainableMethod('a', an); 1123 | 1124 | /** 1125 | * ### .include(value) 1126 | * 1127 | * The `include` and `contain` assertions can be used as either property 1128 | * based language chains or as methods to assert the inclusion of an object 1129 | * in an array or a substring in a string. When used as language chains, 1130 | * they toggle the `contains` flag for the `keys` assertion. 1131 | * 1132 | * expect([1,2,3]).to.include(2); 1133 | * expect('foobar').to.contain('foo'); 1134 | * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); 1135 | * 1136 | * @name include 1137 | * @alias contain 1138 | * @alias includes 1139 | * @alias contains 1140 | * @param {Object|String|Number} obj 1141 | * @param {String} message _optional_ 1142 | * @api public 1143 | */ 1144 | 1145 | function includeChainingBehavior () { 1146 | flag(this, 'contains', true); 1147 | } 1148 | 1149 | function include (val, msg) { 1150 | if (msg) flag(this, 'message', msg); 1151 | var obj = flag(this, 'object'); 1152 | var expected = false; 1153 | if (_.type(obj) === 'array' && _.type(val) === 'object') { 1154 | for (var i in obj) { 1155 | if (_.eql(obj[i], val)) { 1156 | expected = true; 1157 | break; 1158 | } 1159 | } 1160 | } else if (_.type(val) === 'object') { 1161 | if (!flag(this, 'negate')) { 1162 | for (var k in val) new Assertion(obj).property(k, val[k]); 1163 | return; 1164 | } 1165 | var subset = {}; 1166 | for (var k in val) subset[k] = obj[k]; 1167 | expected = _.eql(subset, val); 1168 | } else { 1169 | expected = obj && ~obj.indexOf(val); 1170 | } 1171 | this.assert( 1172 | expected 1173 | , 'expected #{this} to include ' + _.inspect(val) 1174 | , 'expected #{this} to not include ' + _.inspect(val)); 1175 | } 1176 | 1177 | Assertion.addChainableMethod('include', include, includeChainingBehavior); 1178 | Assertion.addChainableMethod('contain', include, includeChainingBehavior); 1179 | Assertion.addChainableMethod('contains', include, includeChainingBehavior); 1180 | Assertion.addChainableMethod('includes', include, includeChainingBehavior); 1181 | 1182 | /** 1183 | * ### .ok 1184 | * 1185 | * Asserts that the target is truthy. 1186 | * 1187 | * expect('everthing').to.be.ok; 1188 | * expect(1).to.be.ok; 1189 | * expect(false).to.not.be.ok; 1190 | * expect(undefined).to.not.be.ok; 1191 | * expect(null).to.not.be.ok; 1192 | * 1193 | * @name ok 1194 | * @api public 1195 | */ 1196 | 1197 | Assertion.addProperty('ok', function () { 1198 | this.assert( 1199 | flag(this, 'object') 1200 | , 'expected #{this} to be truthy' 1201 | , 'expected #{this} to be falsy'); 1202 | }); 1203 | 1204 | /** 1205 | * ### .true 1206 | * 1207 | * Asserts that the target is `true`. 1208 | * 1209 | * expect(true).to.be.true; 1210 | * expect(1).to.not.be.true; 1211 | * 1212 | * @name true 1213 | * @api public 1214 | */ 1215 | 1216 | Assertion.addProperty('true', function () { 1217 | this.assert( 1218 | true === flag(this, 'object') 1219 | , 'expected #{this} to be true' 1220 | , 'expected #{this} to be false' 1221 | , this.negate ? false : true 1222 | ); 1223 | }); 1224 | 1225 | /** 1226 | * ### .false 1227 | * 1228 | * Asserts that the target is `false`. 1229 | * 1230 | * expect(false).to.be.false; 1231 | * expect(0).to.not.be.false; 1232 | * 1233 | * @name false 1234 | * @api public 1235 | */ 1236 | 1237 | Assertion.addProperty('false', function () { 1238 | this.assert( 1239 | false === flag(this, 'object') 1240 | , 'expected #{this} to be false' 1241 | , 'expected #{this} to be true' 1242 | , this.negate ? true : false 1243 | ); 1244 | }); 1245 | 1246 | /** 1247 | * ### .null 1248 | * 1249 | * Asserts that the target is `null`. 1250 | * 1251 | * expect(null).to.be.null; 1252 | * expect(undefined).to.not.be.null; 1253 | * 1254 | * @name null 1255 | * @api public 1256 | */ 1257 | 1258 | Assertion.addProperty('null', function () { 1259 | this.assert( 1260 | null === flag(this, 'object') 1261 | , 'expected #{this} to be null' 1262 | , 'expected #{this} not to be null' 1263 | ); 1264 | }); 1265 | 1266 | /** 1267 | * ### .undefined 1268 | * 1269 | * Asserts that the target is `undefined`. 1270 | * 1271 | * expect(undefined).to.be.undefined; 1272 | * expect(null).to.not.be.undefined; 1273 | * 1274 | * @name undefined 1275 | * @api public 1276 | */ 1277 | 1278 | Assertion.addProperty('undefined', function () { 1279 | this.assert( 1280 | undefined === flag(this, 'object') 1281 | , 'expected #{this} to be undefined' 1282 | , 'expected #{this} not to be undefined' 1283 | ); 1284 | }); 1285 | 1286 | /** 1287 | * ### .exist 1288 | * 1289 | * Asserts that the target is neither `null` nor `undefined`. 1290 | * 1291 | * var foo = 'hi' 1292 | * , bar = null 1293 | * , baz; 1294 | * 1295 | * expect(foo).to.exist; 1296 | * expect(bar).to.not.exist; 1297 | * expect(baz).to.not.exist; 1298 | * 1299 | * @name exist 1300 | * @api public 1301 | */ 1302 | 1303 | Assertion.addProperty('exist', function () { 1304 | this.assert( 1305 | null != flag(this, 'object') 1306 | , 'expected #{this} to exist' 1307 | , 'expected #{this} to not exist' 1308 | ); 1309 | }); 1310 | 1311 | 1312 | /** 1313 | * ### .empty 1314 | * 1315 | * Asserts that the target's length is `0`. For arrays and strings, it checks 1316 | * the `length` property. For objects, it gets the count of 1317 | * enumerable keys. 1318 | * 1319 | * expect([]).to.be.empty; 1320 | * expect('').to.be.empty; 1321 | * expect({}).to.be.empty; 1322 | * 1323 | * @name empty 1324 | * @api public 1325 | */ 1326 | 1327 | Assertion.addProperty('empty', function () { 1328 | var obj = flag(this, 'object') 1329 | , expected = obj; 1330 | 1331 | if (Array.isArray(obj) || 'string' === typeof object) { 1332 | expected = obj.length; 1333 | } else if (typeof obj === 'object') { 1334 | expected = Object.keys(obj).length; 1335 | } 1336 | 1337 | this.assert( 1338 | !expected 1339 | , 'expected #{this} to be empty' 1340 | , 'expected #{this} not to be empty' 1341 | ); 1342 | }); 1343 | 1344 | /** 1345 | * ### .arguments 1346 | * 1347 | * Asserts that the target is an arguments object. 1348 | * 1349 | * function test () { 1350 | * expect(arguments).to.be.arguments; 1351 | * } 1352 | * 1353 | * @name arguments 1354 | * @alias Arguments 1355 | * @api public 1356 | */ 1357 | 1358 | function checkArguments () { 1359 | var obj = flag(this, 'object') 1360 | , type = Object.prototype.toString.call(obj); 1361 | this.assert( 1362 | '[object Arguments]' === type 1363 | , 'expected #{this} to be arguments but got ' + type 1364 | , 'expected #{this} to not be arguments' 1365 | ); 1366 | } 1367 | 1368 | Assertion.addProperty('arguments', checkArguments); 1369 | Assertion.addProperty('Arguments', checkArguments); 1370 | 1371 | /** 1372 | * ### .equal(value) 1373 | * 1374 | * Asserts that the target is strictly equal (`===`) to `value`. 1375 | * Alternately, if the `deep` flag is set, asserts that 1376 | * the target is deeply equal to `value`. 1377 | * 1378 | * expect('hello').to.equal('hello'); 1379 | * expect(42).to.equal(42); 1380 | * expect(1).to.not.equal(true); 1381 | * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); 1382 | * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); 1383 | * 1384 | * @name equal 1385 | * @alias equals 1386 | * @alias eq 1387 | * @alias deep.equal 1388 | * @param {Mixed} value 1389 | * @param {String} message _optional_ 1390 | * @api public 1391 | */ 1392 | 1393 | function assertEqual (val, msg) { 1394 | if (msg) flag(this, 'message', msg); 1395 | var obj = flag(this, 'object'); 1396 | if (flag(this, 'deep')) { 1397 | return this.eql(val); 1398 | } else { 1399 | this.assert( 1400 | val === obj 1401 | , 'expected #{this} to equal #{exp}' 1402 | , 'expected #{this} to not equal #{exp}' 1403 | , val 1404 | , this._obj 1405 | , true 1406 | ); 1407 | } 1408 | } 1409 | 1410 | Assertion.addMethod('equal', assertEqual); 1411 | Assertion.addMethod('equals', assertEqual); 1412 | Assertion.addMethod('eq', assertEqual); 1413 | 1414 | /** 1415 | * ### .eql(value) 1416 | * 1417 | * Asserts that the target is deeply equal to `value`. 1418 | * 1419 | * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); 1420 | * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); 1421 | * 1422 | * @name eql 1423 | * @alias eqls 1424 | * @param {Mixed} value 1425 | * @param {String} message _optional_ 1426 | * @api public 1427 | */ 1428 | 1429 | function assertEql(obj, msg) { 1430 | if (msg) flag(this, 'message', msg); 1431 | this.assert( 1432 | _.eql(obj, flag(this, 'object')) 1433 | , 'expected #{this} to deeply equal #{exp}' 1434 | , 'expected #{this} to not deeply equal #{exp}' 1435 | , obj 1436 | , this._obj 1437 | , true 1438 | ); 1439 | } 1440 | 1441 | Assertion.addMethod('eql', assertEql); 1442 | Assertion.addMethod('eqls', assertEql); 1443 | 1444 | /** 1445 | * ### .above(value) 1446 | * 1447 | * Asserts that the target is greater than `value`. 1448 | * 1449 | * expect(10).to.be.above(5); 1450 | * 1451 | * Can also be used in conjunction with `length` to 1452 | * assert a minimum length. The benefit being a 1453 | * more informative error message than if the length 1454 | * was supplied directly. 1455 | * 1456 | * expect('foo').to.have.length.above(2); 1457 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1458 | * 1459 | * @name above 1460 | * @alias gt 1461 | * @alias greaterThan 1462 | * @param {Number} value 1463 | * @param {String} message _optional_ 1464 | * @api public 1465 | */ 1466 | 1467 | function assertAbove (n, msg) { 1468 | if (msg) flag(this, 'message', msg); 1469 | var obj = flag(this, 'object'); 1470 | if (flag(this, 'doLength')) { 1471 | new Assertion(obj, msg).to.have.property('length'); 1472 | var len = obj.length; 1473 | this.assert( 1474 | len > n 1475 | , 'expected #{this} to have a length above #{exp} but got #{act}' 1476 | , 'expected #{this} to not have a length above #{exp}' 1477 | , n 1478 | , len 1479 | ); 1480 | } else { 1481 | this.assert( 1482 | obj > n 1483 | , 'expected #{this} to be above ' + n 1484 | , 'expected #{this} to be at most ' + n 1485 | ); 1486 | } 1487 | } 1488 | 1489 | Assertion.addMethod('above', assertAbove); 1490 | Assertion.addMethod('gt', assertAbove); 1491 | Assertion.addMethod('greaterThan', assertAbove); 1492 | 1493 | /** 1494 | * ### .least(value) 1495 | * 1496 | * Asserts that the target is greater than or equal to `value`. 1497 | * 1498 | * expect(10).to.be.at.least(10); 1499 | * 1500 | * Can also be used in conjunction with `length` to 1501 | * assert a minimum length. The benefit being a 1502 | * more informative error message than if the length 1503 | * was supplied directly. 1504 | * 1505 | * expect('foo').to.have.length.of.at.least(2); 1506 | * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); 1507 | * 1508 | * @name least 1509 | * @alias gte 1510 | * @param {Number} value 1511 | * @param {String} message _optional_ 1512 | * @api public 1513 | */ 1514 | 1515 | function assertLeast (n, msg) { 1516 | if (msg) flag(this, 'message', msg); 1517 | var obj = flag(this, 'object'); 1518 | if (flag(this, 'doLength')) { 1519 | new Assertion(obj, msg).to.have.property('length'); 1520 | var len = obj.length; 1521 | this.assert( 1522 | len >= n 1523 | , 'expected #{this} to have a length at least #{exp} but got #{act}' 1524 | , 'expected #{this} to have a length below #{exp}' 1525 | , n 1526 | , len 1527 | ); 1528 | } else { 1529 | this.assert( 1530 | obj >= n 1531 | , 'expected #{this} to be at least ' + n 1532 | , 'expected #{this} to be below ' + n 1533 | ); 1534 | } 1535 | } 1536 | 1537 | Assertion.addMethod('least', assertLeast); 1538 | Assertion.addMethod('gte', assertLeast); 1539 | 1540 | /** 1541 | * ### .below(value) 1542 | * 1543 | * Asserts that the target is less than `value`. 1544 | * 1545 | * expect(5).to.be.below(10); 1546 | * 1547 | * Can also be used in conjunction with `length` to 1548 | * assert a maximum length. The benefit being a 1549 | * more informative error message than if the length 1550 | * was supplied directly. 1551 | * 1552 | * expect('foo').to.have.length.below(4); 1553 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1554 | * 1555 | * @name below 1556 | * @alias lt 1557 | * @alias lessThan 1558 | * @param {Number} value 1559 | * @param {String} message _optional_ 1560 | * @api public 1561 | */ 1562 | 1563 | function assertBelow (n, msg) { 1564 | if (msg) flag(this, 'message', msg); 1565 | var obj = flag(this, 'object'); 1566 | if (flag(this, 'doLength')) { 1567 | new Assertion(obj, msg).to.have.property('length'); 1568 | var len = obj.length; 1569 | this.assert( 1570 | len < n 1571 | , 'expected #{this} to have a length below #{exp} but got #{act}' 1572 | , 'expected #{this} to not have a length below #{exp}' 1573 | , n 1574 | , len 1575 | ); 1576 | } else { 1577 | this.assert( 1578 | obj < n 1579 | , 'expected #{this} to be below ' + n 1580 | , 'expected #{this} to be at least ' + n 1581 | ); 1582 | } 1583 | } 1584 | 1585 | Assertion.addMethod('below', assertBelow); 1586 | Assertion.addMethod('lt', assertBelow); 1587 | Assertion.addMethod('lessThan', assertBelow); 1588 | 1589 | /** 1590 | * ### .most(value) 1591 | * 1592 | * Asserts that the target is less than or equal to `value`. 1593 | * 1594 | * expect(5).to.be.at.most(5); 1595 | * 1596 | * Can also be used in conjunction with `length` to 1597 | * assert a maximum length. The benefit being a 1598 | * more informative error message than if the length 1599 | * was supplied directly. 1600 | * 1601 | * expect('foo').to.have.length.of.at.most(4); 1602 | * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); 1603 | * 1604 | * @name most 1605 | * @alias lte 1606 | * @param {Number} value 1607 | * @param {String} message _optional_ 1608 | * @api public 1609 | */ 1610 | 1611 | function assertMost (n, msg) { 1612 | if (msg) flag(this, 'message', msg); 1613 | var obj = flag(this, 'object'); 1614 | if (flag(this, 'doLength')) { 1615 | new Assertion(obj, msg).to.have.property('length'); 1616 | var len = obj.length; 1617 | this.assert( 1618 | len <= n 1619 | , 'expected #{this} to have a length at most #{exp} but got #{act}' 1620 | , 'expected #{this} to have a length above #{exp}' 1621 | , n 1622 | , len 1623 | ); 1624 | } else { 1625 | this.assert( 1626 | obj <= n 1627 | , 'expected #{this} to be at most ' + n 1628 | , 'expected #{this} to be above ' + n 1629 | ); 1630 | } 1631 | } 1632 | 1633 | Assertion.addMethod('most', assertMost); 1634 | Assertion.addMethod('lte', assertMost); 1635 | 1636 | /** 1637 | * ### .within(start, finish) 1638 | * 1639 | * Asserts that the target is within a range. 1640 | * 1641 | * expect(7).to.be.within(5,10); 1642 | * 1643 | * Can also be used in conjunction with `length` to 1644 | * assert a length range. The benefit being a 1645 | * more informative error message than if the length 1646 | * was supplied directly. 1647 | * 1648 | * expect('foo').to.have.length.within(2,4); 1649 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1650 | * 1651 | * @name within 1652 | * @param {Number} start lowerbound inclusive 1653 | * @param {Number} finish upperbound inclusive 1654 | * @param {String} message _optional_ 1655 | * @api public 1656 | */ 1657 | 1658 | Assertion.addMethod('within', function (start, finish, msg) { 1659 | if (msg) flag(this, 'message', msg); 1660 | var obj = flag(this, 'object') 1661 | , range = start + '..' + finish; 1662 | if (flag(this, 'doLength')) { 1663 | new Assertion(obj, msg).to.have.property('length'); 1664 | var len = obj.length; 1665 | this.assert( 1666 | len >= start && len <= finish 1667 | , 'expected #{this} to have a length within ' + range 1668 | , 'expected #{this} to not have a length within ' + range 1669 | ); 1670 | } else { 1671 | this.assert( 1672 | obj >= start && obj <= finish 1673 | , 'expected #{this} to be within ' + range 1674 | , 'expected #{this} to not be within ' + range 1675 | ); 1676 | } 1677 | }); 1678 | 1679 | /** 1680 | * ### .instanceof(constructor) 1681 | * 1682 | * Asserts that the target is an instance of `constructor`. 1683 | * 1684 | * var Tea = function (name) { this.name = name; } 1685 | * , Chai = new Tea('chai'); 1686 | * 1687 | * expect(Chai).to.be.an.instanceof(Tea); 1688 | * expect([ 1, 2, 3 ]).to.be.instanceof(Array); 1689 | * 1690 | * @name instanceof 1691 | * @param {Constructor} constructor 1692 | * @param {String} message _optional_ 1693 | * @alias instanceOf 1694 | * @api public 1695 | */ 1696 | 1697 | function assertInstanceOf (constructor, msg) { 1698 | if (msg) flag(this, 'message', msg); 1699 | var name = _.getName(constructor); 1700 | this.assert( 1701 | flag(this, 'object') instanceof constructor 1702 | , 'expected #{this} to be an instance of ' + name 1703 | , 'expected #{this} to not be an instance of ' + name 1704 | ); 1705 | }; 1706 | 1707 | Assertion.addMethod('instanceof', assertInstanceOf); 1708 | Assertion.addMethod('instanceOf', assertInstanceOf); 1709 | 1710 | /** 1711 | * ### .property(name, [value]) 1712 | * 1713 | * Asserts that the target has a property `name`, optionally asserting that 1714 | * the value of that property is strictly equal to `value`. 1715 | * If the `deep` flag is set, you can use dot- and bracket-notation for deep 1716 | * references into objects and arrays. 1717 | * 1718 | * // simple referencing 1719 | * var obj = { foo: 'bar' }; 1720 | * expect(obj).to.have.property('foo'); 1721 | * expect(obj).to.have.property('foo', 'bar'); 1722 | * 1723 | * // deep referencing 1724 | * var deepObj = { 1725 | * green: { tea: 'matcha' } 1726 | * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] 1727 | * }; 1728 | * 1729 | * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); 1730 | * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); 1731 | * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); 1732 | * 1733 | * You can also use an array as the starting point of a `deep.property` 1734 | * assertion, or traverse nested arrays. 1735 | * 1736 | * var arr = [ 1737 | * [ 'chai', 'matcha', 'konacha' ] 1738 | * , [ { tea: 'chai' } 1739 | * , { tea: 'matcha' } 1740 | * , { tea: 'konacha' } ] 1741 | * ]; 1742 | * 1743 | * expect(arr).to.have.deep.property('[0][1]', 'matcha'); 1744 | * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); 1745 | * 1746 | * Furthermore, `property` changes the subject of the assertion 1747 | * to be the value of that property from the original object. This 1748 | * permits for further chainable assertions on that property. 1749 | * 1750 | * expect(obj).to.have.property('foo') 1751 | * .that.is.a('string'); 1752 | * expect(deepObj).to.have.property('green') 1753 | * .that.is.an('object') 1754 | * .that.deep.equals({ tea: 'matcha' }); 1755 | * expect(deepObj).to.have.property('teas') 1756 | * .that.is.an('array') 1757 | * .with.deep.property('[2]') 1758 | * .that.deep.equals({ tea: 'konacha' }); 1759 | * 1760 | * Note that dots and bracket in `name` must be backslash-escaped when 1761 | * the `deep` flag is set, while they must NOT be escaped when the `deep` 1762 | * flag is not set. 1763 | * 1764 | * // simple referencing 1765 | * var css = { '.link[target]': 42 }; 1766 | * expect(css).to.have.property('.link[target]', 42); 1767 | * 1768 | * // deep referencing 1769 | * var deepCss = { '.link': { '[target]': 42 }}; 1770 | * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); 1771 | * 1772 | * @name property 1773 | * @alias deep.property 1774 | * @param {String} name 1775 | * @param {Mixed} value (optional) 1776 | * @param {String} message _optional_ 1777 | * @returns value of property for chaining 1778 | * @api public 1779 | */ 1780 | 1781 | Assertion.addMethod('property', function (name, val, msg) { 1782 | if (msg) flag(this, 'message', msg); 1783 | 1784 | var isDeep = !!flag(this, 'deep') 1785 | , descriptor = isDeep ? 'deep property ' : 'property ' 1786 | , negate = flag(this, 'negate') 1787 | , obj = flag(this, 'object') 1788 | , pathInfo = isDeep ? _.getPathInfo(name, obj) : null 1789 | , hasProperty = isDeep 1790 | ? pathInfo.exists 1791 | : _.hasProperty(name, obj) 1792 | , value = isDeep 1793 | ? pathInfo.value 1794 | : obj[name]; 1795 | 1796 | if (negate && undefined !== val) { 1797 | if (undefined === value) { 1798 | msg = (msg != null) ? msg + ': ' : ''; 1799 | throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); 1800 | } 1801 | } else { 1802 | this.assert( 1803 | hasProperty 1804 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) 1805 | , 'expected #{this} to not have ' + descriptor + _.inspect(name)); 1806 | } 1807 | 1808 | if (undefined !== val) { 1809 | this.assert( 1810 | val === value 1811 | , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' 1812 | , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' 1813 | , val 1814 | , value 1815 | ); 1816 | } 1817 | 1818 | flag(this, 'object', value); 1819 | }); 1820 | 1821 | 1822 | /** 1823 | * ### .ownProperty(name) 1824 | * 1825 | * Asserts that the target has an own property `name`. 1826 | * 1827 | * expect('test').to.have.ownProperty('length'); 1828 | * 1829 | * @name ownProperty 1830 | * @alias haveOwnProperty 1831 | * @param {String} name 1832 | * @param {String} message _optional_ 1833 | * @api public 1834 | */ 1835 | 1836 | function assertOwnProperty (name, msg) { 1837 | if (msg) flag(this, 'message', msg); 1838 | var obj = flag(this, 'object'); 1839 | this.assert( 1840 | obj.hasOwnProperty(name) 1841 | , 'expected #{this} to have own property ' + _.inspect(name) 1842 | , 'expected #{this} to not have own property ' + _.inspect(name) 1843 | ); 1844 | } 1845 | 1846 | Assertion.addMethod('ownProperty', assertOwnProperty); 1847 | Assertion.addMethod('haveOwnProperty', assertOwnProperty); 1848 | 1849 | /** 1850 | * ### .ownPropertyDescriptor(name[, descriptor[, message]]) 1851 | * 1852 | * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. 1853 | * 1854 | * expect('test').to.have.ownPropertyDescriptor('length'); 1855 | * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); 1856 | * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); 1857 | * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); 1858 | * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); 1859 | * 1860 | * @name ownPropertyDescriptor 1861 | * @alias haveOwnPropertyDescriptor 1862 | * @param {String} name 1863 | * @param {Object} descriptor _optional_ 1864 | * @param {String} message _optional_ 1865 | * @api public 1866 | */ 1867 | 1868 | function assertOwnPropertyDescriptor (name, descriptor, msg) { 1869 | if (typeof descriptor === 'string') { 1870 | msg = descriptor; 1871 | descriptor = null; 1872 | } 1873 | if (msg) flag(this, 'message', msg); 1874 | var obj = flag(this, 'object'); 1875 | var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); 1876 | if (actualDescriptor && descriptor) { 1877 | this.assert( 1878 | _.eql(descriptor, actualDescriptor) 1879 | , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) 1880 | , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) 1881 | , descriptor 1882 | , actualDescriptor 1883 | , true 1884 | ); 1885 | } else { 1886 | this.assert( 1887 | actualDescriptor 1888 | , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) 1889 | , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) 1890 | ); 1891 | } 1892 | flag(this, 'object', actualDescriptor); 1893 | } 1894 | 1895 | Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); 1896 | Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); 1897 | 1898 | /** 1899 | * ### .length(value) 1900 | * 1901 | * Asserts that the target's `length` property has 1902 | * the expected value. 1903 | * 1904 | * expect([ 1, 2, 3]).to.have.length(3); 1905 | * expect('foobar').to.have.length(6); 1906 | * 1907 | * Can also be used as a chain precursor to a value 1908 | * comparison for the length property. 1909 | * 1910 | * expect('foo').to.have.length.above(2); 1911 | * expect([ 1, 2, 3 ]).to.have.length.above(2); 1912 | * expect('foo').to.have.length.below(4); 1913 | * expect([ 1, 2, 3 ]).to.have.length.below(4); 1914 | * expect('foo').to.have.length.within(2,4); 1915 | * expect([ 1, 2, 3 ]).to.have.length.within(2,4); 1916 | * 1917 | * @name length 1918 | * @alias lengthOf 1919 | * @param {Number} length 1920 | * @param {String} message _optional_ 1921 | * @api public 1922 | */ 1923 | 1924 | function assertLengthChain () { 1925 | flag(this, 'doLength', true); 1926 | } 1927 | 1928 | function assertLength (n, msg) { 1929 | if (msg) flag(this, 'message', msg); 1930 | var obj = flag(this, 'object'); 1931 | new Assertion(obj, msg).to.have.property('length'); 1932 | var len = obj.length; 1933 | 1934 | this.assert( 1935 | len == n 1936 | , 'expected #{this} to have a length of #{exp} but got #{act}' 1937 | , 'expected #{this} to not have a length of #{act}' 1938 | , n 1939 | , len 1940 | ); 1941 | } 1942 | 1943 | Assertion.addChainableMethod('length', assertLength, assertLengthChain); 1944 | Assertion.addMethod('lengthOf', assertLength); 1945 | 1946 | /** 1947 | * ### .match(regexp) 1948 | * 1949 | * Asserts that the target matches a regular expression. 1950 | * 1951 | * expect('foobar').to.match(/^foo/); 1952 | * 1953 | * @name match 1954 | * @param {RegExp} RegularExpression 1955 | * @param {String} message _optional_ 1956 | * @api public 1957 | */ 1958 | 1959 | Assertion.addMethod('match', function (re, msg) { 1960 | if (msg) flag(this, 'message', msg); 1961 | var obj = flag(this, 'object'); 1962 | this.assert( 1963 | re.exec(obj) 1964 | , 'expected #{this} to match ' + re 1965 | , 'expected #{this} not to match ' + re 1966 | ); 1967 | }); 1968 | 1969 | /** 1970 | * ### .string(string) 1971 | * 1972 | * Asserts that the string target contains another string. 1973 | * 1974 | * expect('foobar').to.have.string('bar'); 1975 | * 1976 | * @name string 1977 | * @param {String} string 1978 | * @param {String} message _optional_ 1979 | * @api public 1980 | */ 1981 | 1982 | Assertion.addMethod('string', function (str, msg) { 1983 | if (msg) flag(this, 'message', msg); 1984 | var obj = flag(this, 'object'); 1985 | new Assertion(obj, msg).is.a('string'); 1986 | 1987 | this.assert( 1988 | ~obj.indexOf(str) 1989 | , 'expected #{this} to contain ' + _.inspect(str) 1990 | , 'expected #{this} to not contain ' + _.inspect(str) 1991 | ); 1992 | }); 1993 | 1994 | 1995 | /** 1996 | * ### .keys(key1, [key2], [...]) 1997 | * 1998 | * Asserts that the target contains any or all of the passed-in keys. 1999 | * Use in combination with `any`, `all`, `contains`, or `have` will affect 2000 | * what will pass. 2001 | * 2002 | * When used in conjunction with `any`, at least one key that is passed 2003 | * in must exist in the target object. This is regardless whether or not 2004 | * the `have` or `contain` qualifiers are used. Note, either `any` or `all` 2005 | * should be used in the assertion. If neither are used, the assertion is 2006 | * defaulted to `all`. 2007 | * 2008 | * When both `all` and `contain` are used, the target object must have at 2009 | * least all of the passed-in keys but may have more keys not listed. 2010 | * 2011 | * When both `all` and `have` are used, the target object must both contain 2012 | * all of the passed-in keys AND the number of keys in the target object must 2013 | * match the number of keys passed in (in other words, a target object must 2014 | * have all and only all of the passed-in keys). 2015 | * 2016 | * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); 2017 | * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); 2018 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); 2019 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); 2020 | * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); 2021 | * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); 2022 | * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); 2023 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); 2024 | * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys([{'bar': 6}}]); 2025 | * 2026 | * 2027 | * @name keys 2028 | * @alias key 2029 | * @param {String...|Array|Object} keys 2030 | * @api public 2031 | */ 2032 | 2033 | function assertKeys (keys) { 2034 | var obj = flag(this, 'object') 2035 | , str 2036 | , ok = true 2037 | , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; 2038 | 2039 | switch (_.type(keys)) { 2040 | case "array": 2041 | if (arguments.length > 1) throw (new Error(mixedArgsMsg)); 2042 | break; 2043 | case "object": 2044 | if (arguments.length > 1) throw (new Error(mixedArgsMsg)); 2045 | keys = Object.keys(keys); 2046 | break; 2047 | default: 2048 | keys = Array.prototype.slice.call(arguments); 2049 | } 2050 | 2051 | if (!keys.length) throw new Error('keys required'); 2052 | 2053 | var actual = Object.keys(obj) 2054 | , expected = keys 2055 | , len = keys.length 2056 | , any = flag(this, 'any') 2057 | , all = flag(this, 'all'); 2058 | 2059 | if (!any && !all) { 2060 | all = true; 2061 | } 2062 | 2063 | // Has any 2064 | if (any) { 2065 | var intersection = expected.filter(function(key) { 2066 | return ~actual.indexOf(key); 2067 | }); 2068 | ok = intersection.length > 0; 2069 | } 2070 | 2071 | // Has all 2072 | if (all) { 2073 | ok = keys.every(function(key){ 2074 | return ~actual.indexOf(key); 2075 | }); 2076 | if (!flag(this, 'negate') && !flag(this, 'contains')) { 2077 | ok = ok && keys.length == actual.length; 2078 | } 2079 | } 2080 | 2081 | // Key string 2082 | if (len > 1) { 2083 | keys = keys.map(function(key){ 2084 | return _.inspect(key); 2085 | }); 2086 | var last = keys.pop(); 2087 | if (all) { 2088 | str = keys.join(', ') + ', and ' + last; 2089 | } 2090 | if (any) { 2091 | str = keys.join(', ') + ', or ' + last; 2092 | } 2093 | } else { 2094 | str = _.inspect(keys[0]); 2095 | } 2096 | 2097 | // Form 2098 | str = (len > 1 ? 'keys ' : 'key ') + str; 2099 | 2100 | // Have / include 2101 | str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; 2102 | 2103 | // Assertion 2104 | this.assert( 2105 | ok 2106 | , 'expected #{this} to ' + str 2107 | , 'expected #{this} to not ' + str 2108 | , expected.slice(0).sort() 2109 | , actual.sort() 2110 | , true 2111 | ); 2112 | } 2113 | 2114 | Assertion.addMethod('keys', assertKeys); 2115 | Assertion.addMethod('key', assertKeys); 2116 | 2117 | /** 2118 | * ### .throw(constructor) 2119 | * 2120 | * Asserts that the function target will throw a specific error, or specific type of error 2121 | * (as determined using `instanceof`), optionally with a RegExp or string inclusion test 2122 | * for the error's message. 2123 | * 2124 | * var err = new ReferenceError('This is a bad function.'); 2125 | * var fn = function () { throw err; } 2126 | * expect(fn).to.throw(ReferenceError); 2127 | * expect(fn).to.throw(Error); 2128 | * expect(fn).to.throw(/bad function/); 2129 | * expect(fn).to.not.throw('good function'); 2130 | * expect(fn).to.throw(ReferenceError, /bad function/); 2131 | * expect(fn).to.throw(err); 2132 | * expect(fn).to.not.throw(new RangeError('Out of range.')); 2133 | * 2134 | * Please note that when a throw expectation is negated, it will check each 2135 | * parameter independently, starting with error constructor type. The appropriate way 2136 | * to check for the existence of a type of error but for a message that does not match 2137 | * is to use `and`. 2138 | * 2139 | * expect(fn).to.throw(ReferenceError) 2140 | * .and.not.throw(/good function/); 2141 | * 2142 | * @name throw 2143 | * @alias throws 2144 | * @alias Throw 2145 | * @param {ErrorConstructor} constructor 2146 | * @param {String|RegExp} expected error message 2147 | * @param {String} message _optional_ 2148 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 2149 | * @returns error for chaining (null if no error) 2150 | * @api public 2151 | */ 2152 | 2153 | function assertThrows (constructor, errMsg, msg) { 2154 | if (msg) flag(this, 'message', msg); 2155 | var obj = flag(this, 'object'); 2156 | new Assertion(obj, msg).is.a('function'); 2157 | 2158 | var thrown = false 2159 | , desiredError = null 2160 | , name = null 2161 | , thrownError = null; 2162 | 2163 | if (arguments.length === 0) { 2164 | errMsg = null; 2165 | constructor = null; 2166 | } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { 2167 | errMsg = constructor; 2168 | constructor = null; 2169 | } else if (constructor && constructor instanceof Error) { 2170 | desiredError = constructor; 2171 | constructor = null; 2172 | errMsg = null; 2173 | } else if (typeof constructor === 'function') { 2174 | name = constructor.prototype.name || constructor.name; 2175 | if (name === 'Error' && constructor !== Error) { 2176 | name = (new constructor()).name; 2177 | } 2178 | } else { 2179 | constructor = null; 2180 | } 2181 | 2182 | try { 2183 | obj(); 2184 | } catch (err) { 2185 | // first, check desired error 2186 | if (desiredError) { 2187 | this.assert( 2188 | err === desiredError 2189 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 2190 | , 'expected #{this} to not throw #{exp}' 2191 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 2192 | , (err instanceof Error ? err.toString() : err) 2193 | ); 2194 | 2195 | flag(this, 'object', err); 2196 | return this; 2197 | } 2198 | 2199 | // next, check constructor 2200 | if (constructor) { 2201 | this.assert( 2202 | err instanceof constructor 2203 | , 'expected #{this} to throw #{exp} but #{act} was thrown' 2204 | , 'expected #{this} to not throw #{exp} but #{act} was thrown' 2205 | , name 2206 | , (err instanceof Error ? err.toString() : err) 2207 | ); 2208 | 2209 | if (!errMsg) { 2210 | flag(this, 'object', err); 2211 | return this; 2212 | } 2213 | } 2214 | 2215 | // next, check message 2216 | var message = 'object' === _.type(err) && "message" in err 2217 | ? err.message 2218 | : '' + err; 2219 | 2220 | if ((message != null) && errMsg && errMsg instanceof RegExp) { 2221 | this.assert( 2222 | errMsg.exec(message) 2223 | , 'expected #{this} to throw error matching #{exp} but got #{act}' 2224 | , 'expected #{this} to throw error not matching #{exp}' 2225 | , errMsg 2226 | , message 2227 | ); 2228 | 2229 | flag(this, 'object', err); 2230 | return this; 2231 | } else if ((message != null) && errMsg && 'string' === typeof errMsg) { 2232 | this.assert( 2233 | ~message.indexOf(errMsg) 2234 | , 'expected #{this} to throw error including #{exp} but got #{act}' 2235 | , 'expected #{this} to throw error not including #{act}' 2236 | , errMsg 2237 | , message 2238 | ); 2239 | 2240 | flag(this, 'object', err); 2241 | return this; 2242 | } else { 2243 | thrown = true; 2244 | thrownError = err; 2245 | } 2246 | } 2247 | 2248 | var actuallyGot = '' 2249 | , expectedThrown = name !== null 2250 | ? name 2251 | : desiredError 2252 | ? '#{exp}' //_.inspect(desiredError) 2253 | : 'an error'; 2254 | 2255 | if (thrown) { 2256 | actuallyGot = ' but #{act} was thrown' 2257 | } 2258 | 2259 | this.assert( 2260 | thrown === true 2261 | , 'expected #{this} to throw ' + expectedThrown + actuallyGot 2262 | , 'expected #{this} to not throw ' + expectedThrown + actuallyGot 2263 | , (desiredError instanceof Error ? desiredError.toString() : desiredError) 2264 | , (thrownError instanceof Error ? thrownError.toString() : thrownError) 2265 | ); 2266 | 2267 | flag(this, 'object', thrownError); 2268 | }; 2269 | 2270 | Assertion.addMethod('throw', assertThrows); 2271 | Assertion.addMethod('throws', assertThrows); 2272 | Assertion.addMethod('Throw', assertThrows); 2273 | 2274 | /** 2275 | * ### .respondTo(method) 2276 | * 2277 | * Asserts that the object or class target will respond to a method. 2278 | * 2279 | * Klass.prototype.bar = function(){}; 2280 | * expect(Klass).to.respondTo('bar'); 2281 | * expect(obj).to.respondTo('bar'); 2282 | * 2283 | * To check if a constructor will respond to a static function, 2284 | * set the `itself` flag. 2285 | * 2286 | * Klass.baz = function(){}; 2287 | * expect(Klass).itself.to.respondTo('baz'); 2288 | * 2289 | * @name respondTo 2290 | * @param {String} method 2291 | * @param {String} message _optional_ 2292 | * @api public 2293 | */ 2294 | 2295 | Assertion.addMethod('respondTo', function (method, msg) { 2296 | if (msg) flag(this, 'message', msg); 2297 | var obj = flag(this, 'object') 2298 | , itself = flag(this, 'itself') 2299 | , context = ('function' === _.type(obj) && !itself) 2300 | ? obj.prototype[method] 2301 | : obj[method]; 2302 | 2303 | this.assert( 2304 | 'function' === typeof context 2305 | , 'expected #{this} to respond to ' + _.inspect(method) 2306 | , 'expected #{this} to not respond to ' + _.inspect(method) 2307 | ); 2308 | }); 2309 | 2310 | /** 2311 | * ### .itself 2312 | * 2313 | * Sets the `itself` flag, later used by the `respondTo` assertion. 2314 | * 2315 | * function Foo() {} 2316 | * Foo.bar = function() {} 2317 | * Foo.prototype.baz = function() {} 2318 | * 2319 | * expect(Foo).itself.to.respondTo('bar'); 2320 | * expect(Foo).itself.not.to.respondTo('baz'); 2321 | * 2322 | * @name itself 2323 | * @api public 2324 | */ 2325 | 2326 | Assertion.addProperty('itself', function () { 2327 | flag(this, 'itself', true); 2328 | }); 2329 | 2330 | /** 2331 | * ### .satisfy(method) 2332 | * 2333 | * Asserts that the target passes a given truth test. 2334 | * 2335 | * expect(1).to.satisfy(function(num) { return num > 0; }); 2336 | * 2337 | * @name satisfy 2338 | * @param {Function} matcher 2339 | * @param {String} message _optional_ 2340 | * @api public 2341 | */ 2342 | 2343 | Assertion.addMethod('satisfy', function (matcher, msg) { 2344 | if (msg) flag(this, 'message', msg); 2345 | var obj = flag(this, 'object'); 2346 | var result = matcher(obj); 2347 | this.assert( 2348 | result 2349 | , 'expected #{this} to satisfy ' + _.objDisplay(matcher) 2350 | , 'expected #{this} to not satisfy' + _.objDisplay(matcher) 2351 | , this.negate ? false : true 2352 | , result 2353 | ); 2354 | }); 2355 | 2356 | /** 2357 | * ### .closeTo(expected, delta) 2358 | * 2359 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 2360 | * 2361 | * expect(1.5).to.be.closeTo(1, 0.5); 2362 | * 2363 | * @name closeTo 2364 | * @param {Number} expected 2365 | * @param {Number} delta 2366 | * @param {String} message _optional_ 2367 | * @api public 2368 | */ 2369 | 2370 | Assertion.addMethod('closeTo', function (expected, delta, msg) { 2371 | if (msg) flag(this, 'message', msg); 2372 | var obj = flag(this, 'object'); 2373 | 2374 | new Assertion(obj, msg).is.a('number'); 2375 | if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { 2376 | throw new Error('the arguments to closeTo must be numbers'); 2377 | } 2378 | 2379 | this.assert( 2380 | Math.abs(obj - expected) <= delta 2381 | , 'expected #{this} to be close to ' + expected + ' +/- ' + delta 2382 | , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta 2383 | ); 2384 | }); 2385 | 2386 | function isSubsetOf(subset, superset, cmp) { 2387 | return subset.every(function(elem) { 2388 | if (!cmp) return superset.indexOf(elem) !== -1; 2389 | 2390 | return superset.some(function(elem2) { 2391 | return cmp(elem, elem2); 2392 | }); 2393 | }) 2394 | } 2395 | 2396 | /** 2397 | * ### .members(set) 2398 | * 2399 | * Asserts that the target is a superset of `set`, 2400 | * or that the target and `set` have the same strictly-equal (===) members. 2401 | * Alternately, if the `deep` flag is set, set members are compared for deep 2402 | * equality. 2403 | * 2404 | * expect([1, 2, 3]).to.include.members([3, 2]); 2405 | * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); 2406 | * 2407 | * expect([4, 2]).to.have.members([2, 4]); 2408 | * expect([5, 2]).to.not.have.members([5, 2, 1]); 2409 | * 2410 | * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); 2411 | * 2412 | * @name members 2413 | * @param {Array} set 2414 | * @param {String} message _optional_ 2415 | * @api public 2416 | */ 2417 | 2418 | Assertion.addMethod('members', function (subset, msg) { 2419 | if (msg) flag(this, 'message', msg); 2420 | var obj = flag(this, 'object'); 2421 | 2422 | new Assertion(obj).to.be.an('array'); 2423 | new Assertion(subset).to.be.an('array'); 2424 | 2425 | var cmp = flag(this, 'deep') ? _.eql : undefined; 2426 | 2427 | if (flag(this, 'contains')) { 2428 | return this.assert( 2429 | isSubsetOf(subset, obj, cmp) 2430 | , 'expected #{this} to be a superset of #{act}' 2431 | , 'expected #{this} to not be a superset of #{act}' 2432 | , obj 2433 | , subset 2434 | ); 2435 | } 2436 | 2437 | this.assert( 2438 | isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) 2439 | , 'expected #{this} to have the same members as #{act}' 2440 | , 'expected #{this} to not have the same members as #{act}' 2441 | , obj 2442 | , subset 2443 | ); 2444 | }); 2445 | 2446 | /** 2447 | * ### .change(function) 2448 | * 2449 | * Asserts that a function changes an object property 2450 | * 2451 | * var obj = { val: 10 }; 2452 | * var fn = function() { obj.val += 3 }; 2453 | * var noChangeFn = function() { return 'foo' + 'bar'; } 2454 | * expect(fn).to.change(obj, 'val'); 2455 | * expect(noChangFn).to.not.change(obj, 'val') 2456 | * 2457 | * @name change 2458 | * @alias changes 2459 | * @alias Change 2460 | * @param {String} object 2461 | * @param {String} property name 2462 | * @param {String} message _optional_ 2463 | * @api public 2464 | */ 2465 | 2466 | function assertChanges (object, prop, msg) { 2467 | if (msg) flag(this, 'message', msg); 2468 | var fn = flag(this, 'object'); 2469 | new Assertion(object, msg).to.have.property(prop); 2470 | new Assertion(fn).is.a('function'); 2471 | 2472 | var initial = object[prop]; 2473 | fn(); 2474 | 2475 | this.assert( 2476 | initial !== object[prop] 2477 | , 'expected .' + prop + ' to change' 2478 | , 'expected .' + prop + ' to not change' 2479 | ); 2480 | } 2481 | 2482 | Assertion.addChainableMethod('change', assertChanges); 2483 | Assertion.addChainableMethod('changes', assertChanges); 2484 | 2485 | /** 2486 | * ### .increase(function) 2487 | * 2488 | * Asserts that a function increases an object property 2489 | * 2490 | * var obj = { val: 10 }; 2491 | * var fn = function() { obj.val = 15 }; 2492 | * expect(fn).to.increase(obj, 'val'); 2493 | * 2494 | * @name increase 2495 | * @alias increases 2496 | * @alias Increase 2497 | * @param {String} object 2498 | * @param {String} property name 2499 | * @param {String} message _optional_ 2500 | * @api public 2501 | */ 2502 | 2503 | function assertIncreases (object, prop, msg) { 2504 | if (msg) flag(this, 'message', msg); 2505 | var fn = flag(this, 'object'); 2506 | new Assertion(object, msg).to.have.property(prop); 2507 | new Assertion(fn).is.a('function'); 2508 | 2509 | var initial = object[prop]; 2510 | fn(); 2511 | 2512 | this.assert( 2513 | object[prop] - initial > 0 2514 | , 'expected .' + prop + ' to increase' 2515 | , 'expected .' + prop + ' to not increase' 2516 | ); 2517 | } 2518 | 2519 | Assertion.addChainableMethod('increase', assertIncreases); 2520 | Assertion.addChainableMethod('increases', assertIncreases); 2521 | 2522 | /** 2523 | * ### .decrease(function) 2524 | * 2525 | * Asserts that a function decreases an object property 2526 | * 2527 | * var obj = { val: 10 }; 2528 | * var fn = function() { obj.val = 5 }; 2529 | * expect(fn).to.decrease(obj, 'val'); 2530 | * 2531 | * @name decrease 2532 | * @alias decreases 2533 | * @alias Decrease 2534 | * @param {String} object 2535 | * @param {String} property name 2536 | * @param {String} message _optional_ 2537 | * @api public 2538 | */ 2539 | 2540 | function assertDecreases (object, prop, msg) { 2541 | if (msg) flag(this, 'message', msg); 2542 | var fn = flag(this, 'object'); 2543 | new Assertion(object, msg).to.have.property(prop); 2544 | new Assertion(fn).is.a('function'); 2545 | 2546 | var initial = object[prop]; 2547 | fn(); 2548 | 2549 | this.assert( 2550 | object[prop] - initial < 0 2551 | , 'expected .' + prop + ' to decrease' 2552 | , 'expected .' + prop + ' to not decrease' 2553 | ); 2554 | } 2555 | 2556 | Assertion.addChainableMethod('decrease', assertDecreases); 2557 | Assertion.addChainableMethod('decreases', assertDecreases); 2558 | 2559 | }; 2560 | 2561 | }); 2562 | 2563 | require.register("chai/lib/chai/interface/assert.js", function (exports, module) { 2564 | /*! 2565 | * chai 2566 | * Copyright(c) 2011-2014 Jake Luer 2567 | * MIT Licensed 2568 | */ 2569 | 2570 | 2571 | module.exports = function (chai, util) { 2572 | 2573 | /*! 2574 | * Chai dependencies. 2575 | */ 2576 | 2577 | var Assertion = chai.Assertion 2578 | , flag = util.flag; 2579 | 2580 | /*! 2581 | * Module export. 2582 | */ 2583 | 2584 | /** 2585 | * ### assert(expression, message) 2586 | * 2587 | * Write your own test expressions. 2588 | * 2589 | * assert('foo' !== 'bar', 'foo is not bar'); 2590 | * assert(Array.isArray([]), 'empty arrays are arrays'); 2591 | * 2592 | * @param {Mixed} expression to test for truthiness 2593 | * @param {String} message to display on error 2594 | * @name assert 2595 | * @api public 2596 | */ 2597 | 2598 | var assert = chai.assert = function (express, errmsg) { 2599 | var test = new Assertion(null, null, chai.assert); 2600 | test.assert( 2601 | express 2602 | , errmsg 2603 | , '[ negation message unavailable ]' 2604 | ); 2605 | }; 2606 | 2607 | /** 2608 | * ### .fail(actual, expected, [message], [operator]) 2609 | * 2610 | * Throw a failure. Node.js `assert` module-compatible. 2611 | * 2612 | * @name fail 2613 | * @param {Mixed} actual 2614 | * @param {Mixed} expected 2615 | * @param {String} message 2616 | * @param {String} operator 2617 | * @api public 2618 | */ 2619 | 2620 | assert.fail = function (actual, expected, message, operator) { 2621 | message = message || 'assert.fail()'; 2622 | throw new chai.AssertionError(message, { 2623 | actual: actual 2624 | , expected: expected 2625 | , operator: operator 2626 | }, assert.fail); 2627 | }; 2628 | 2629 | /** 2630 | * ### .ok(object, [message]) 2631 | * 2632 | * Asserts that `object` is truthy. 2633 | * 2634 | * assert.ok('everything', 'everything is ok'); 2635 | * assert.ok(false, 'this will fail'); 2636 | * 2637 | * @name ok 2638 | * @param {Mixed} object to test 2639 | * @param {String} message 2640 | * @api public 2641 | */ 2642 | 2643 | assert.ok = function (val, msg) { 2644 | new Assertion(val, msg).is.ok; 2645 | }; 2646 | 2647 | /** 2648 | * ### .notOk(object, [message]) 2649 | * 2650 | * Asserts that `object` is falsy. 2651 | * 2652 | * assert.notOk('everything', 'this will fail'); 2653 | * assert.notOk(false, 'this will pass'); 2654 | * 2655 | * @name notOk 2656 | * @param {Mixed} object to test 2657 | * @param {String} message 2658 | * @api public 2659 | */ 2660 | 2661 | assert.notOk = function (val, msg) { 2662 | new Assertion(val, msg).is.not.ok; 2663 | }; 2664 | 2665 | /** 2666 | * ### .equal(actual, expected, [message]) 2667 | * 2668 | * Asserts non-strict equality (`==`) of `actual` and `expected`. 2669 | * 2670 | * assert.equal(3, '3', '== coerces values to strings'); 2671 | * 2672 | * @name equal 2673 | * @param {Mixed} actual 2674 | * @param {Mixed} expected 2675 | * @param {String} message 2676 | * @api public 2677 | */ 2678 | 2679 | assert.equal = function (act, exp, msg) { 2680 | var test = new Assertion(act, msg, assert.equal); 2681 | 2682 | test.assert( 2683 | exp == flag(test, 'object') 2684 | , 'expected #{this} to equal #{exp}' 2685 | , 'expected #{this} to not equal #{act}' 2686 | , exp 2687 | , act 2688 | ); 2689 | }; 2690 | 2691 | /** 2692 | * ### .notEqual(actual, expected, [message]) 2693 | * 2694 | * Asserts non-strict inequality (`!=`) of `actual` and `expected`. 2695 | * 2696 | * assert.notEqual(3, 4, 'these numbers are not equal'); 2697 | * 2698 | * @name notEqual 2699 | * @param {Mixed} actual 2700 | * @param {Mixed} expected 2701 | * @param {String} message 2702 | * @api public 2703 | */ 2704 | 2705 | assert.notEqual = function (act, exp, msg) { 2706 | var test = new Assertion(act, msg, assert.notEqual); 2707 | 2708 | test.assert( 2709 | exp != flag(test, 'object') 2710 | , 'expected #{this} to not equal #{exp}' 2711 | , 'expected #{this} to equal #{act}' 2712 | , exp 2713 | , act 2714 | ); 2715 | }; 2716 | 2717 | /** 2718 | * ### .strictEqual(actual, expected, [message]) 2719 | * 2720 | * Asserts strict equality (`===`) of `actual` and `expected`. 2721 | * 2722 | * assert.strictEqual(true, true, 'these booleans are strictly equal'); 2723 | * 2724 | * @name strictEqual 2725 | * @param {Mixed} actual 2726 | * @param {Mixed} expected 2727 | * @param {String} message 2728 | * @api public 2729 | */ 2730 | 2731 | assert.strictEqual = function (act, exp, msg) { 2732 | new Assertion(act, msg).to.equal(exp); 2733 | }; 2734 | 2735 | /** 2736 | * ### .notStrictEqual(actual, expected, [message]) 2737 | * 2738 | * Asserts strict inequality (`!==`) of `actual` and `expected`. 2739 | * 2740 | * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); 2741 | * 2742 | * @name notStrictEqual 2743 | * @param {Mixed} actual 2744 | * @param {Mixed} expected 2745 | * @param {String} message 2746 | * @api public 2747 | */ 2748 | 2749 | assert.notStrictEqual = function (act, exp, msg) { 2750 | new Assertion(act, msg).to.not.equal(exp); 2751 | }; 2752 | 2753 | /** 2754 | * ### .deepEqual(actual, expected, [message]) 2755 | * 2756 | * Asserts that `actual` is deeply equal to `expected`. 2757 | * 2758 | * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); 2759 | * 2760 | * @name deepEqual 2761 | * @param {Mixed} actual 2762 | * @param {Mixed} expected 2763 | * @param {String} message 2764 | * @api public 2765 | */ 2766 | 2767 | assert.deepEqual = function (act, exp, msg) { 2768 | new Assertion(act, msg).to.eql(exp); 2769 | }; 2770 | 2771 | /** 2772 | * ### .notDeepEqual(actual, expected, [message]) 2773 | * 2774 | * Assert that `actual` is not deeply equal to `expected`. 2775 | * 2776 | * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); 2777 | * 2778 | * @name notDeepEqual 2779 | * @param {Mixed} actual 2780 | * @param {Mixed} expected 2781 | * @param {String} message 2782 | * @api public 2783 | */ 2784 | 2785 | assert.notDeepEqual = function (act, exp, msg) { 2786 | new Assertion(act, msg).to.not.eql(exp); 2787 | }; 2788 | 2789 | /** 2790 | * ### .isTrue(value, [message]) 2791 | * 2792 | * Asserts that `value` is true. 2793 | * 2794 | * var teaServed = true; 2795 | * assert.isTrue(teaServed, 'the tea has been served'); 2796 | * 2797 | * @name isTrue 2798 | * @param {Mixed} value 2799 | * @param {String} message 2800 | * @api public 2801 | */ 2802 | 2803 | assert.isAbove = function (val, abv, msg) { 2804 | new Assertion(val, msg).to.be.above(abv); 2805 | }; 2806 | 2807 | /** 2808 | * ### .isAbove(valueToCheck, valueToBeAbove, [message]) 2809 | * 2810 | * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` 2811 | * 2812 | * assert.isAbove(5, 2, '5 is strictly greater than 2'); 2813 | * 2814 | * @name isAbove 2815 | * @param {Mixed} valueToCheck 2816 | * @param {Mixed} valueToBeAbove 2817 | * @param {String} message 2818 | * @api public 2819 | */ 2820 | 2821 | assert.isBelow = function (val, blw, msg) { 2822 | new Assertion(val, msg).to.be.below(blw); 2823 | }; 2824 | 2825 | /** 2826 | * ### .isBelow(valueToCheck, valueToBeBelow, [message]) 2827 | * 2828 | * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` 2829 | * 2830 | * assert.isBelow(3, 6, '3 is strictly less than 6'); 2831 | * 2832 | * @name isBelow 2833 | * @param {Mixed} valueToCheck 2834 | * @param {Mixed} valueToBeBelow 2835 | * @param {String} message 2836 | * @api public 2837 | */ 2838 | 2839 | assert.isTrue = function (val, msg) { 2840 | new Assertion(val, msg).is['true']; 2841 | }; 2842 | 2843 | /** 2844 | * ### .isFalse(value, [message]) 2845 | * 2846 | * Asserts that `value` is false. 2847 | * 2848 | * var teaServed = false; 2849 | * assert.isFalse(teaServed, 'no tea yet? hmm...'); 2850 | * 2851 | * @name isFalse 2852 | * @param {Mixed} value 2853 | * @param {String} message 2854 | * @api public 2855 | */ 2856 | 2857 | assert.isFalse = function (val, msg) { 2858 | new Assertion(val, msg).is['false']; 2859 | }; 2860 | 2861 | /** 2862 | * ### .isNull(value, [message]) 2863 | * 2864 | * Asserts that `value` is null. 2865 | * 2866 | * assert.isNull(err, 'there was no error'); 2867 | * 2868 | * @name isNull 2869 | * @param {Mixed} value 2870 | * @param {String} message 2871 | * @api public 2872 | */ 2873 | 2874 | assert.isNull = function (val, msg) { 2875 | new Assertion(val, msg).to.equal(null); 2876 | }; 2877 | 2878 | /** 2879 | * ### .isNotNull(value, [message]) 2880 | * 2881 | * Asserts that `value` is not null. 2882 | * 2883 | * var tea = 'tasty chai'; 2884 | * assert.isNotNull(tea, 'great, time for tea!'); 2885 | * 2886 | * @name isNotNull 2887 | * @param {Mixed} value 2888 | * @param {String} message 2889 | * @api public 2890 | */ 2891 | 2892 | assert.isNotNull = function (val, msg) { 2893 | new Assertion(val, msg).to.not.equal(null); 2894 | }; 2895 | 2896 | /** 2897 | * ### .isUndefined(value, [message]) 2898 | * 2899 | * Asserts that `value` is `undefined`. 2900 | * 2901 | * var tea; 2902 | * assert.isUndefined(tea, 'no tea defined'); 2903 | * 2904 | * @name isUndefined 2905 | * @param {Mixed} value 2906 | * @param {String} message 2907 | * @api public 2908 | */ 2909 | 2910 | assert.isUndefined = function (val, msg) { 2911 | new Assertion(val, msg).to.equal(undefined); 2912 | }; 2913 | 2914 | /** 2915 | * ### .isDefined(value, [message]) 2916 | * 2917 | * Asserts that `value` is not `undefined`. 2918 | * 2919 | * var tea = 'cup of chai'; 2920 | * assert.isDefined(tea, 'tea has been defined'); 2921 | * 2922 | * @name isDefined 2923 | * @param {Mixed} value 2924 | * @param {String} message 2925 | * @api public 2926 | */ 2927 | 2928 | assert.isDefined = function (val, msg) { 2929 | new Assertion(val, msg).to.not.equal(undefined); 2930 | }; 2931 | 2932 | /** 2933 | * ### .isFunction(value, [message]) 2934 | * 2935 | * Asserts that `value` is a function. 2936 | * 2937 | * function serveTea() { return 'cup of tea'; }; 2938 | * assert.isFunction(serveTea, 'great, we can have tea now'); 2939 | * 2940 | * @name isFunction 2941 | * @param {Mixed} value 2942 | * @param {String} message 2943 | * @api public 2944 | */ 2945 | 2946 | assert.isFunction = function (val, msg) { 2947 | new Assertion(val, msg).to.be.a('function'); 2948 | }; 2949 | 2950 | /** 2951 | * ### .isNotFunction(value, [message]) 2952 | * 2953 | * Asserts that `value` is _not_ a function. 2954 | * 2955 | * var serveTea = [ 'heat', 'pour', 'sip' ]; 2956 | * assert.isNotFunction(serveTea, 'great, we have listed the steps'); 2957 | * 2958 | * @name isNotFunction 2959 | * @param {Mixed} value 2960 | * @param {String} message 2961 | * @api public 2962 | */ 2963 | 2964 | assert.isNotFunction = function (val, msg) { 2965 | new Assertion(val, msg).to.not.be.a('function'); 2966 | }; 2967 | 2968 | /** 2969 | * ### .isObject(value, [message]) 2970 | * 2971 | * Asserts that `value` is an object (as revealed by 2972 | * `Object.prototype.toString`). 2973 | * 2974 | * var selection = { name: 'Chai', serve: 'with spices' }; 2975 | * assert.isObject(selection, 'tea selection is an object'); 2976 | * 2977 | * @name isObject 2978 | * @param {Mixed} value 2979 | * @param {String} message 2980 | * @api public 2981 | */ 2982 | 2983 | assert.isObject = function (val, msg) { 2984 | new Assertion(val, msg).to.be.a('object'); 2985 | }; 2986 | 2987 | /** 2988 | * ### .isNotObject(value, [message]) 2989 | * 2990 | * Asserts that `value` is _not_ an object. 2991 | * 2992 | * var selection = 'chai' 2993 | * assert.isNotObject(selection, 'tea selection is not an object'); 2994 | * assert.isNotObject(null, 'null is not an object'); 2995 | * 2996 | * @name isNotObject 2997 | * @param {Mixed} value 2998 | * @param {String} message 2999 | * @api public 3000 | */ 3001 | 3002 | assert.isNotObject = function (val, msg) { 3003 | new Assertion(val, msg).to.not.be.a('object'); 3004 | }; 3005 | 3006 | /** 3007 | * ### .isArray(value, [message]) 3008 | * 3009 | * Asserts that `value` is an array. 3010 | * 3011 | * var menu = [ 'green', 'chai', 'oolong' ]; 3012 | * assert.isArray(menu, 'what kind of tea do we want?'); 3013 | * 3014 | * @name isArray 3015 | * @param {Mixed} value 3016 | * @param {String} message 3017 | * @api public 3018 | */ 3019 | 3020 | assert.isArray = function (val, msg) { 3021 | new Assertion(val, msg).to.be.an('array'); 3022 | }; 3023 | 3024 | /** 3025 | * ### .isNotArray(value, [message]) 3026 | * 3027 | * Asserts that `value` is _not_ an array. 3028 | * 3029 | * var menu = 'green|chai|oolong'; 3030 | * assert.isNotArray(menu, 'what kind of tea do we want?'); 3031 | * 3032 | * @name isNotArray 3033 | * @param {Mixed} value 3034 | * @param {String} message 3035 | * @api public 3036 | */ 3037 | 3038 | assert.isNotArray = function (val, msg) { 3039 | new Assertion(val, msg).to.not.be.an('array'); 3040 | }; 3041 | 3042 | /** 3043 | * ### .isString(value, [message]) 3044 | * 3045 | * Asserts that `value` is a string. 3046 | * 3047 | * var teaOrder = 'chai'; 3048 | * assert.isString(teaOrder, 'order placed'); 3049 | * 3050 | * @name isString 3051 | * @param {Mixed} value 3052 | * @param {String} message 3053 | * @api public 3054 | */ 3055 | 3056 | assert.isString = function (val, msg) { 3057 | new Assertion(val, msg).to.be.a('string'); 3058 | }; 3059 | 3060 | /** 3061 | * ### .isNotString(value, [message]) 3062 | * 3063 | * Asserts that `value` is _not_ a string. 3064 | * 3065 | * var teaOrder = 4; 3066 | * assert.isNotString(teaOrder, 'order placed'); 3067 | * 3068 | * @name isNotString 3069 | * @param {Mixed} value 3070 | * @param {String} message 3071 | * @api public 3072 | */ 3073 | 3074 | assert.isNotString = function (val, msg) { 3075 | new Assertion(val, msg).to.not.be.a('string'); 3076 | }; 3077 | 3078 | /** 3079 | * ### .isNumber(value, [message]) 3080 | * 3081 | * Asserts that `value` is a number. 3082 | * 3083 | * var cups = 2; 3084 | * assert.isNumber(cups, 'how many cups'); 3085 | * 3086 | * @name isNumber 3087 | * @param {Number} value 3088 | * @param {String} message 3089 | * @api public 3090 | */ 3091 | 3092 | assert.isNumber = function (val, msg) { 3093 | new Assertion(val, msg).to.be.a('number'); 3094 | }; 3095 | 3096 | /** 3097 | * ### .isNotNumber(value, [message]) 3098 | * 3099 | * Asserts that `value` is _not_ a number. 3100 | * 3101 | * var cups = '2 cups please'; 3102 | * assert.isNotNumber(cups, 'how many cups'); 3103 | * 3104 | * @name isNotNumber 3105 | * @param {Mixed} value 3106 | * @param {String} message 3107 | * @api public 3108 | */ 3109 | 3110 | assert.isNotNumber = function (val, msg) { 3111 | new Assertion(val, msg).to.not.be.a('number'); 3112 | }; 3113 | 3114 | /** 3115 | * ### .isBoolean(value, [message]) 3116 | * 3117 | * Asserts that `value` is a boolean. 3118 | * 3119 | * var teaReady = true 3120 | * , teaServed = false; 3121 | * 3122 | * assert.isBoolean(teaReady, 'is the tea ready'); 3123 | * assert.isBoolean(teaServed, 'has tea been served'); 3124 | * 3125 | * @name isBoolean 3126 | * @param {Mixed} value 3127 | * @param {String} message 3128 | * @api public 3129 | */ 3130 | 3131 | assert.isBoolean = function (val, msg) { 3132 | new Assertion(val, msg).to.be.a('boolean'); 3133 | }; 3134 | 3135 | /** 3136 | * ### .isNotBoolean(value, [message]) 3137 | * 3138 | * Asserts that `value` is _not_ a boolean. 3139 | * 3140 | * var teaReady = 'yep' 3141 | * , teaServed = 'nope'; 3142 | * 3143 | * assert.isNotBoolean(teaReady, 'is the tea ready'); 3144 | * assert.isNotBoolean(teaServed, 'has tea been served'); 3145 | * 3146 | * @name isNotBoolean 3147 | * @param {Mixed} value 3148 | * @param {String} message 3149 | * @api public 3150 | */ 3151 | 3152 | assert.isNotBoolean = function (val, msg) { 3153 | new Assertion(val, msg).to.not.be.a('boolean'); 3154 | }; 3155 | 3156 | /** 3157 | * ### .typeOf(value, name, [message]) 3158 | * 3159 | * Asserts that `value`'s type is `name`, as determined by 3160 | * `Object.prototype.toString`. 3161 | * 3162 | * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); 3163 | * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); 3164 | * assert.typeOf('tea', 'string', 'we have a string'); 3165 | * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); 3166 | * assert.typeOf(null, 'null', 'we have a null'); 3167 | * assert.typeOf(undefined, 'undefined', 'we have an undefined'); 3168 | * 3169 | * @name typeOf 3170 | * @param {Mixed} value 3171 | * @param {String} name 3172 | * @param {String} message 3173 | * @api public 3174 | */ 3175 | 3176 | assert.typeOf = function (val, type, msg) { 3177 | new Assertion(val, msg).to.be.a(type); 3178 | }; 3179 | 3180 | /** 3181 | * ### .notTypeOf(value, name, [message]) 3182 | * 3183 | * Asserts that `value`'s type is _not_ `name`, as determined by 3184 | * `Object.prototype.toString`. 3185 | * 3186 | * assert.notTypeOf('tea', 'number', 'strings are not numbers'); 3187 | * 3188 | * @name notTypeOf 3189 | * @param {Mixed} value 3190 | * @param {String} typeof name 3191 | * @param {String} message 3192 | * @api public 3193 | */ 3194 | 3195 | assert.notTypeOf = function (val, type, msg) { 3196 | new Assertion(val, msg).to.not.be.a(type); 3197 | }; 3198 | 3199 | /** 3200 | * ### .instanceOf(object, constructor, [message]) 3201 | * 3202 | * Asserts that `value` is an instance of `constructor`. 3203 | * 3204 | * var Tea = function (name) { this.name = name; } 3205 | * , chai = new Tea('chai'); 3206 | * 3207 | * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); 3208 | * 3209 | * @name instanceOf 3210 | * @param {Object} object 3211 | * @param {Constructor} constructor 3212 | * @param {String} message 3213 | * @api public 3214 | */ 3215 | 3216 | assert.instanceOf = function (val, type, msg) { 3217 | new Assertion(val, msg).to.be.instanceOf(type); 3218 | }; 3219 | 3220 | /** 3221 | * ### .notInstanceOf(object, constructor, [message]) 3222 | * 3223 | * Asserts `value` is not an instance of `constructor`. 3224 | * 3225 | * var Tea = function (name) { this.name = name; } 3226 | * , chai = new String('chai'); 3227 | * 3228 | * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); 3229 | * 3230 | * @name notInstanceOf 3231 | * @param {Object} object 3232 | * @param {Constructor} constructor 3233 | * @param {String} message 3234 | * @api public 3235 | */ 3236 | 3237 | assert.notInstanceOf = function (val, type, msg) { 3238 | new Assertion(val, msg).to.not.be.instanceOf(type); 3239 | }; 3240 | 3241 | /** 3242 | * ### .include(haystack, needle, [message]) 3243 | * 3244 | * Asserts that `haystack` includes `needle`. Works 3245 | * for strings and arrays. 3246 | * 3247 | * assert.include('foobar', 'bar', 'foobar contains string "bar"'); 3248 | * assert.include([ 1, 2, 3 ], 3, 'array contains value'); 3249 | * 3250 | * @name include 3251 | * @param {Array|String} haystack 3252 | * @param {Mixed} needle 3253 | * @param {String} message 3254 | * @api public 3255 | */ 3256 | 3257 | assert.include = function (exp, inc, msg) { 3258 | new Assertion(exp, msg, assert.include).include(inc); 3259 | }; 3260 | 3261 | /** 3262 | * ### .notInclude(haystack, needle, [message]) 3263 | * 3264 | * Asserts that `haystack` does not include `needle`. Works 3265 | * for strings and arrays. 3266 | *i 3267 | * assert.notInclude('foobar', 'baz', 'string not include substring'); 3268 | * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); 3269 | * 3270 | * @name notInclude 3271 | * @param {Array|String} haystack 3272 | * @param {Mixed} needle 3273 | * @param {String} message 3274 | * @api public 3275 | */ 3276 | 3277 | assert.notInclude = function (exp, inc, msg) { 3278 | new Assertion(exp, msg, assert.notInclude).not.include(inc); 3279 | }; 3280 | 3281 | /** 3282 | * ### .match(value, regexp, [message]) 3283 | * 3284 | * Asserts that `value` matches the regular expression `regexp`. 3285 | * 3286 | * assert.match('foobar', /^foo/, 'regexp matches'); 3287 | * 3288 | * @name match 3289 | * @param {Mixed} value 3290 | * @param {RegExp} regexp 3291 | * @param {String} message 3292 | * @api public 3293 | */ 3294 | 3295 | assert.match = function (exp, re, msg) { 3296 | new Assertion(exp, msg).to.match(re); 3297 | }; 3298 | 3299 | /** 3300 | * ### .notMatch(value, regexp, [message]) 3301 | * 3302 | * Asserts that `value` does not match the regular expression `regexp`. 3303 | * 3304 | * assert.notMatch('foobar', /^foo/, 'regexp does not match'); 3305 | * 3306 | * @name notMatch 3307 | * @param {Mixed} value 3308 | * @param {RegExp} regexp 3309 | * @param {String} message 3310 | * @api public 3311 | */ 3312 | 3313 | assert.notMatch = function (exp, re, msg) { 3314 | new Assertion(exp, msg).to.not.match(re); 3315 | }; 3316 | 3317 | /** 3318 | * ### .property(object, property, [message]) 3319 | * 3320 | * Asserts that `object` has a property named by `property`. 3321 | * 3322 | * assert.property({ tea: { green: 'matcha' }}, 'tea'); 3323 | * 3324 | * @name property 3325 | * @param {Object} object 3326 | * @param {String} property 3327 | * @param {String} message 3328 | * @api public 3329 | */ 3330 | 3331 | assert.property = function (obj, prop, msg) { 3332 | new Assertion(obj, msg).to.have.property(prop); 3333 | }; 3334 | 3335 | /** 3336 | * ### .notProperty(object, property, [message]) 3337 | * 3338 | * Asserts that `object` does _not_ have a property named by `property`. 3339 | * 3340 | * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); 3341 | * 3342 | * @name notProperty 3343 | * @param {Object} object 3344 | * @param {String} property 3345 | * @param {String} message 3346 | * @api public 3347 | */ 3348 | 3349 | assert.notProperty = function (obj, prop, msg) { 3350 | new Assertion(obj, msg).to.not.have.property(prop); 3351 | }; 3352 | 3353 | /** 3354 | * ### .deepProperty(object, property, [message]) 3355 | * 3356 | * Asserts that `object` has a property named by `property`, which can be a 3357 | * string using dot- and bracket-notation for deep reference. 3358 | * 3359 | * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); 3360 | * 3361 | * @name deepProperty 3362 | * @param {Object} object 3363 | * @param {String} property 3364 | * @param {String} message 3365 | * @api public 3366 | */ 3367 | 3368 | assert.deepProperty = function (obj, prop, msg) { 3369 | new Assertion(obj, msg).to.have.deep.property(prop); 3370 | }; 3371 | 3372 | /** 3373 | * ### .notDeepProperty(object, property, [message]) 3374 | * 3375 | * Asserts that `object` does _not_ have a property named by `property`, which 3376 | * can be a string using dot- and bracket-notation for deep reference. 3377 | * 3378 | * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); 3379 | * 3380 | * @name notDeepProperty 3381 | * @param {Object} object 3382 | * @param {String} property 3383 | * @param {String} message 3384 | * @api public 3385 | */ 3386 | 3387 | assert.notDeepProperty = function (obj, prop, msg) { 3388 | new Assertion(obj, msg).to.not.have.deep.property(prop); 3389 | }; 3390 | 3391 | /** 3392 | * ### .propertyVal(object, property, value, [message]) 3393 | * 3394 | * Asserts that `object` has a property named by `property` with value given 3395 | * by `value`. 3396 | * 3397 | * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); 3398 | * 3399 | * @name propertyVal 3400 | * @param {Object} object 3401 | * @param {String} property 3402 | * @param {Mixed} value 3403 | * @param {String} message 3404 | * @api public 3405 | */ 3406 | 3407 | assert.propertyVal = function (obj, prop, val, msg) { 3408 | new Assertion(obj, msg).to.have.property(prop, val); 3409 | }; 3410 | 3411 | /** 3412 | * ### .propertyNotVal(object, property, value, [message]) 3413 | * 3414 | * Asserts that `object` has a property named by `property`, but with a value 3415 | * different from that given by `value`. 3416 | * 3417 | * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); 3418 | * 3419 | * @name propertyNotVal 3420 | * @param {Object} object 3421 | * @param {String} property 3422 | * @param {Mixed} value 3423 | * @param {String} message 3424 | * @api public 3425 | */ 3426 | 3427 | assert.propertyNotVal = function (obj, prop, val, msg) { 3428 | new Assertion(obj, msg).to.not.have.property(prop, val); 3429 | }; 3430 | 3431 | /** 3432 | * ### .deepPropertyVal(object, property, value, [message]) 3433 | * 3434 | * Asserts that `object` has a property named by `property` with value given 3435 | * by `value`. `property` can use dot- and bracket-notation for deep 3436 | * reference. 3437 | * 3438 | * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); 3439 | * 3440 | * @name deepPropertyVal 3441 | * @param {Object} object 3442 | * @param {String} property 3443 | * @param {Mixed} value 3444 | * @param {String} message 3445 | * @api public 3446 | */ 3447 | 3448 | assert.deepPropertyVal = function (obj, prop, val, msg) { 3449 | new Assertion(obj, msg).to.have.deep.property(prop, val); 3450 | }; 3451 | 3452 | /** 3453 | * ### .deepPropertyNotVal(object, property, value, [message]) 3454 | * 3455 | * Asserts that `object` has a property named by `property`, but with a value 3456 | * different from that given by `value`. `property` can use dot- and 3457 | * bracket-notation for deep reference. 3458 | * 3459 | * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); 3460 | * 3461 | * @name deepPropertyNotVal 3462 | * @param {Object} object 3463 | * @param {String} property 3464 | * @param {Mixed} value 3465 | * @param {String} message 3466 | * @api public 3467 | */ 3468 | 3469 | assert.deepPropertyNotVal = function (obj, prop, val, msg) { 3470 | new Assertion(obj, msg).to.not.have.deep.property(prop, val); 3471 | }; 3472 | 3473 | /** 3474 | * ### .lengthOf(object, length, [message]) 3475 | * 3476 | * Asserts that `object` has a `length` property with the expected value. 3477 | * 3478 | * assert.lengthOf([1,2,3], 3, 'array has length of 3'); 3479 | * assert.lengthOf('foobar', 5, 'string has length of 6'); 3480 | * 3481 | * @name lengthOf 3482 | * @param {Mixed} object 3483 | * @param {Number} length 3484 | * @param {String} message 3485 | * @api public 3486 | */ 3487 | 3488 | assert.lengthOf = function (exp, len, msg) { 3489 | new Assertion(exp, msg).to.have.length(len); 3490 | }; 3491 | 3492 | /** 3493 | * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) 3494 | * 3495 | * Asserts that `function` will throw an error that is an instance of 3496 | * `constructor`, or alternately that it will throw an error with message 3497 | * matching `regexp`. 3498 | * 3499 | * assert.throw(fn, 'function throws a reference error'); 3500 | * assert.throw(fn, /function throws a reference error/); 3501 | * assert.throw(fn, ReferenceError); 3502 | * assert.throw(fn, ReferenceError, 'function throws a reference error'); 3503 | * assert.throw(fn, ReferenceError, /function throws a reference error/); 3504 | * 3505 | * @name throws 3506 | * @alias throw 3507 | * @alias Throw 3508 | * @param {Function} function 3509 | * @param {ErrorConstructor} constructor 3510 | * @param {RegExp} regexp 3511 | * @param {String} message 3512 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3513 | * @api public 3514 | */ 3515 | 3516 | assert.Throw = function (fn, errt, errs, msg) { 3517 | if ('string' === typeof errt || errt instanceof RegExp) { 3518 | errs = errt; 3519 | errt = null; 3520 | } 3521 | 3522 | var assertErr = new Assertion(fn, msg).to.Throw(errt, errs); 3523 | return flag(assertErr, 'object'); 3524 | }; 3525 | 3526 | /** 3527 | * ### .doesNotThrow(function, [constructor/regexp], [message]) 3528 | * 3529 | * Asserts that `function` will _not_ throw an error that is an instance of 3530 | * `constructor`, or alternately that it will not throw an error with message 3531 | * matching `regexp`. 3532 | * 3533 | * assert.doesNotThrow(fn, Error, 'function does not throw'); 3534 | * 3535 | * @name doesNotThrow 3536 | * @param {Function} function 3537 | * @param {ErrorConstructor} constructor 3538 | * @param {RegExp} regexp 3539 | * @param {String} message 3540 | * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types 3541 | * @api public 3542 | */ 3543 | 3544 | assert.doesNotThrow = function (fn, type, msg) { 3545 | if ('string' === typeof type) { 3546 | msg = type; 3547 | type = null; 3548 | } 3549 | 3550 | new Assertion(fn, msg).to.not.Throw(type); 3551 | }; 3552 | 3553 | /** 3554 | * ### .operator(val1, operator, val2, [message]) 3555 | * 3556 | * Compares two values using `operator`. 3557 | * 3558 | * assert.operator(1, '<', 2, 'everything is ok'); 3559 | * assert.operator(1, '>', 2, 'this will fail'); 3560 | * 3561 | * @name operator 3562 | * @param {Mixed} val1 3563 | * @param {String} operator 3564 | * @param {Mixed} val2 3565 | * @param {String} message 3566 | * @api public 3567 | */ 3568 | 3569 | assert.operator = function (val, operator, val2, msg) { 3570 | var ok; 3571 | switch(operator) { 3572 | case '==': 3573 | ok = val == val2; 3574 | break; 3575 | case '===': 3576 | ok = val === val2; 3577 | break; 3578 | case '>': 3579 | ok = val > val2; 3580 | break; 3581 | case '>=': 3582 | ok = val >= val2; 3583 | break; 3584 | case '<': 3585 | ok = val < val2; 3586 | break; 3587 | case '<=': 3588 | ok = val <= val2; 3589 | break; 3590 | case '!=': 3591 | ok = val != val2; 3592 | break; 3593 | case '!==': 3594 | ok = val !== val2; 3595 | break; 3596 | default: 3597 | throw new Error('Invalid operator "' + operator + '"'); 3598 | } 3599 | var test = new Assertion(ok, msg); 3600 | test.assert( 3601 | true === flag(test, 'object') 3602 | , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) 3603 | , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); 3604 | }; 3605 | 3606 | /** 3607 | * ### .closeTo(actual, expected, delta, [message]) 3608 | * 3609 | * Asserts that the target is equal `expected`, to within a +/- `delta` range. 3610 | * 3611 | * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); 3612 | * 3613 | * @name closeTo 3614 | * @param {Number} actual 3615 | * @param {Number} expected 3616 | * @param {Number} delta 3617 | * @param {String} message 3618 | * @api public 3619 | */ 3620 | 3621 | assert.closeTo = function (act, exp, delta, msg) { 3622 | new Assertion(act, msg).to.be.closeTo(exp, delta); 3623 | }; 3624 | 3625 | /** 3626 | * ### .sameMembers(set1, set2, [message]) 3627 | * 3628 | * Asserts that `set1` and `set2` have the same members. 3629 | * Order is not taken into account. 3630 | * 3631 | * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); 3632 | * 3633 | * @name sameMembers 3634 | * @param {Array} set1 3635 | * @param {Array} set2 3636 | * @param {String} message 3637 | * @api public 3638 | */ 3639 | 3640 | assert.sameMembers = function (set1, set2, msg) { 3641 | new Assertion(set1, msg).to.have.same.members(set2); 3642 | } 3643 | 3644 | /** 3645 | * ### .sameDeepMembers(set1, set2, [message]) 3646 | * 3647 | * Asserts that `set1` and `set2` have the same members - using a deep equality checking. 3648 | * Order is not taken into account. 3649 | * 3650 | * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); 3651 | * 3652 | * @name sameDeepMembers 3653 | * @param {Array} set1 3654 | * @param {Array} set2 3655 | * @param {String} message 3656 | * @api public 3657 | */ 3658 | 3659 | assert.sameDeepMembers = function (set1, set2, msg) { 3660 | new Assertion(set1, msg).to.have.same.deep.members(set2); 3661 | } 3662 | 3663 | /** 3664 | * ### .includeMembers(superset, subset, [message]) 3665 | * 3666 | * Asserts that `subset` is included in `superset`. 3667 | * Order is not taken into account. 3668 | * 3669 | * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); 3670 | * 3671 | * @name includeMembers 3672 | * @param {Array} superset 3673 | * @param {Array} subset 3674 | * @param {String} message 3675 | * @api public 3676 | */ 3677 | 3678 | assert.includeMembers = function (superset, subset, msg) { 3679 | new Assertion(superset, msg).to.include.members(subset); 3680 | } 3681 | 3682 | /** 3683 | * ### .changes(function, object, property) 3684 | * 3685 | * Asserts that a function changes the value of a property 3686 | * 3687 | * var obj = { val: 10 }; 3688 | * var fn = function() { obj.val = 22 }; 3689 | * assert.changes(fn, obj, 'val'); 3690 | * 3691 | * @name changes 3692 | * @param {Function} modifier function 3693 | * @param {Object} object 3694 | * @param {String} property name 3695 | * @param {String} message _optional_ 3696 | * @api public 3697 | */ 3698 | 3699 | assert.changes = function (fn, obj, prop) { 3700 | new Assertion(fn).to.change(obj, prop); 3701 | } 3702 | 3703 | /** 3704 | * ### .doesNotChange(function, object, property) 3705 | * 3706 | * Asserts that a function does not changes the value of a property 3707 | * 3708 | * var obj = { val: 10 }; 3709 | * var fn = function() { console.log('foo'); }; 3710 | * assert.doesNotChange(fn, obj, 'val'); 3711 | * 3712 | * @name doesNotChange 3713 | * @param {Function} modifier function 3714 | * @param {Object} object 3715 | * @param {String} property name 3716 | * @param {String} message _optional_ 3717 | * @api public 3718 | */ 3719 | 3720 | assert.doesNotChange = function (fn, obj, prop) { 3721 | new Assertion(fn).to.not.change(obj, prop); 3722 | } 3723 | 3724 | /** 3725 | * ### .increases(function, object, property) 3726 | * 3727 | * Asserts that a function increases an object property 3728 | * 3729 | * var obj = { val: 10 }; 3730 | * var fn = function() { obj.val = 13 }; 3731 | * assert.increases(fn, obj, 'val'); 3732 | * 3733 | * @name increases 3734 | * @param {Function} modifier function 3735 | * @param {Object} object 3736 | * @param {String} property name 3737 | * @param {String} message _optional_ 3738 | * @api public 3739 | */ 3740 | 3741 | assert.increases = function (fn, obj, prop) { 3742 | new Assertion(fn).to.increase(obj, prop); 3743 | } 3744 | 3745 | /** 3746 | * ### .doesNotIncrease(function, object, property) 3747 | * 3748 | * Asserts that a function does not increase object property 3749 | * 3750 | * var obj = { val: 10 }; 3751 | * var fn = function() { obj.val = 8 }; 3752 | * assert.doesNotIncrease(fn, obj, 'val'); 3753 | * 3754 | * @name doesNotIncrease 3755 | * @param {Function} modifier function 3756 | * @param {Object} object 3757 | * @param {String} property name 3758 | * @param {String} message _optional_ 3759 | * @api public 3760 | */ 3761 | 3762 | assert.doesNotIncrease = function (fn, obj, prop) { 3763 | new Assertion(fn).to.not.increase(obj, prop); 3764 | } 3765 | 3766 | /** 3767 | * ### .decreases(function, object, property) 3768 | * 3769 | * Asserts that a function decreases an object property 3770 | * 3771 | * var obj = { val: 10 }; 3772 | * var fn = function() { obj.val = 5 }; 3773 | * assert.decreases(fn, obj, 'val'); 3774 | * 3775 | * @name decreases 3776 | * @param {Function} modifier function 3777 | * @param {Object} object 3778 | * @param {String} property name 3779 | * @param {String} message _optional_ 3780 | * @api public 3781 | */ 3782 | 3783 | assert.decreases = function (fn, obj, prop) { 3784 | new Assertion(fn).to.decrease(obj, prop); 3785 | } 3786 | 3787 | /** 3788 | * ### .doesNotDecrease(function, object, property) 3789 | * 3790 | * Asserts that a function does not decreases an object property 3791 | * 3792 | * var obj = { val: 10 }; 3793 | * var fn = function() { obj.val = 15 }; 3794 | * assert.doesNotDecrease(fn, obj, 'val'); 3795 | * 3796 | * @name doesNotDecrease 3797 | * @param {Function} modifier function 3798 | * @param {Object} object 3799 | * @param {String} property name 3800 | * @param {String} message _optional_ 3801 | * @api public 3802 | */ 3803 | 3804 | assert.doesNotDecrease = function (fn, obj, prop) { 3805 | new Assertion(fn).to.not.decrease(obj, prop); 3806 | } 3807 | 3808 | /*! 3809 | * Undocumented / untested 3810 | */ 3811 | 3812 | assert.ifError = function (val, msg) { 3813 | new Assertion(val, msg).to.not.be.ok; 3814 | }; 3815 | 3816 | /*! 3817 | * Aliases. 3818 | */ 3819 | 3820 | (function alias(name, as){ 3821 | assert[as] = assert[name]; 3822 | return alias; 3823 | }) 3824 | ('Throw', 'throw') 3825 | ('Throw', 'throws'); 3826 | }; 3827 | 3828 | }); 3829 | 3830 | require.register("chai/lib/chai/interface/expect.js", function (exports, module) { 3831 | /*! 3832 | * chai 3833 | * Copyright(c) 2011-2014 Jake Luer 3834 | * MIT Licensed 3835 | */ 3836 | 3837 | module.exports = function (chai, util) { 3838 | chai.expect = function (val, message) { 3839 | return new chai.Assertion(val, message); 3840 | }; 3841 | 3842 | /** 3843 | * ### .fail(actual, expected, [message], [operator]) 3844 | * 3845 | * Throw a failure. 3846 | * 3847 | * @name fail 3848 | * @param {Mixed} actual 3849 | * @param {Mixed} expected 3850 | * @param {String} message 3851 | * @param {String} operator 3852 | * @api public 3853 | */ 3854 | 3855 | chai.expect.fail = function (actual, expected, message, operator) { 3856 | message = message || 'expect.fail()'; 3857 | throw new chai.AssertionError(message, { 3858 | actual: actual 3859 | , expected: expected 3860 | , operator: operator 3861 | }, chai.expect.fail); 3862 | }; 3863 | }; 3864 | 3865 | }); 3866 | 3867 | require.register("chai/lib/chai/interface/should.js", function (exports, module) { 3868 | /*! 3869 | * chai 3870 | * Copyright(c) 2011-2014 Jake Luer 3871 | * MIT Licensed 3872 | */ 3873 | 3874 | module.exports = function (chai, util) { 3875 | var Assertion = chai.Assertion; 3876 | 3877 | function loadShould () { 3878 | // explicitly define this method as function as to have it's name to include as `ssfi` 3879 | function shouldGetter() { 3880 | if (this instanceof String || this instanceof Number || this instanceof Boolean ) { 3881 | return new Assertion(this.valueOf(), null, shouldGetter); 3882 | } 3883 | return new Assertion(this, null, shouldGetter); 3884 | } 3885 | function shouldSetter(value) { 3886 | // See https://github.com/chaijs/chai/issues/86: this makes 3887 | // `whatever.should = someValue` actually set `someValue`, which is 3888 | // especially useful for `global.should = require('chai').should()`. 3889 | // 3890 | // Note that we have to use [[DefineProperty]] instead of [[Put]] 3891 | // since otherwise we would trigger this very setter! 3892 | Object.defineProperty(this, 'should', { 3893 | value: value, 3894 | enumerable: true, 3895 | configurable: true, 3896 | writable: true 3897 | }); 3898 | } 3899 | // modify Object.prototype to have `should` 3900 | Object.defineProperty(Object.prototype, 'should', { 3901 | set: shouldSetter 3902 | , get: shouldGetter 3903 | , configurable: true 3904 | }); 3905 | 3906 | var should = {}; 3907 | 3908 | /** 3909 | * ### .fail(actual, expected, [message], [operator]) 3910 | * 3911 | * Throw a failure. 3912 | * 3913 | * @name fail 3914 | * @param {Mixed} actual 3915 | * @param {Mixed} expected 3916 | * @param {String} message 3917 | * @param {String} operator 3918 | * @api public 3919 | */ 3920 | 3921 | should.fail = function (actual, expected, message, operator) { 3922 | message = message || 'should.fail()'; 3923 | throw new chai.AssertionError(message, { 3924 | actual: actual 3925 | , expected: expected 3926 | , operator: operator 3927 | }, should.fail); 3928 | }; 3929 | 3930 | should.equal = function (val1, val2, msg) { 3931 | new Assertion(val1, msg).to.equal(val2); 3932 | }; 3933 | 3934 | should.Throw = function (fn, errt, errs, msg) { 3935 | new Assertion(fn, msg).to.Throw(errt, errs); 3936 | }; 3937 | 3938 | should.exist = function (val, msg) { 3939 | new Assertion(val, msg).to.exist; 3940 | } 3941 | 3942 | // negation 3943 | should.not = {} 3944 | 3945 | should.not.equal = function (val1, val2, msg) { 3946 | new Assertion(val1, msg).to.not.equal(val2); 3947 | }; 3948 | 3949 | should.not.Throw = function (fn, errt, errs, msg) { 3950 | new Assertion(fn, msg).to.not.Throw(errt, errs); 3951 | }; 3952 | 3953 | should.not.exist = function (val, msg) { 3954 | new Assertion(val, msg).to.not.exist; 3955 | } 3956 | 3957 | should['throw'] = should['Throw']; 3958 | should.not['throw'] = should.not['Throw']; 3959 | 3960 | return should; 3961 | }; 3962 | 3963 | chai.should = loadShould; 3964 | chai.Should = loadShould; 3965 | }; 3966 | 3967 | }); 3968 | 3969 | require.register("chai/lib/chai/utils/addChainableMethod.js", function (exports, module) { 3970 | /*! 3971 | * Chai - addChainingMethod utility 3972 | * Copyright(c) 2012-2014 Jake Luer 3973 | * MIT Licensed 3974 | */ 3975 | 3976 | /*! 3977 | * Module dependencies 3978 | */ 3979 | 3980 | var transferFlags = require('chai/lib/chai/utils/transferFlags.js'); 3981 | var flag = require('chai/lib/chai/utils/flag.js'); 3982 | var config = require('chai/lib/chai/config.js'); 3983 | 3984 | /*! 3985 | * Module variables 3986 | */ 3987 | 3988 | // Check whether `__proto__` is supported 3989 | var hasProtoSupport = '__proto__' in Object; 3990 | 3991 | // Without `__proto__` support, this module will need to add properties to a function. 3992 | // However, some Function.prototype methods cannot be overwritten, 3993 | // and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). 3994 | var excludeNames = /^(?:length|name|arguments|caller)$/; 3995 | 3996 | // Cache `Function` properties 3997 | var call = Function.prototype.call, 3998 | apply = Function.prototype.apply; 3999 | 4000 | /** 4001 | * ### addChainableMethod (ctx, name, method, chainingBehavior) 4002 | * 4003 | * Adds a method to an object, such that the method can also be chained. 4004 | * 4005 | * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { 4006 | * var obj = utils.flag(this, 'object'); 4007 | * new chai.Assertion(obj).to.be.equal(str); 4008 | * }); 4009 | * 4010 | * Can also be accessed directly from `chai.Assertion`. 4011 | * 4012 | * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); 4013 | * 4014 | * The result can then be used as both a method assertion, executing both `method` and 4015 | * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. 4016 | * 4017 | * expect(fooStr).to.be.foo('bar'); 4018 | * expect(fooStr).to.be.foo.equal('foo'); 4019 | * 4020 | * @param {Object} ctx object to which the method is added 4021 | * @param {String} name of method to add 4022 | * @param {Function} method function to be used for `name`, when called 4023 | * @param {Function} chainingBehavior function to be called every time the property is accessed 4024 | * @name addChainableMethod 4025 | * @api public 4026 | */ 4027 | 4028 | module.exports = function (ctx, name, method, chainingBehavior) { 4029 | if (typeof chainingBehavior !== 'function') { 4030 | chainingBehavior = function () { }; 4031 | } 4032 | 4033 | var chainableBehavior = { 4034 | method: method 4035 | , chainingBehavior: chainingBehavior 4036 | }; 4037 | 4038 | // save the methods so we can overwrite them later, if we need to. 4039 | if (!ctx.__methods) { 4040 | ctx.__methods = {}; 4041 | } 4042 | ctx.__methods[name] = chainableBehavior; 4043 | 4044 | Object.defineProperty(ctx, name, 4045 | { get: function () { 4046 | chainableBehavior.chainingBehavior.call(this); 4047 | 4048 | var assert = function assert() { 4049 | var old_ssfi = flag(this, 'ssfi'); 4050 | if (old_ssfi && config.includeStack === false) 4051 | flag(this, 'ssfi', assert); 4052 | var result = chainableBehavior.method.apply(this, arguments); 4053 | return result === undefined ? this : result; 4054 | }; 4055 | 4056 | // Use `__proto__` if available 4057 | if (hasProtoSupport) { 4058 | // Inherit all properties from the object by replacing the `Function` prototype 4059 | var prototype = assert.__proto__ = Object.create(this); 4060 | // Restore the `call` and `apply` methods from `Function` 4061 | prototype.call = call; 4062 | prototype.apply = apply; 4063 | } 4064 | // Otherwise, redefine all properties (slow!) 4065 | else { 4066 | var asserterNames = Object.getOwnPropertyNames(ctx); 4067 | asserterNames.forEach(function (asserterName) { 4068 | if (!excludeNames.test(asserterName)) { 4069 | var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); 4070 | Object.defineProperty(assert, asserterName, pd); 4071 | } 4072 | }); 4073 | } 4074 | 4075 | transferFlags(this, assert); 4076 | return assert; 4077 | } 4078 | , configurable: true 4079 | }); 4080 | }; 4081 | 4082 | }); 4083 | 4084 | require.register("chai/lib/chai/utils/addMethod.js", function (exports, module) { 4085 | /*! 4086 | * Chai - addMethod utility 4087 | * Copyright(c) 2012-2014 Jake Luer 4088 | * MIT Licensed 4089 | */ 4090 | 4091 | var config = require('chai/lib/chai/config.js'); 4092 | 4093 | /** 4094 | * ### .addMethod (ctx, name, method) 4095 | * 4096 | * Adds a method to the prototype of an object. 4097 | * 4098 | * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { 4099 | * var obj = utils.flag(this, 'object'); 4100 | * new chai.Assertion(obj).to.be.equal(str); 4101 | * }); 4102 | * 4103 | * Can also be accessed directly from `chai.Assertion`. 4104 | * 4105 | * chai.Assertion.addMethod('foo', fn); 4106 | * 4107 | * Then can be used as any other assertion. 4108 | * 4109 | * expect(fooStr).to.be.foo('bar'); 4110 | * 4111 | * @param {Object} ctx object to which the method is added 4112 | * @param {String} name of method to add 4113 | * @param {Function} method function to be used for name 4114 | * @name addMethod 4115 | * @api public 4116 | */ 4117 | var flag = require('chai/lib/chai/utils/flag.js'); 4118 | 4119 | module.exports = function (ctx, name, method) { 4120 | ctx[name] = function () { 4121 | var old_ssfi = flag(this, 'ssfi'); 4122 | if (old_ssfi && config.includeStack === false) 4123 | flag(this, 'ssfi', ctx[name]); 4124 | var result = method.apply(this, arguments); 4125 | return result === undefined ? this : result; 4126 | }; 4127 | }; 4128 | 4129 | }); 4130 | 4131 | require.register("chai/lib/chai/utils/addProperty.js", function (exports, module) { 4132 | /*! 4133 | * Chai - addProperty utility 4134 | * Copyright(c) 2012-2014 Jake Luer 4135 | * MIT Licensed 4136 | */ 4137 | 4138 | /** 4139 | * ### addProperty (ctx, name, getter) 4140 | * 4141 | * Adds a property to the prototype of an object. 4142 | * 4143 | * utils.addProperty(chai.Assertion.prototype, 'foo', function () { 4144 | * var obj = utils.flag(this, 'object'); 4145 | * new chai.Assertion(obj).to.be.instanceof(Foo); 4146 | * }); 4147 | * 4148 | * Can also be accessed directly from `chai.Assertion`. 4149 | * 4150 | * chai.Assertion.addProperty('foo', fn); 4151 | * 4152 | * Then can be used as any other assertion. 4153 | * 4154 | * expect(myFoo).to.be.foo; 4155 | * 4156 | * @param {Object} ctx object to which the property is added 4157 | * @param {String} name of property to add 4158 | * @param {Function} getter function to be used for name 4159 | * @name addProperty 4160 | * @api public 4161 | */ 4162 | 4163 | module.exports = function (ctx, name, getter) { 4164 | Object.defineProperty(ctx, name, 4165 | { get: function () { 4166 | var result = getter.call(this); 4167 | return result === undefined ? this : result; 4168 | } 4169 | , configurable: true 4170 | }); 4171 | }; 4172 | 4173 | }); 4174 | 4175 | require.register("chai/lib/chai/utils/flag.js", function (exports, module) { 4176 | /*! 4177 | * Chai - flag utility 4178 | * Copyright(c) 2012-2014 Jake Luer 4179 | * MIT Licensed 4180 | */ 4181 | 4182 | /** 4183 | * ### flag(object, key, [value]) 4184 | * 4185 | * Get or set a flag value on an object. If a 4186 | * value is provided it will be set, else it will 4187 | * return the currently set value or `undefined` if 4188 | * the value is not set. 4189 | * 4190 | * utils.flag(this, 'foo', 'bar'); // setter 4191 | * utils.flag(this, 'foo'); // getter, returns `bar` 4192 | * 4193 | * @param {Object} object constructed Assertion 4194 | * @param {String} key 4195 | * @param {Mixed} value (optional) 4196 | * @name flag 4197 | * @api private 4198 | */ 4199 | 4200 | module.exports = function (obj, key, value) { 4201 | var flags = obj.__flags || (obj.__flags = Object.create(null)); 4202 | if (arguments.length === 3) { 4203 | flags[key] = value; 4204 | } else { 4205 | return flags[key]; 4206 | } 4207 | }; 4208 | 4209 | }); 4210 | 4211 | require.register("chai/lib/chai/utils/getActual.js", function (exports, module) { 4212 | /*! 4213 | * Chai - getActual utility 4214 | * Copyright(c) 2012-2014 Jake Luer 4215 | * MIT Licensed 4216 | */ 4217 | 4218 | /** 4219 | * # getActual(object, [actual]) 4220 | * 4221 | * Returns the `actual` value for an Assertion 4222 | * 4223 | * @param {Object} object (constructed Assertion) 4224 | * @param {Arguments} chai.Assertion.prototype.assert arguments 4225 | */ 4226 | 4227 | module.exports = function (obj, args) { 4228 | return args.length > 4 ? args[4] : obj._obj; 4229 | }; 4230 | 4231 | }); 4232 | 4233 | require.register("chai/lib/chai/utils/getEnumerableProperties.js", function (exports, module) { 4234 | /*! 4235 | * Chai - getEnumerableProperties utility 4236 | * Copyright(c) 2012-2014 Jake Luer 4237 | * MIT Licensed 4238 | */ 4239 | 4240 | /** 4241 | * ### .getEnumerableProperties(object) 4242 | * 4243 | * This allows the retrieval of enumerable property names of an object, 4244 | * inherited or not. 4245 | * 4246 | * @param {Object} object 4247 | * @returns {Array} 4248 | * @name getEnumerableProperties 4249 | * @api public 4250 | */ 4251 | 4252 | module.exports = function getEnumerableProperties(object) { 4253 | var result = []; 4254 | for (var name in object) { 4255 | result.push(name); 4256 | } 4257 | return result; 4258 | }; 4259 | 4260 | }); 4261 | 4262 | require.register("chai/lib/chai/utils/getMessage.js", function (exports, module) { 4263 | /*! 4264 | * Chai - message composition utility 4265 | * Copyright(c) 2012-2014 Jake Luer 4266 | * MIT Licensed 4267 | */ 4268 | 4269 | /*! 4270 | * Module dependancies 4271 | */ 4272 | 4273 | var flag = require('chai/lib/chai/utils/flag.js') 4274 | , getActual = require('chai/lib/chai/utils/getActual.js') 4275 | , inspect = require('chai/lib/chai/utils/inspect.js') 4276 | , objDisplay = require('chai/lib/chai/utils/objDisplay.js'); 4277 | 4278 | /** 4279 | * ### .getMessage(object, message, negateMessage) 4280 | * 4281 | * Construct the error message based on flags 4282 | * and template tags. Template tags will return 4283 | * a stringified inspection of the object referenced. 4284 | * 4285 | * Message template tags: 4286 | * - `#{this}` current asserted object 4287 | * - `#{act}` actual value 4288 | * - `#{exp}` expected value 4289 | * 4290 | * @param {Object} object (constructed Assertion) 4291 | * @param {Arguments} chai.Assertion.prototype.assert arguments 4292 | * @name getMessage 4293 | * @api public 4294 | */ 4295 | 4296 | module.exports = function (obj, args) { 4297 | var negate = flag(obj, 'negate') 4298 | , val = flag(obj, 'object') 4299 | , expected = args[3] 4300 | , actual = getActual(obj, args) 4301 | , msg = negate ? args[2] : args[1] 4302 | , flagMsg = flag(obj, 'message'); 4303 | 4304 | if(typeof msg === "function") msg = msg(); 4305 | msg = msg || ''; 4306 | msg = msg 4307 | .replace(/#{this}/g, objDisplay(val)) 4308 | .replace(/#{act}/g, objDisplay(actual)) 4309 | .replace(/#{exp}/g, objDisplay(expected)); 4310 | 4311 | return flagMsg ? flagMsg + ': ' + msg : msg; 4312 | }; 4313 | 4314 | }); 4315 | 4316 | require.register("chai/lib/chai/utils/getName.js", function (exports, module) { 4317 | /*! 4318 | * Chai - getName utility 4319 | * Copyright(c) 2012-2014 Jake Luer 4320 | * MIT Licensed 4321 | */ 4322 | 4323 | /** 4324 | * # getName(func) 4325 | * 4326 | * Gets the name of a function, in a cross-browser way. 4327 | * 4328 | * @param {Function} a function (usually a constructor) 4329 | */ 4330 | 4331 | module.exports = function (func) { 4332 | if (func.name) return func.name; 4333 | 4334 | var match = /^\s?function ([^(]*)\(/.exec(func); 4335 | return match && match[1] ? match[1] : ""; 4336 | }; 4337 | 4338 | }); 4339 | 4340 | require.register("chai/lib/chai/utils/getPathValue.js", function (exports, module) { 4341 | /*! 4342 | * Chai - getPathValue utility 4343 | * Copyright(c) 2012-2014 Jake Luer 4344 | * @see https://github.com/logicalparadox/filtr 4345 | * MIT Licensed 4346 | */ 4347 | 4348 | var getPathInfo = require('chai/lib/chai/utils/getPathInfo.js'); 4349 | 4350 | /** 4351 | * ### .getPathValue(path, object) 4352 | * 4353 | * This allows the retrieval of values in an 4354 | * object given a string path. 4355 | * 4356 | * var obj = { 4357 | * prop1: { 4358 | * arr: ['a', 'b', 'c'] 4359 | * , str: 'Hello' 4360 | * } 4361 | * , prop2: { 4362 | * arr: [ { nested: 'Universe' } ] 4363 | * , str: 'Hello again!' 4364 | * } 4365 | * } 4366 | * 4367 | * The following would be the results. 4368 | * 4369 | * getPathValue('prop1.str', obj); // Hello 4370 | * getPathValue('prop1.att[2]', obj); // b 4371 | * getPathValue('prop2.arr[0].nested', obj); // Universe 4372 | * 4373 | * @param {String} path 4374 | * @param {Object} object 4375 | * @returns {Object} value or `undefined` 4376 | * @name getPathValue 4377 | * @api public 4378 | */ 4379 | module.exports = function(path, obj) { 4380 | var info = getPathInfo(path, obj); 4381 | return info.value; 4382 | }; 4383 | 4384 | }); 4385 | 4386 | require.register("chai/lib/chai/utils/getPathInfo.js", function (exports, module) { 4387 | /*! 4388 | * Chai - getPathInfo utility 4389 | * Copyright(c) 2012-2014 Jake Luer 4390 | * MIT Licensed 4391 | */ 4392 | 4393 | var hasProperty = require('chai/lib/chai/utils/hasProperty.js'); 4394 | 4395 | /** 4396 | * ### .getPathInfo(path, object) 4397 | * 4398 | * This allows the retrieval of property info in an 4399 | * object given a string path. 4400 | * 4401 | * The path info consists of an object with the 4402 | * following properties: 4403 | * 4404 | * * parent - The parent object of the property referenced by `path` 4405 | * * name - The name of the final property, a number if it was an array indexer 4406 | * * value - The value of the property, if it exists, otherwise `undefined` 4407 | * * exists - Whether the property exists or not 4408 | * 4409 | * @param {String} path 4410 | * @param {Object} object 4411 | * @returns {Object} info 4412 | * @name getPathInfo 4413 | * @api public 4414 | */ 4415 | 4416 | module.exports = function getPathInfo(path, obj) { 4417 | var parsed = parsePath(path), 4418 | last = parsed[parsed.length - 1]; 4419 | 4420 | var info = { 4421 | parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, 4422 | name: last.p || last.i, 4423 | value: _getPathValue(parsed, obj), 4424 | }; 4425 | info.exists = hasProperty(info.name, info.parent); 4426 | 4427 | return info; 4428 | }; 4429 | 4430 | 4431 | /*! 4432 | * ## parsePath(path) 4433 | * 4434 | * Helper function used to parse string object 4435 | * paths. Use in conjunction with `_getPathValue`. 4436 | * 4437 | * var parsed = parsePath('myobject.property.subprop'); 4438 | * 4439 | * ### Paths: 4440 | * 4441 | * * Can be as near infinitely deep and nested 4442 | * * Arrays are also valid using the formal `myobject.document[3].property`. 4443 | * * Literal dots and brackets (not delimiter) must be backslash-escaped. 4444 | * 4445 | * @param {String} path 4446 | * @returns {Object} parsed 4447 | * @api private 4448 | */ 4449 | 4450 | function parsePath (path) { 4451 | var str = path.replace(/([^\\])\[/g, '$1.[') 4452 | , parts = str.match(/(\\\.|[^.]+?)+/g); 4453 | return parts.map(function (value) { 4454 | var re = /^\[(\d+)\]$/ 4455 | , mArr = re.exec(value); 4456 | if (mArr) return { i: parseFloat(mArr[1]) }; 4457 | else return { p: value.replace(/\\([.\[\]])/g, '$1') }; 4458 | }); 4459 | } 4460 | 4461 | 4462 | /*! 4463 | * ## _getPathValue(parsed, obj) 4464 | * 4465 | * Helper companion function for `.parsePath` that returns 4466 | * the value located at the parsed address. 4467 | * 4468 | * var value = getPathValue(parsed, obj); 4469 | * 4470 | * @param {Object} parsed definition from `parsePath`. 4471 | * @param {Object} object to search against 4472 | * @param {Number} object to search against 4473 | * @returns {Object|Undefined} value 4474 | * @api private 4475 | */ 4476 | 4477 | function _getPathValue (parsed, obj, index) { 4478 | var tmp = obj 4479 | , res; 4480 | 4481 | index = (index === undefined ? parsed.length : index); 4482 | 4483 | for (var i = 0, l = index; i < l; i++) { 4484 | var part = parsed[i]; 4485 | if (tmp) { 4486 | if ('undefined' !== typeof part.p) 4487 | tmp = tmp[part.p]; 4488 | else if ('undefined' !== typeof part.i) 4489 | tmp = tmp[part.i]; 4490 | if (i == (l - 1)) res = tmp; 4491 | } else { 4492 | res = undefined; 4493 | } 4494 | } 4495 | return res; 4496 | } 4497 | 4498 | }); 4499 | 4500 | require.register("chai/lib/chai/utils/hasProperty.js", function (exports, module) { 4501 | /*! 4502 | * Chai - hasProperty utility 4503 | * Copyright(c) 2012-2014 Jake Luer 4504 | * MIT Licensed 4505 | */ 4506 | 4507 | var type = require('chai/lib/chai/utils/type.js'); 4508 | 4509 | /** 4510 | * ### .hasProperty(object, name) 4511 | * 4512 | * This allows checking whether an object has 4513 | * named property or numeric array index. 4514 | * 4515 | * Basically does the same thing as the `in` 4516 | * operator but works properly with natives 4517 | * and null/undefined values. 4518 | * 4519 | * var obj = { 4520 | * arr: ['a', 'b', 'c'] 4521 | * , str: 'Hello' 4522 | * } 4523 | * 4524 | * The following would be the results. 4525 | * 4526 | * hasProperty('str', obj); // true 4527 | * hasProperty('constructor', obj); // true 4528 | * hasProperty('bar', obj); // false 4529 | * 4530 | * hasProperty('length', obj.str); // true 4531 | * hasProperty(1, obj.str); // true 4532 | * hasProperty(5, obj.str); // false 4533 | * 4534 | * hasProperty('length', obj.arr); // true 4535 | * hasProperty(2, obj.arr); // true 4536 | * hasProperty(3, obj.arr); // false 4537 | * 4538 | * @param {Objuect} object 4539 | * @param {String|Number} name 4540 | * @returns {Boolean} whether it exists 4541 | * @name getPathInfo 4542 | * @api public 4543 | */ 4544 | 4545 | var literals = { 4546 | 'number': Number 4547 | , 'string': String 4548 | }; 4549 | 4550 | module.exports = function hasProperty(name, obj) { 4551 | var ot = type(obj); 4552 | 4553 | // Bad Object, obviously no props at all 4554 | if(ot === 'null' || ot === 'undefined') 4555 | return false; 4556 | 4557 | // The `in` operator does not work with certain literals 4558 | // box these before the check 4559 | if(literals[ot] && typeof obj !== 'object') 4560 | obj = new literals[ot](obj); 4561 | 4562 | return name in obj; 4563 | }; 4564 | 4565 | }); 4566 | 4567 | require.register("chai/lib/chai/utils/getProperties.js", function (exports, module) { 4568 | /*! 4569 | * Chai - getProperties utility 4570 | * Copyright(c) 2012-2014 Jake Luer 4571 | * MIT Licensed 4572 | */ 4573 | 4574 | /** 4575 | * ### .getProperties(object) 4576 | * 4577 | * This allows the retrieval of property names of an object, enumerable or not, 4578 | * inherited or not. 4579 | * 4580 | * @param {Object} object 4581 | * @returns {Array} 4582 | * @name getProperties 4583 | * @api public 4584 | */ 4585 | 4586 | module.exports = function getProperties(object) { 4587 | var result = Object.getOwnPropertyNames(subject); 4588 | 4589 | function addProperty(property) { 4590 | if (result.indexOf(property) === -1) { 4591 | result.push(property); 4592 | } 4593 | } 4594 | 4595 | var proto = Object.getPrototypeOf(subject); 4596 | while (proto !== null) { 4597 | Object.getOwnPropertyNames(proto).forEach(addProperty); 4598 | proto = Object.getPrototypeOf(proto); 4599 | } 4600 | 4601 | return result; 4602 | }; 4603 | 4604 | }); 4605 | 4606 | require.register("chai/lib/chai/utils/index.js", function (exports, module) { 4607 | /*! 4608 | * chai 4609 | * Copyright(c) 2011 Jake Luer 4610 | * MIT Licensed 4611 | */ 4612 | 4613 | /*! 4614 | * Main exports 4615 | */ 4616 | 4617 | var exports = module.exports = {}; 4618 | 4619 | /*! 4620 | * test utility 4621 | */ 4622 | 4623 | exports.test = require('chai/lib/chai/utils/test.js'); 4624 | 4625 | /*! 4626 | * type utility 4627 | */ 4628 | 4629 | exports.type = require('chai/lib/chai/utils/type.js'); 4630 | 4631 | /*! 4632 | * message utility 4633 | */ 4634 | 4635 | exports.getMessage = require('chai/lib/chai/utils/getMessage.js'); 4636 | 4637 | /*! 4638 | * actual utility 4639 | */ 4640 | 4641 | exports.getActual = require('chai/lib/chai/utils/getActual.js'); 4642 | 4643 | /*! 4644 | * Inspect util 4645 | */ 4646 | 4647 | exports.inspect = require('chai/lib/chai/utils/inspect.js'); 4648 | 4649 | /*! 4650 | * Object Display util 4651 | */ 4652 | 4653 | exports.objDisplay = require('chai/lib/chai/utils/objDisplay.js'); 4654 | 4655 | /*! 4656 | * Flag utility 4657 | */ 4658 | 4659 | exports.flag = require('chai/lib/chai/utils/flag.js'); 4660 | 4661 | /*! 4662 | * Flag transferring utility 4663 | */ 4664 | 4665 | exports.transferFlags = require('chai/lib/chai/utils/transferFlags.js'); 4666 | 4667 | /*! 4668 | * Deep equal utility 4669 | */ 4670 | 4671 | exports.eql = require('chaijs~deep-eql@0.1.3'); 4672 | 4673 | /*! 4674 | * Deep path value 4675 | */ 4676 | 4677 | exports.getPathValue = require('chai/lib/chai/utils/getPathValue.js'); 4678 | 4679 | /*! 4680 | * Deep path info 4681 | */ 4682 | 4683 | exports.getPathInfo = require('chai/lib/chai/utils/getPathInfo.js'); 4684 | 4685 | /*! 4686 | * Check if a property exists 4687 | */ 4688 | 4689 | exports.hasProperty = require('chai/lib/chai/utils/hasProperty.js'); 4690 | 4691 | /*! 4692 | * Function name 4693 | */ 4694 | 4695 | exports.getName = require('chai/lib/chai/utils/getName.js'); 4696 | 4697 | /*! 4698 | * add Property 4699 | */ 4700 | 4701 | exports.addProperty = require('chai/lib/chai/utils/addProperty.js'); 4702 | 4703 | /*! 4704 | * add Method 4705 | */ 4706 | 4707 | exports.addMethod = require('chai/lib/chai/utils/addMethod.js'); 4708 | 4709 | /*! 4710 | * overwrite Property 4711 | */ 4712 | 4713 | exports.overwriteProperty = require('chai/lib/chai/utils/overwriteProperty.js'); 4714 | 4715 | /*! 4716 | * overwrite Method 4717 | */ 4718 | 4719 | exports.overwriteMethod = require('chai/lib/chai/utils/overwriteMethod.js'); 4720 | 4721 | /*! 4722 | * Add a chainable method 4723 | */ 4724 | 4725 | exports.addChainableMethod = require('chai/lib/chai/utils/addChainableMethod.js'); 4726 | 4727 | /*! 4728 | * Overwrite chainable method 4729 | */ 4730 | 4731 | exports.overwriteChainableMethod = require('chai/lib/chai/utils/overwriteChainableMethod.js'); 4732 | 4733 | 4734 | }); 4735 | 4736 | require.register("chai/lib/chai/utils/inspect.js", function (exports, module) { 4737 | // This is (almost) directly from Node.js utils 4738 | // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js 4739 | 4740 | var getName = require('chai/lib/chai/utils/getName.js'); 4741 | var getProperties = require('chai/lib/chai/utils/getProperties.js'); 4742 | var getEnumerableProperties = require('chai/lib/chai/utils/getEnumerableProperties.js'); 4743 | 4744 | module.exports = inspect; 4745 | 4746 | /** 4747 | * Echos the value of a value. Trys to print the value out 4748 | * in the best way possible given the different types. 4749 | * 4750 | * @param {Object} obj The object to print out. 4751 | * @param {Boolean} showHidden Flag that shows hidden (not enumerable) 4752 | * properties of objects. 4753 | * @param {Number} depth Depth in which to descend in object. Default is 2. 4754 | * @param {Boolean} colors Flag to turn on ANSI escape codes to color the 4755 | * output. Default is false (no coloring). 4756 | */ 4757 | function inspect(obj, showHidden, depth, colors) { 4758 | var ctx = { 4759 | showHidden: showHidden, 4760 | seen: [], 4761 | stylize: function (str) { return str; } 4762 | }; 4763 | return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); 4764 | } 4765 | 4766 | // Returns true if object is a DOM element. 4767 | var isDOMElement = function (object) { 4768 | if (typeof HTMLElement === 'object') { 4769 | return object instanceof HTMLElement; 4770 | } else { 4771 | return object && 4772 | typeof object === 'object' && 4773 | object.nodeType === 1 && 4774 | typeof object.nodeName === 'string'; 4775 | } 4776 | }; 4777 | 4778 | function formatValue(ctx, value, recurseTimes) { 4779 | // Provide a hook for user-specified inspect functions. 4780 | // Check that value is an object with an inspect function on it 4781 | if (value && typeof value.inspect === 'function' && 4782 | // Filter out the util module, it's inspect function is special 4783 | value.inspect !== exports.inspect && 4784 | // Also filter out any prototype objects using the circular check. 4785 | !(value.constructor && value.constructor.prototype === value)) { 4786 | var ret = value.inspect(recurseTimes); 4787 | if (typeof ret !== 'string') { 4788 | ret = formatValue(ctx, ret, recurseTimes); 4789 | } 4790 | return ret; 4791 | } 4792 | 4793 | // Primitive types cannot have properties 4794 | var primitive = formatPrimitive(ctx, value); 4795 | if (primitive) { 4796 | return primitive; 4797 | } 4798 | 4799 | // If this is a DOM element, try to get the outer HTML. 4800 | if (isDOMElement(value)) { 4801 | if ('outerHTML' in value) { 4802 | return value.outerHTML; 4803 | // This value does not have an outerHTML attribute, 4804 | // it could still be an XML element 4805 | } else { 4806 | // Attempt to serialize it 4807 | try { 4808 | if (document.xmlVersion) { 4809 | var xmlSerializer = new XMLSerializer(); 4810 | return xmlSerializer.serializeToString(value); 4811 | } else { 4812 | // Firefox 11- do not support outerHTML 4813 | // It does, however, support innerHTML 4814 | // Use the following to render the element 4815 | var ns = "http://www.w3.org/1999/xhtml"; 4816 | var container = document.createElementNS(ns, '_'); 4817 | 4818 | container.appendChild(value.cloneNode(false)); 4819 | html = container.innerHTML 4820 | .replace('><', '>' + value.innerHTML + '<'); 4821 | container.innerHTML = ''; 4822 | return html; 4823 | } 4824 | } catch (err) { 4825 | // This could be a non-native DOM implementation, 4826 | // continue with the normal flow: 4827 | // printing the element as if it is an object. 4828 | } 4829 | } 4830 | } 4831 | 4832 | // Look up the keys of the object. 4833 | var visibleKeys = getEnumerableProperties(value); 4834 | var keys = ctx.showHidden ? getProperties(value) : visibleKeys; 4835 | 4836 | // Some type of object without properties can be shortcutted. 4837 | // In IE, errors have a single `stack` property, or if they are vanilla `Error`, 4838 | // a `stack` plus `description` property; ignore those for consistency. 4839 | if (keys.length === 0 || (isError(value) && ( 4840 | (keys.length === 1 && keys[0] === 'stack') || 4841 | (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') 4842 | ))) { 4843 | if (typeof value === 'function') { 4844 | var name = getName(value); 4845 | var nameSuffix = name ? ': ' + name : ''; 4846 | return ctx.stylize('[Function' + nameSuffix + ']', 'special'); 4847 | } 4848 | if (isRegExp(value)) { 4849 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 4850 | } 4851 | if (isDate(value)) { 4852 | return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); 4853 | } 4854 | if (isError(value)) { 4855 | return formatError(value); 4856 | } 4857 | } 4858 | 4859 | var base = '', array = false, braces = ['{', '}']; 4860 | 4861 | // Make Array say that they are Array 4862 | if (isArray(value)) { 4863 | array = true; 4864 | braces = ['[', ']']; 4865 | } 4866 | 4867 | // Make functions say that they are functions 4868 | if (typeof value === 'function') { 4869 | var name = getName(value); 4870 | var nameSuffix = name ? ': ' + name : ''; 4871 | base = ' [Function' + nameSuffix + ']'; 4872 | } 4873 | 4874 | // Make RegExps say that they are RegExps 4875 | if (isRegExp(value)) { 4876 | base = ' ' + RegExp.prototype.toString.call(value); 4877 | } 4878 | 4879 | // Make dates with properties first say the date 4880 | if (isDate(value)) { 4881 | base = ' ' + Date.prototype.toUTCString.call(value); 4882 | } 4883 | 4884 | // Make error with message first say the error 4885 | if (isError(value)) { 4886 | return formatError(value); 4887 | } 4888 | 4889 | if (keys.length === 0 && (!array || value.length == 0)) { 4890 | return braces[0] + base + braces[1]; 4891 | } 4892 | 4893 | if (recurseTimes < 0) { 4894 | if (isRegExp(value)) { 4895 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 4896 | } else { 4897 | return ctx.stylize('[Object]', 'special'); 4898 | } 4899 | } 4900 | 4901 | ctx.seen.push(value); 4902 | 4903 | var output; 4904 | if (array) { 4905 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 4906 | } else { 4907 | output = keys.map(function(key) { 4908 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 4909 | }); 4910 | } 4911 | 4912 | ctx.seen.pop(); 4913 | 4914 | return reduceToSingleString(output, base, braces); 4915 | } 4916 | 4917 | 4918 | function formatPrimitive(ctx, value) { 4919 | switch (typeof value) { 4920 | case 'undefined': 4921 | return ctx.stylize('undefined', 'undefined'); 4922 | 4923 | case 'string': 4924 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 4925 | .replace(/'/g, "\\'") 4926 | .replace(/\\"/g, '"') + '\''; 4927 | return ctx.stylize(simple, 'string'); 4928 | 4929 | case 'number': 4930 | if (value === 0 && (1/value) === -Infinity) { 4931 | return ctx.stylize('-0', 'number'); 4932 | } 4933 | return ctx.stylize('' + value, 'number'); 4934 | 4935 | case 'boolean': 4936 | return ctx.stylize('' + value, 'boolean'); 4937 | } 4938 | // For some reason typeof null is "object", so special case here. 4939 | if (value === null) { 4940 | return ctx.stylize('null', 'null'); 4941 | } 4942 | } 4943 | 4944 | 4945 | function formatError(value) { 4946 | return '[' + Error.prototype.toString.call(value) + ']'; 4947 | } 4948 | 4949 | 4950 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 4951 | var output = []; 4952 | for (var i = 0, l = value.length; i < l; ++i) { 4953 | if (Object.prototype.hasOwnProperty.call(value, String(i))) { 4954 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 4955 | String(i), true)); 4956 | } else { 4957 | output.push(''); 4958 | } 4959 | } 4960 | keys.forEach(function(key) { 4961 | if (!key.match(/^\d+$/)) { 4962 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 4963 | key, true)); 4964 | } 4965 | }); 4966 | return output; 4967 | } 4968 | 4969 | 4970 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 4971 | var name, str; 4972 | if (value.__lookupGetter__) { 4973 | if (value.__lookupGetter__(key)) { 4974 | if (value.__lookupSetter__(key)) { 4975 | str = ctx.stylize('[Getter/Setter]', 'special'); 4976 | } else { 4977 | str = ctx.stylize('[Getter]', 'special'); 4978 | } 4979 | } else { 4980 | if (value.__lookupSetter__(key)) { 4981 | str = ctx.stylize('[Setter]', 'special'); 4982 | } 4983 | } 4984 | } 4985 | if (visibleKeys.indexOf(key) < 0) { 4986 | name = '[' + key + ']'; 4987 | } 4988 | if (!str) { 4989 | if (ctx.seen.indexOf(value[key]) < 0) { 4990 | if (recurseTimes === null) { 4991 | str = formatValue(ctx, value[key], null); 4992 | } else { 4993 | str = formatValue(ctx, value[key], recurseTimes - 1); 4994 | } 4995 | if (str.indexOf('\n') > -1) { 4996 | if (array) { 4997 | str = str.split('\n').map(function(line) { 4998 | return ' ' + line; 4999 | }).join('\n').substr(2); 5000 | } else { 5001 | str = '\n' + str.split('\n').map(function(line) { 5002 | return ' ' + line; 5003 | }).join('\n'); 5004 | } 5005 | } 5006 | } else { 5007 | str = ctx.stylize('[Circular]', 'special'); 5008 | } 5009 | } 5010 | if (typeof name === 'undefined') { 5011 | if (array && key.match(/^\d+$/)) { 5012 | return str; 5013 | } 5014 | name = JSON.stringify('' + key); 5015 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 5016 | name = name.substr(1, name.length - 2); 5017 | name = ctx.stylize(name, 'name'); 5018 | } else { 5019 | name = name.replace(/'/g, "\\'") 5020 | .replace(/\\"/g, '"') 5021 | .replace(/(^"|"$)/g, "'"); 5022 | name = ctx.stylize(name, 'string'); 5023 | } 5024 | } 5025 | 5026 | return name + ': ' + str; 5027 | } 5028 | 5029 | 5030 | function reduceToSingleString(output, base, braces) { 5031 | var numLinesEst = 0; 5032 | var length = output.reduce(function(prev, cur) { 5033 | numLinesEst++; 5034 | if (cur.indexOf('\n') >= 0) numLinesEst++; 5035 | return prev + cur.length + 1; 5036 | }, 0); 5037 | 5038 | if (length > 60) { 5039 | return braces[0] + 5040 | (base === '' ? '' : base + '\n ') + 5041 | ' ' + 5042 | output.join(',\n ') + 5043 | ' ' + 5044 | braces[1]; 5045 | } 5046 | 5047 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 5048 | } 5049 | 5050 | function isArray(ar) { 5051 | return Array.isArray(ar) || 5052 | (typeof ar === 'object' && objectToString(ar) === '[object Array]'); 5053 | } 5054 | 5055 | function isRegExp(re) { 5056 | return typeof re === 'object' && objectToString(re) === '[object RegExp]'; 5057 | } 5058 | 5059 | function isDate(d) { 5060 | return typeof d === 'object' && objectToString(d) === '[object Date]'; 5061 | } 5062 | 5063 | function isError(e) { 5064 | return typeof e === 'object' && objectToString(e) === '[object Error]'; 5065 | } 5066 | 5067 | function objectToString(o) { 5068 | return Object.prototype.toString.call(o); 5069 | } 5070 | 5071 | }); 5072 | 5073 | require.register("chai/lib/chai/utils/objDisplay.js", function (exports, module) { 5074 | /*! 5075 | * Chai - flag utility 5076 | * Copyright(c) 2012-2014 Jake Luer 5077 | * MIT Licensed 5078 | */ 5079 | 5080 | /*! 5081 | * Module dependancies 5082 | */ 5083 | 5084 | var inspect = require('chai/lib/chai/utils/inspect.js'); 5085 | var config = require('chai/lib/chai/config.js'); 5086 | 5087 | /** 5088 | * ### .objDisplay (object) 5089 | * 5090 | * Determines if an object or an array matches 5091 | * criteria to be inspected in-line for error 5092 | * messages or should be truncated. 5093 | * 5094 | * @param {Mixed} javascript object to inspect 5095 | * @name objDisplay 5096 | * @api public 5097 | */ 5098 | 5099 | module.exports = function (obj) { 5100 | var str = inspect(obj) 5101 | , type = Object.prototype.toString.call(obj); 5102 | 5103 | if (config.truncateThreshold && str.length >= config.truncateThreshold) { 5104 | if (type === '[object Function]') { 5105 | return !obj.name || obj.name === '' 5106 | ? '[Function]' 5107 | : '[Function: ' + obj.name + ']'; 5108 | } else if (type === '[object Array]') { 5109 | return '[ Array(' + obj.length + ') ]'; 5110 | } else if (type === '[object Object]') { 5111 | var keys = Object.keys(obj) 5112 | , kstr = keys.length > 2 5113 | ? keys.splice(0, 2).join(', ') + ', ...' 5114 | : keys.join(', '); 5115 | return '{ Object (' + kstr + ') }'; 5116 | } else { 5117 | return str; 5118 | } 5119 | } else { 5120 | return str; 5121 | } 5122 | }; 5123 | 5124 | }); 5125 | 5126 | require.register("chai/lib/chai/utils/overwriteMethod.js", function (exports, module) { 5127 | /*! 5128 | * Chai - overwriteMethod utility 5129 | * Copyright(c) 2012-2014 Jake Luer 5130 | * MIT Licensed 5131 | */ 5132 | 5133 | /** 5134 | * ### overwriteMethod (ctx, name, fn) 5135 | * 5136 | * Overwites an already existing method and provides 5137 | * access to previous function. Must return function 5138 | * to be used for name. 5139 | * 5140 | * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { 5141 | * return function (str) { 5142 | * var obj = utils.flag(this, 'object'); 5143 | * if (obj instanceof Foo) { 5144 | * new chai.Assertion(obj.value).to.equal(str); 5145 | * } else { 5146 | * _super.apply(this, arguments); 5147 | * } 5148 | * } 5149 | * }); 5150 | * 5151 | * Can also be accessed directly from `chai.Assertion`. 5152 | * 5153 | * chai.Assertion.overwriteMethod('foo', fn); 5154 | * 5155 | * Then can be used as any other assertion. 5156 | * 5157 | * expect(myFoo).to.equal('bar'); 5158 | * 5159 | * @param {Object} ctx object whose method is to be overwritten 5160 | * @param {String} name of method to overwrite 5161 | * @param {Function} method function that returns a function to be used for name 5162 | * @name overwriteMethod 5163 | * @api public 5164 | */ 5165 | 5166 | module.exports = function (ctx, name, method) { 5167 | var _method = ctx[name] 5168 | , _super = function () { return this; }; 5169 | 5170 | if (_method && 'function' === typeof _method) 5171 | _super = _method; 5172 | 5173 | ctx[name] = function () { 5174 | var result = method(_super).apply(this, arguments); 5175 | return result === undefined ? this : result; 5176 | } 5177 | }; 5178 | 5179 | }); 5180 | 5181 | require.register("chai/lib/chai/utils/overwriteProperty.js", function (exports, module) { 5182 | /*! 5183 | * Chai - overwriteProperty utility 5184 | * Copyright(c) 2012-2014 Jake Luer 5185 | * MIT Licensed 5186 | */ 5187 | 5188 | /** 5189 | * ### overwriteProperty (ctx, name, fn) 5190 | * 5191 | * Overwites an already existing property getter and provides 5192 | * access to previous value. Must return function to use as getter. 5193 | * 5194 | * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { 5195 | * return function () { 5196 | * var obj = utils.flag(this, 'object'); 5197 | * if (obj instanceof Foo) { 5198 | * new chai.Assertion(obj.name).to.equal('bar'); 5199 | * } else { 5200 | * _super.call(this); 5201 | * } 5202 | * } 5203 | * }); 5204 | * 5205 | * 5206 | * Can also be accessed directly from `chai.Assertion`. 5207 | * 5208 | * chai.Assertion.overwriteProperty('foo', fn); 5209 | * 5210 | * Then can be used as any other assertion. 5211 | * 5212 | * expect(myFoo).to.be.ok; 5213 | * 5214 | * @param {Object} ctx object whose property is to be overwritten 5215 | * @param {String} name of property to overwrite 5216 | * @param {Function} getter function that returns a getter function to be used for name 5217 | * @name overwriteProperty 5218 | * @api public 5219 | */ 5220 | 5221 | module.exports = function (ctx, name, getter) { 5222 | var _get = Object.getOwnPropertyDescriptor(ctx, name) 5223 | , _super = function () {}; 5224 | 5225 | if (_get && 'function' === typeof _get.get) 5226 | _super = _get.get 5227 | 5228 | Object.defineProperty(ctx, name, 5229 | { get: function () { 5230 | var result = getter(_super).call(this); 5231 | return result === undefined ? this : result; 5232 | } 5233 | , configurable: true 5234 | }); 5235 | }; 5236 | 5237 | }); 5238 | 5239 | require.register("chai/lib/chai/utils/overwriteChainableMethod.js", function (exports, module) { 5240 | /*! 5241 | * Chai - overwriteChainableMethod utility 5242 | * Copyright(c) 2012-2014 Jake Luer 5243 | * MIT Licensed 5244 | */ 5245 | 5246 | /** 5247 | * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) 5248 | * 5249 | * Overwites an already existing chainable method 5250 | * and provides access to the previous function or 5251 | * property. Must return functions to be used for 5252 | * name. 5253 | * 5254 | * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', 5255 | * function (_super) { 5256 | * } 5257 | * , function (_super) { 5258 | * } 5259 | * ); 5260 | * 5261 | * Can also be accessed directly from `chai.Assertion`. 5262 | * 5263 | * chai.Assertion.overwriteChainableMethod('foo', fn, fn); 5264 | * 5265 | * Then can be used as any other assertion. 5266 | * 5267 | * expect(myFoo).to.have.length(3); 5268 | * expect(myFoo).to.have.length.above(3); 5269 | * 5270 | * @param {Object} ctx object whose method / property is to be overwritten 5271 | * @param {String} name of method / property to overwrite 5272 | * @param {Function} method function that returns a function to be used for name 5273 | * @param {Function} chainingBehavior function that returns a function to be used for property 5274 | * @name overwriteChainableMethod 5275 | * @api public 5276 | */ 5277 | 5278 | module.exports = function (ctx, name, method, chainingBehavior) { 5279 | var chainableBehavior = ctx.__methods[name]; 5280 | 5281 | var _chainingBehavior = chainableBehavior.chainingBehavior; 5282 | chainableBehavior.chainingBehavior = function () { 5283 | var result = chainingBehavior(_chainingBehavior).call(this); 5284 | return result === undefined ? this : result; 5285 | }; 5286 | 5287 | var _method = chainableBehavior.method; 5288 | chainableBehavior.method = function () { 5289 | var result = method(_method).apply(this, arguments); 5290 | return result === undefined ? this : result; 5291 | }; 5292 | }; 5293 | 5294 | }); 5295 | 5296 | require.register("chai/lib/chai/utils/test.js", function (exports, module) { 5297 | /*! 5298 | * Chai - test utility 5299 | * Copyright(c) 2012-2014 Jake Luer 5300 | * MIT Licensed 5301 | */ 5302 | 5303 | /*! 5304 | * Module dependancies 5305 | */ 5306 | 5307 | var flag = require('chai/lib/chai/utils/flag.js'); 5308 | 5309 | /** 5310 | * # test(object, expression) 5311 | * 5312 | * Test and object for expression. 5313 | * 5314 | * @param {Object} object (constructed Assertion) 5315 | * @param {Arguments} chai.Assertion.prototype.assert arguments 5316 | */ 5317 | 5318 | module.exports = function (obj, args) { 5319 | var negate = flag(obj, 'negate') 5320 | , expr = args[0]; 5321 | return negate ? !expr : expr; 5322 | }; 5323 | 5324 | }); 5325 | 5326 | require.register("chai/lib/chai/utils/transferFlags.js", function (exports, module) { 5327 | /*! 5328 | * Chai - transferFlags utility 5329 | * Copyright(c) 2012-2014 Jake Luer 5330 | * MIT Licensed 5331 | */ 5332 | 5333 | /** 5334 | * ### transferFlags(assertion, object, includeAll = true) 5335 | * 5336 | * Transfer all the flags for `assertion` to `object`. If 5337 | * `includeAll` is set to `false`, then the base Chai 5338 | * assertion flags (namely `object`, `ssfi`, and `message`) 5339 | * will not be transferred. 5340 | * 5341 | * 5342 | * var newAssertion = new Assertion(); 5343 | * utils.transferFlags(assertion, newAssertion); 5344 | * 5345 | * var anotherAsseriton = new Assertion(myObj); 5346 | * utils.transferFlags(assertion, anotherAssertion, false); 5347 | * 5348 | * @param {Assertion} assertion the assertion to transfer the flags from 5349 | * @param {Object} object the object to transfer the flags to; usually a new assertion 5350 | * @param {Boolean} includeAll 5351 | * @name transferFlags 5352 | * @api private 5353 | */ 5354 | 5355 | module.exports = function (assertion, object, includeAll) { 5356 | var flags = assertion.__flags || (assertion.__flags = Object.create(null)); 5357 | 5358 | if (!object.__flags) { 5359 | object.__flags = Object.create(null); 5360 | } 5361 | 5362 | includeAll = arguments.length === 3 ? includeAll : true; 5363 | 5364 | for (var flag in flags) { 5365 | if (includeAll || 5366 | (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { 5367 | object.__flags[flag] = flags[flag]; 5368 | } 5369 | } 5370 | }; 5371 | 5372 | }); 5373 | 5374 | require.register("chai/lib/chai/utils/type.js", function (exports, module) { 5375 | /*! 5376 | * Chai - type utility 5377 | * Copyright(c) 2012-2014 Jake Luer 5378 | * MIT Licensed 5379 | */ 5380 | 5381 | /*! 5382 | * Detectable javascript natives 5383 | */ 5384 | 5385 | var natives = { 5386 | '[object Arguments]': 'arguments' 5387 | , '[object Array]': 'array' 5388 | , '[object Date]': 'date' 5389 | , '[object Function]': 'function' 5390 | , '[object Number]': 'number' 5391 | , '[object RegExp]': 'regexp' 5392 | , '[object String]': 'string' 5393 | }; 5394 | 5395 | /** 5396 | * ### type(object) 5397 | * 5398 | * Better implementation of `typeof` detection that can 5399 | * be used cross-browser. Handles the inconsistencies of 5400 | * Array, `null`, and `undefined` detection. 5401 | * 5402 | * utils.type({}) // 'object' 5403 | * utils.type(null) // `null' 5404 | * utils.type(undefined) // `undefined` 5405 | * utils.type([]) // `array` 5406 | * 5407 | * @param {Mixed} object to detect type of 5408 | * @name type 5409 | * @api private 5410 | */ 5411 | 5412 | module.exports = function (obj) { 5413 | var str = Object.prototype.toString.call(obj); 5414 | if (natives[str]) return natives[str]; 5415 | if (obj === null) return 'null'; 5416 | if (obj === undefined) return 'undefined'; 5417 | if (obj === Object(obj)) return 'object'; 5418 | return typeof obj; 5419 | }; 5420 | 5421 | }); 5422 | 5423 | if (typeof exports == "object") { 5424 | module.exports = require("chai"); 5425 | } else if (typeof define == "function" && define.amd) { 5426 | define("chai", [], function(){ return require("chai"); }); 5427 | } else { 5428 | (this || window)["chai"] = require("chai"); 5429 | } 5430 | })() 5431 | -------------------------------------------------------------------------------- /test/vendors/mocha-2.2.5/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | /** 140 | * (1): approximate for browsers not supporting calc 141 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 142 | * ^^ seriously 143 | */ 144 | #mocha .test pre { 145 | display: block; 146 | float: left; 147 | clear: left; 148 | font: 12px/1.5 monaco, monospace; 149 | margin: 5px; 150 | padding: 15px; 151 | border: 1px solid #eee; 152 | max-width: 85%; /*(1)*/ 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | word-wrap: break-word; 155 | border-bottom-color: #ddd; 156 | -webkit-border-radius: 3px; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-border-radius: 3px; 159 | -moz-box-shadow: 0 1px 3px #eee; 160 | border-radius: 3px; 161 | } 162 | 163 | #mocha .test h2 { 164 | position: relative; 165 | } 166 | 167 | #mocha .test a.replay { 168 | position: absolute; 169 | top: 3px; 170 | right: 0; 171 | text-decoration: none; 172 | vertical-align: middle; 173 | display: block; 174 | width: 15px; 175 | height: 15px; 176 | line-height: 15px; 177 | text-align: center; 178 | background: #eee; 179 | font-size: 15px; 180 | -moz-border-radius: 15px; 181 | border-radius: 15px; 182 | -webkit-transition: opacity 200ms; 183 | -moz-transition: opacity 200ms; 184 | transition: opacity 200ms; 185 | opacity: 0.3; 186 | color: #888; 187 | } 188 | 189 | #mocha .test:hover a.replay { 190 | opacity: 1; 191 | } 192 | 193 | #mocha-report.pass .test.fail { 194 | display: none; 195 | } 196 | 197 | #mocha-report.fail .test.pass { 198 | display: none; 199 | } 200 | 201 | #mocha-report.pending .test.pass, 202 | #mocha-report.pending .test.fail { 203 | display: none; 204 | } 205 | #mocha-report.pending .test.pass.pending { 206 | display: block; 207 | } 208 | 209 | #mocha-error { 210 | color: #c00; 211 | font-size: 1.5em; 212 | font-weight: 100; 213 | letter-spacing: 1px; 214 | } 215 | 216 | #mocha-stats { 217 | position: fixed; 218 | top: 15px; 219 | right: 10px; 220 | font-size: 12px; 221 | margin: 0; 222 | color: #888; 223 | z-index: 1; 224 | } 225 | 226 | #mocha-stats .progress { 227 | float: right; 228 | padding-top: 0; 229 | } 230 | 231 | #mocha-stats em { 232 | color: black; 233 | } 234 | 235 | #mocha-stats a { 236 | text-decoration: none; 237 | color: inherit; 238 | } 239 | 240 | #mocha-stats a:hover { 241 | border-bottom: 1px solid #eee; 242 | } 243 | 244 | #mocha-stats li { 245 | display: inline-block; 246 | margin: 0 5px; 247 | list-style: none; 248 | padding-top: 11px; 249 | } 250 | 251 | #mocha-stats canvas { 252 | width: 40px; 253 | height: 40px; 254 | } 255 | 256 | #mocha code .comment { color: #ddd; } 257 | #mocha code .init { color: #2f6fad; } 258 | #mocha code .string { color: #5890ad; } 259 | #mocha code .keyword { color: #8a6343; } 260 | #mocha code .number { color: #2f6fad; } 261 | 262 | @media screen and (max-device-width: 480px) { 263 | #mocha { 264 | margin: 60px 0px; 265 | } 266 | 267 | #mocha #stats { 268 | position: absolute; 269 | } 270 | } 271 | --------------------------------------------------------------------------------