├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin ├── common.sh ├── compile ├── detect └── test ├── test ├── caching │ ├── README.md │ └── package.json ├── dangerous-range-greater-than │ ├── README.md │ └── package.json ├── dangerous-range-star │ ├── README.md │ └── package.json ├── invalid-dependency │ ├── README.md │ └── package.json ├── invalid-node-version │ ├── README.md │ └── package.json ├── modules-checked-in │ ├── README.md │ ├── node_modules │ │ └── hashish │ │ │ ├── README.markdown │ │ │ ├── examples │ │ │ ├── chain.js │ │ │ └── map.js │ │ │ ├── index.js │ │ │ ├── node_modules │ │ │ └── traverse │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── examples │ │ │ │ ├── json.js │ │ │ │ ├── leaves.js │ │ │ │ ├── negative.js │ │ │ │ ├── scrub.js │ │ │ │ └── stringify.js │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ ├── readme.markdown │ │ │ │ ├── test │ │ │ │ ├── circular.js │ │ │ │ ├── date.js │ │ │ │ ├── equal.js │ │ │ │ ├── error.js │ │ │ │ ├── has.js │ │ │ │ ├── instance.js │ │ │ │ ├── interface.js │ │ │ │ ├── json.js │ │ │ │ ├── keys.js │ │ │ │ ├── leaves.js │ │ │ │ ├── lib │ │ │ │ │ └── deep_equal.js │ │ │ │ ├── mutability.js │ │ │ │ ├── negative.js │ │ │ │ ├── obj.js │ │ │ │ ├── siblings.js │ │ │ │ ├── stop.js │ │ │ │ ├── stringify.js │ │ │ │ ├── subexpr.js │ │ │ │ └── super_deep.js │ │ │ │ └── testling │ │ │ │ └── leaves.js │ │ │ ├── package.json │ │ │ └── test │ │ │ ├── hash.js │ │ │ └── property.js │ └── package.json ├── no-package-json │ └── Gemfile ├── no-script-hooks │ ├── README.md │ └── package.json ├── no-version │ ├── README.md │ └── package.json ├── range-with-space │ ├── README.md │ └── package.json ├── script-hooks │ ├── README.md │ └── package.json ├── stable-node │ ├── README.md │ └── package.json └── unstable-version │ ├── README.md │ └── package.json └── vendor ├── README ├── jq ├── shunit2 └── shunit2 └── test-utils └── test-utils /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Contributing ### 2 | 3 | Thank you for your interest in `strongloop-buildpacks`, an open source project 4 | administered by StrongLoop. 5 | 6 | Contributing to `strongloop-buildpacks` is easy. In a few simple steps: 7 | 8 | * Ensure that your effort is aligned with the project's roadmap by 9 | talking to the maintainers, especially if you are going to spend a 10 | lot of time on it. 11 | 12 | * Make something better or fix a bug. 13 | 14 | * Adhere to code style outlined in the [Google C++ Style Guide][] and 15 | [Google Javascript Style Guide][]. 16 | 17 | * Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/strongloop-buildpacks) 18 | 19 | * Submit a pull request through Github. 20 | 21 | 22 | ### Contributor License Agreement ### 23 | 24 | ``` 25 | Individual Contributor License Agreement 26 | 27 | By signing this Individual Contributor License Agreement 28 | ("Agreement"), and making a Contribution (as defined below) to 29 | StrongLoop, Inc. ("StrongLoop"), You (as defined below) accept and 30 | agree to the following terms and conditions for Your present and 31 | future Contributions submitted to StrongLoop. Except for the license 32 | granted in this Agreement to StrongLoop and recipients of software 33 | distributed by StrongLoop, You reserve all right, title, and interest 34 | in and to Your Contributions. 35 | 36 | 1. Definitions 37 | 38 | "You" or "Your" shall mean the copyright owner or the individual 39 | authorized by the copyright owner that is entering into this 40 | Agreement with StrongLoop. 41 | 42 | "Contribution" shall mean any original work of authorship, 43 | including any modifications or additions to an existing work, that 44 | is intentionally submitted by You to StrongLoop for inclusion in, 45 | or documentation of, any of the products owned or managed by 46 | StrongLoop ("Work"). For purposes of this definition, "submitted" 47 | means any form of electronic, verbal, or written communication 48 | sent to StrongLoop or its representatives, including but not 49 | limited to communication or electronic mailing lists, source code 50 | control systems, and issue tracking systems that are managed by, 51 | or on behalf of, StrongLoop for the purpose of discussing and 52 | improving the Work, but excluding communication that is 53 | conspicuously marked or otherwise designated in writing by You as 54 | "Not a Contribution." 55 | 56 | 2. You Grant a Copyright License to StrongLoop 57 | 58 | Subject to the terms and conditions of this Agreement, You hereby 59 | grant to StrongLoop and recipients of software distributed by 60 | StrongLoop, a perpetual, worldwide, non-exclusive, no-charge, 61 | royalty-free, irrevocable copyright license to reproduce, prepare 62 | derivative works of, publicly display, publicly perform, 63 | sublicense, and distribute Your Contributions and such derivative 64 | works under any license and without any restrictions. 65 | 66 | 3. You Grant a Patent License to StrongLoop 67 | 68 | Subject to the terms and conditions of this Agreement, You hereby 69 | grant to StrongLoop and to recipients of software distributed by 70 | StrongLoop a perpetual, worldwide, non-exclusive, no-charge, 71 | royalty-free, irrevocable (except as stated in this Section) 72 | patent license to make, have made, use, offer to sell, sell, 73 | import, and otherwise transfer the Work under any license and 74 | without any restrictions. The patent license You grant to 75 | StrongLoop under this Section applies only to those patent claims 76 | licensable by You that are necessarily infringed by Your 77 | Contributions(s) alone or by combination of Your Contributions(s) 78 | with the Work to which such Contribution(s) was submitted. If any 79 | entity institutes a patent litigation against You or any other 80 | entity (including a cross-claim or counterclaim in a lawsuit) 81 | alleging that Your Contribution, or the Work to which You have 82 | contributed, constitutes direct or contributory patent 83 | infringement, any patent licenses granted to that entity under 84 | this Agreement for that Contribution or Work shall terminate as 85 | of the date such litigation is filed. 86 | 87 | 4. You Have the Right to Grant Licenses to StrongLoop 88 | 89 | You represent that You are legally entitled to grant the licenses 90 | in this Agreement. 91 | 92 | If Your employer(s) has rights to intellectual property that You 93 | create, You represent that You have received permission to make 94 | the Contributions on behalf of that employer, that Your employer 95 | has waived such rights for Your Contributions, or that Your 96 | employer has executed a separate Corporate Contributor License 97 | Agreement with StrongLoop. 98 | 99 | 5. The Contributions Are Your Original Work 100 | 101 | You represent that each of Your Contributions are Your original 102 | works of authorship (see Section 8 (Submissions on Behalf of 103 | Others) for submission on behalf of others). You represent that to 104 | Your knowledge, no other person claims, or has the right to claim, 105 | any right in any intellectual property right related to Your 106 | Contributions. 107 | 108 | You also represent that You are not legally obligated, whether by 109 | entering into an agreement or otherwise, in any way that conflicts 110 | with the terms of this Agreement. 111 | 112 | You represent that Your Contribution submissions include complete 113 | details of any third-party license or other restriction (including, 114 | but not limited to, related patents and trademarks) of which You 115 | are personally aware and which are associated with any part of 116 | Your Contributions. 117 | 118 | 6. You Don't Have an Obligation to Provide Support for Your Contributions 119 | 120 | You are not expected to provide support for Your Contributions, 121 | except to the extent You desire to provide support. You may provide 122 | support for free, for a fee, or not at all. 123 | 124 | 6. No Warranties or Conditions 125 | 126 | StrongLoop acknowledges that unless required by applicable law or 127 | agreed to in writing, You provide Your Contributions on an "AS IS" 128 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 129 | EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES 130 | OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR 131 | FITNESS FOR A PARTICULAR PURPOSE. 132 | 133 | 7. Submission on Behalf of Others 134 | 135 | If You wish to submit work that is not Your original creation, You 136 | may submit it to StrongLoop separately from any Contribution, 137 | identifying the complete details of its source and of any license 138 | or other restriction (including, but not limited to, related 139 | patents, trademarks, and license agreements) of which You are 140 | personally aware, and conspicuously marking the work as 141 | "Submitted on Behalf of a Third-Party: [named here]". 142 | 143 | 8. Agree to Notify of Change of Circumstances 144 | 145 | You agree to notify StrongLoop of any facts or circumstances of 146 | which You become aware that would make these representations 147 | inaccurate in any respect. Email us at callback@strongloop.com. 148 | ``` 149 | 150 | [Google C++ Style Guide]: https://google.github.io/styleguide/cppguide.html 151 | [Google Javascript Style Guide]: https://google.github.io/styleguide/javascriptguide.xml 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) IBM Corp. 2013,2014. All Rights Reserved. 2 | Package: strongloop-buildpacks 3 | This project is licensed under the MIT License, full text below. 4 | 5 | -------- 6 | 7 | MIT license 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | StrongLoop provides: 2 | 3 | * LoopBack, an open-source Node.js framework that enables you to create dynamic end-to-end REST APIs with little or no coding. For more information, see http://loopback.io. 4 | * StrongLoop Controller, a Node devops system. See [StrongLoop Controller docs](http://docs.strongloop.com/display/SLC/StrongLoop+Controller) for more information. 5 | * StrongLoop Agent (StrongOps), an operational console for Node.js applications that provides deep performance monitoring including CPU profiling, event loop statistics, and more. See [StrongLoop Agent docs](http://docs.strongloop.com/pages/viewpage.action?pageId=3834736) for more information. 6 | 7 | The StrongLoop Heroku Buildpack installs the StrongLoop Controller command-line tool (slc) and the add-on provisions a 8 | [StrongOps](http://www.strongloop.com/ops) monitoring account. 9 | 10 | ## Prerequisites 11 | 12 | Before starting, on your local system: 13 | 14 | - If you have not already done so, install Node.js : [Download native installers](http://nodejs.org/download) 15 | for Windows or Mac OS; for Linux, 16 | see [Installing Node.js via package manager](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager). 17 | - Install StrongLoop software: 18 | ```term 19 | $ npm install -g strongloop 20 | ``` 21 | - Make sure you have installed the [Heroku Toolbelt](https://toolbelt.heroku.com/). 22 | 23 | ## Create your app 24 | 25 | Follow the instructions in 26 | [Getting started with LoopBack](http://docs.strongloop.com/display/LB/Getting+started+with+LoopBack) to create a LoopBack application. 27 | 28 | Just enter: 29 | 30 | ```term 31 | $ slc loopback 32 | ``` 33 | 34 | You'll be prompted to pick a name and directory for the new application; for example, if you entered `myapp` for the application and 35 | directory name: 36 | 37 | ``` 38 | $ cd myapp 39 | ``` 40 | Update `package.json` to add the following line so the app will use the latest stable version of Node.js: 41 | 42 | ```term 43 | ... 44 | "engines": { 45 | "node": "0.10.x" 46 | } 47 | ... 48 | ``` 49 | 50 | Then create a Git repository and commit your code: 51 | 52 | ```term 53 | $ git init 54 | $ git add . 55 | $ git commit -m "init" 56 | ``` 57 | 58 | ## Heroku setup 59 | 60 | Create a Procfile in the root directory of your app that contains the following: 61 | 62 | web: slc run 63 | 64 | Make sure you add the Procfile to your repository: 65 | 66 | ```term 67 | $ git add Procfile 68 | $ git commit -m "adding Procfile" 69 | ``` 70 | 71 | ### Get the buildpack 72 | 73 | Login with the Heroku command line: 74 | 75 | ```term 76 | $ heroku login 77 | ``` 78 | 79 | Create your Heroku app using the buildpack. When it completes, push to Heroku 80 | master to complete the installation of StrongLoop on your dyno. 81 | 82 | ```term 83 | $ heroku apps:create --buildpack https://github.com/strongloop/strongloop-buildpacks.git 84 | $ git push heroku master 85 | ``` 86 | 87 | Test it out 88 | 89 | ```term 90 | $ heroku open 91 | ``` 92 | 93 | ### How to check your dashboard on Heroku 94 | Once you have created your app, its time to look at the instrumentation. 95 | Navigate to the [Heroku dashboard](https://dashboard.heroku.com) 96 | and find your app. Once you've found your app, click on **Heroku app dashboard** to 97 | view the various dynos and add-ons for your app. Click on the StrongLoop add-on to view the StrongOps Control Panel. 98 | The StrongLoop Ops dashboard is 99 | accessible by clicking on the grey button "StrongOps Dashboard". 100 | 101 | The dashboard can also be accessed via the CLI: 102 | 103 | ```term 104 | $ heroku addons:open strongloop 105 | Opening strongloop for sharp-mountain-4005… 106 | ``` 107 | 108 | ## Run your app in a cluster 109 | 110 | To run your application in a cluster, update the start command in the Procfile: 111 | 112 | ```term 113 | $ web: slc run --cluster 114 | ``` 115 | 116 | Where `` is a postive integer indicating the number of worker processes to use. 117 | 118 | Commit your changes and redeploy the app: 119 | 120 | ```term 121 | $ git add Procfile 122 | $ git commit -m "Started clustered app" Procfile 123 | $ git push heroku master 124 | ``` 125 | 126 | Once you have set this up, you can control the cluster through the StrongLoop dashboard: simply click on the **Cluster** tab. 127 | 128 | ## Collect application metrics 129 | 130 | To collect metrics to send to a StatsD server, update the start command in the Procfile: 131 | 132 | ```term 133 | $ web: slc run --metrics 134 | ``` 135 | 136 | Where `` is the URL of your StatsD server with format `statsd:[//host[:port]][/scope]`. 137 | 138 | Commit your changes and redeploy the app: 139 | 140 | ```term 141 | $ git add Procfile 142 | $ git commit -m "Collect metrics using strong-agent" Procfile 143 | $ git push heroku master 144 | ``` 145 | For more information on how to use the StrongLoop Agent API to get performance metrics, see 146 | [On-premises monitoring](http://docs.strongloop.com/display/SLA/On-premises+monitoring). 147 | 148 | ## Troubleshooting 149 | 150 | After configuration, StrongOps is automatic. If you should experience any issues, please let us know immediately by 151 | [email](mailto:callback@strongloop.com) 152 | 153 | ## Migrating between plans 154 | 155 | **NOTE: Carefully manage the migration timing to ensure proper application function during the migration process.** 156 | 157 | Use the `heroku addons:upgrade` command to migrate to a new plan. 158 | 159 | ```term 160 | $ heroku addons:upgrade strongloop:newplan 161 | -----> Upgrading strongloop:newplan to sharp-mountain-4005... done, v18 ($49/mo) 162 | Your plan has been updated to: strongloop:newplan 163 | ``` 164 | 165 | ## Removing the add-on 166 | 167 | Remove StrongOps with the following command. 168 | 169 | **WARNING: This will destroy all associated data and cannot be undone!** 170 | 171 | ```term 172 | $ heroku addons:remove strongloop 173 | -----> Removing strongloop from sharp-mountain-4005... done, v20 (free) 174 | ``` 175 | 176 | ## Support 177 | 178 | Submit all StrongOps support and runtime issues via the [Heroku Support channels](support-channels). 179 | Any non-support related issues or product feedback is welcome at [callback@strongloop.com](mailto:callback@strongloop.com). 180 | -------------------------------------------------------------------------------- /bin/common.sh: -------------------------------------------------------------------------------- 1 | error() { 2 | echo " ! $*" >&2 3 | exit 1 4 | } 5 | 6 | status() { 7 | echo "-----> $*" 8 | } 9 | 10 | protip() { 11 | echo 12 | echo "PRO TIP: $*" | indent 13 | echo "See https://devcenter.heroku.com/articles/nodejs-support" | indent 14 | echo 15 | } 16 | 17 | # sed -l basically makes sed replace and buffer through stdin to stdout 18 | # so you get updates while the command runs and dont wait for the end 19 | # e.g. npm install | indent 20 | indent() { 21 | c='s/^/ /' 22 | case $(uname) in 23 | Darwin) sed -l "$c";; # mac/bsd sed: -l buffers on line boundaries 24 | *) sed -u "$c";; # unix/gnu sed: -u unbuffered (arbitrary) chunks of data 25 | esac 26 | } 27 | 28 | cat_npm_debug_log() { 29 | test -f $build_dir/npm-debug.log && cat $build_dir/npm-debug.log 30 | } 31 | -------------------------------------------------------------------------------- /bin/compile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # fail fast 4 | set -o pipefail # don't ignore exit codes when piping output 5 | # set -x # enable debugging 6 | 7 | # Configure directories 8 | build_dir=$1 9 | cache_dir=$2 10 | bp_dir=$(cd $(dirname $0); cd ..; pwd) 11 | 12 | # Load some convenience functions like status(), echo(), and indent() 13 | source $bp_dir/bin/common.sh 14 | 15 | # Output npm debug info on error 16 | trap cat_npm_debug_log ERR 17 | 18 | # Look in package.json's engines.node field for a semver range 19 | semver_range=$(cat $build_dir/package.json | $bp_dir/vendor/jq -r .engines.node) 20 | 21 | # Resolve node version using semver.io 22 | node_version=$(curl --silent --get --data-urlencode "range=${semver_range}" http://semver.io/node/resolve) 23 | #node_version=0.10.29 24 | 25 | # Recommend using semver ranges in a safe manner 26 | if [ "$semver_range" == "null" ]; then 27 | protip "Specify a node version in package.json" 28 | semver_range="" 29 | elif [ "$semver_range" == "*" ]; then 30 | protip "Avoid using semver ranges like '*' in engines.node" 31 | elif [ ${semver_range:0:1} == ">" ]; then 32 | protip "Avoid using semver ranges starting with '>' in engines.node" 33 | fi 34 | 35 | # Output info about requested range and resolved node version 36 | if [ "$semver_range" == "" ]; then 37 | status "Defaulting to latest stable node: $node_version" 38 | else 39 | status "Requested node range: $semver_range" 40 | status "Resolved node version: $node_version" 41 | fi 42 | 43 | # Download node from Heroku's S3 mirror of nodejs.org/dist 44 | status "Downloading and installing node" 45 | node_url="http://s3pository.heroku.com/node/v$node_version/node-v$node_version-linux-x64.tar.gz" 46 | curl $node_url -s -o - | tar xzf - -C $build_dir 47 | 48 | # Move node into ./vendor and make it executable 49 | mkdir -p $build_dir/vendor 50 | mv $build_dir/node-v$node_version-linux-x64 $build_dir/vendor/node 51 | chmod +x $build_dir/vendor/node/bin/* 52 | PATH=$PATH:$build_dir/vendor/node/bin 53 | 54 | # Run subsequent node/npm commands from the build path 55 | cd $build_dir 56 | 57 | # If node_modules directory is checked into source control then 58 | # rebuild any native deps. Otherwise, restore from the build cache. 59 | if test -d $build_dir/node_modules; then 60 | status "Using existing node_modules directory" 61 | status "Rebuilding any native dependencies" 62 | npm rebuild 2>&1 | indent 63 | elif test -d $cache_dir/node_modules; then 64 | status "Restoring node_modules from cache" 65 | cp -r $cache_dir/node_modules $build_dir/ 66 | fi 67 | 68 | status "Installing StrongLoop dependencies" 69 | npm install -g strongloop 70 | # Make npm output to STDOUT instead of its default STDERR 71 | status "Installing dependencies" 72 | npm install --production 2>&1 | indent 73 | 74 | status "Pruning unused dependencies" 75 | npm prune 2>&1 | indent 76 | 77 | status "Caching node_modules directory for future builds" 78 | rm -rf $cache_dir 79 | mkdir -p $cache_dir 80 | test -d $build_dir/node_modules && cp -r $build_dir/node_modules $cache_dir/ 81 | 82 | status "Cleaning up node-gyp and npm artifacts" 83 | rm -rf "$build_dir/.node-gyp" 84 | rm -rf "$build_dir/.npm" 85 | 86 | # Update the PATH 87 | status "Building runtime environment" 88 | mkdir -p $build_dir/.profile.d 89 | echo "export PATH=\"\$HOME/vendor/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" > $build_dir/.profile.d/nodejs.sh 90 | 91 | # Post package.json to nomnom service 92 | # Use a subshell so failures won't break the build. 93 | ( 94 | curl \ 95 | --data @$build_dir/package.json \ 96 | --fail \ 97 | --silent \ 98 | --request POST \ 99 | --header "content-type: application/json" \ 100 | https://nomnom.heroku.com/?request_id=$REQUEST_ID 101 | ) & 102 | -------------------------------------------------------------------------------- /bin/detect: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # bin/detect 3 | 4 | if [ -f $1/package.json ]; then 5 | echo "Node.js" && exit 0 6 | else 7 | echo "no" && exit 1 8 | fi 9 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # See CONTRIBUTING.md for info on running these tests. 3 | 4 | testDetectWithPackageJson() { 5 | detect "stable-node" 6 | assertCaptured "Node.js" 7 | assertCapturedSuccess 8 | } 9 | 10 | testDetectWithoutPackageJson() { 11 | detect "no-package-json" 12 | assertCapturedError 1 "" 13 | } 14 | 15 | testNoVersion() { 16 | compile "no-version" 17 | assertCaptured "PRO TIP: Specify a node version in package.json" 18 | assertCaptured "Defaulting to latest stable node" 19 | assertCapturedSuccess 20 | } 21 | 22 | testDangerousRangeStar() { 23 | compile "dangerous-range-star" 24 | assertCaptured "PRO TIP: Avoid using semver ranges like '*'" 25 | assertCaptured "Requested node range: *" 26 | assertCaptured "Resolved node version: 0.10" 27 | assertCapturedSuccess 28 | } 29 | 30 | testDangerousRangeGreaterThan() { 31 | compile "dangerous-range-greater-than" 32 | assertCaptured "PRO TIP: Avoid using semver ranges starting with '>'" 33 | assertCaptured "Requested node range: >" 34 | assertCaptured "Resolved node version: 0.10." 35 | assertCapturedSuccess 36 | } 37 | 38 | testRangeWithSpace() { 39 | compile "range-with-space" 40 | assertCaptured "Requested node range: >= 0.8.x" 41 | assertCaptured "Resolved node version: 0.10." 42 | assertCapturedSuccess 43 | } 44 | 45 | testStableVersion() { 46 | compile "stable-node" 47 | assertNotCaptured "PRO TIP: Avoid using semver" 48 | assertNotCaptured "PRO TIP: Specify" 49 | assertCaptured "Resolved node version" 50 | assertCapturedSuccess 51 | } 52 | 53 | testUnstableVersion() { 54 | compile "unstable-version" 55 | assertCaptured "Requested node range: >0.11.0" 56 | assertCaptured "Resolved node version: 0.11." 57 | assertCapturedSuccess 58 | } 59 | 60 | testProfileCreated() { 61 | compile "stable-node" 62 | assertCaptured "Building runtime environment" 63 | assertFile "export PATH=\"\$HOME/vendor/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" ".profile.d/nodejs.sh" 64 | assertCapturedSuccess 65 | } 66 | 67 | testInvalidDependency() { 68 | compile "invalid-dependency" 69 | assertCaptured "not in the npm registry" 70 | assertCapturedError 1 "" 71 | } 72 | 73 | testNodeModulesCached() { 74 | cache=$(mktmpdir) 75 | compile "caching" $cache 76 | assertCaptured "Caching node" 77 | assertEquals "1" "$(ls -1 $cache/ | wc -l)" 78 | } 79 | 80 | testModulesCheckedIn() { 81 | compile "modules-checked-in" 82 | assertCaptured "Using existing node_modules directory" 83 | assertCaptured "Rebuilding any native dependencies" 84 | assertCapturedSuccess 85 | } 86 | 87 | # Pending Tests 88 | 89 | # testNodeBinariesAddedToPath() { 90 | # } 91 | 92 | # testNodeModulesRestoredFromCache() { 93 | # } 94 | 95 | # TODO: Figure out how to test stuff like script hooks 96 | # when restoring node_modules from cache 97 | # testScriptHooks() { 98 | # compile "script-hooks" 99 | # assertCaptured "trigger script hooks" 100 | # assertCaptured "preinstall hook message" 101 | # assertCapturedSuccess 102 | # } 103 | 104 | # testWithoutScriptHooks() { 105 | # compile "no-script-hooks" 106 | # assertNotCaptured "trigger script hooks" 107 | # assertCapturedSuccess 108 | # } 109 | 110 | # testInvalidVersion() { 111 | # compile "invalid-node-version" 112 | # assertCapturedError 1 "not found among available versions" 113 | # } 114 | 115 | # Utils 116 | 117 | pushd $(dirname 0) >/dev/null 118 | bp_dir=$(pwd) 119 | popd >/dev/null 120 | 121 | source ${bp_dir}/vendor/test-utils/test-utils 122 | 123 | mktmpdir() { 124 | dir=$(mktemp -t testXXXXX) 125 | rm -rf $dir 126 | mkdir $dir 127 | echo $dir 128 | } 129 | 130 | detect() { 131 | capture ${bp_dir}/bin/detect ${bp_dir}/test/$1 132 | } 133 | 134 | compile_dir="" 135 | 136 | compile() { 137 | compile_dir=$(mktmpdir) 138 | cp -r ${bp_dir}/test/$1/* ${compile_dir}/ 139 | capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} 140 | } 141 | 142 | assertFile() { 143 | assertEquals "$1" "$(cat ${compile_dir}/$2)" 144 | } 145 | 146 | source ${bp_dir}/vendor/shunit2/shunit2 147 | -------------------------------------------------------------------------------- /test/caching/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/caching/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": "0.10.18" 11 | }, 12 | "dependencies": { 13 | "express": "latest" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/dangerous-range-greater-than/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/dangerous-range-greater-than/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": ">0.4" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/dangerous-range-star/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/dangerous-range-star/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/invalid-dependency/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/invalid-dependency/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": "~0.10.20" 11 | }, 12 | "dependencies": { 13 | "some-crazy-dep-that-doesnt-exist": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/invalid-node-version/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/invalid-node-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": ">2.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/modules-checked-in/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/README.markdown: -------------------------------------------------------------------------------- 1 | Hashish 2 | ======= 3 | 4 | Hashish is a node.js library for manipulating hash data structures. 5 | It is distilled from the finest that ruby, perl, and haskell have to offer by 6 | way of hash/map interfaces. 7 | 8 | Hashish provides a chaining interface, where you can do: 9 | 10 | var Hash = require('hashish'); 11 | 12 | Hash({ a : 1, b : 2, c : 3, d : 4 }) 13 | .map(function (x) { return x * 10 }) 14 | .filter(function (x) { return x < 30 }) 15 | .forEach(function (x, key) { 16 | console.log(key + ' => ' + x); 17 | }) 18 | ; 19 | 20 | Output: 21 | 22 | a => 10 23 | b => 20 24 | 25 | Some functions and attributes in the chaining interface are terminal, like 26 | `.items` or `.detect()`. They return values of their own instead of the chain 27 | context. 28 | 29 | Each function in the chainable interface is also attached to `Hash` in chainless 30 | form: 31 | 32 | var Hash = require('hashish'); 33 | var obj = { a : 1, b : 2, c : 3, d : 4 }; 34 | 35 | var mapped = Hash.map(obj, function (x) { 36 | return x * 10 37 | }); 38 | 39 | console.dir(mapped); 40 | 41 | Output: 42 | 43 | { a: 10, b: 20, c: 30, d: 40 } 44 | 45 | In either case, the 'this' context of the function calls is the same object that 46 | the chained functions return, so you can make nested chains. 47 | 48 | Methods 49 | ======= 50 | 51 | forEach(cb) 52 | ----------- 53 | 54 | For each key/value in the hash, calls `cb(value, key)`. 55 | 56 | map(cb) 57 | ------- 58 | 59 | For each key/value in the hash, calls `cb(value, key)`. 60 | The return value of `cb` is the new value at `key` in the resulting hash. 61 | 62 | filter(cb) 63 | ---------- 64 | 65 | For each key/value in the hash, calls `cb(value, key)`. 66 | The resulting hash omits key/value pairs where `cb` returned a falsy value. 67 | 68 | detect(cb) 69 | ---------- 70 | 71 | Returns the first value in the hash for which `cb(value, key)` is non-falsy. 72 | Order of hashes is not well-defined so watch out for that. 73 | 74 | reduce(cb) 75 | ---------- 76 | 77 | Returns the accumulated value of a left-fold over the key/value pairs. 78 | 79 | some(cb) 80 | -------- 81 | 82 | Returns a boolean: whether or not `cb(value, key)` ever returned a non-falsy 83 | value. 84 | 85 | update(obj1, [obj2, obj3, ...]) 86 | ----------- 87 | 88 | Mutate the context hash, merging the key/value pairs from the passed objects 89 | and overwriting keys from the context hash if the current `obj` has keys of 90 | the same name. Falsy arguments are silently ignored. 91 | 92 | updateAll([ obj1, obj2, ... ]) 93 | ------------------------------ 94 | 95 | Like multi-argument `update()` but operate on an array directly. 96 | 97 | merge(obj1, [obj2, obj3, ...]) 98 | ---------- 99 | 100 | Merge the key/value pairs from the passed objects into the resultant hash 101 | without modifying the context hash. Falsy arguments are silently ignored. 102 | 103 | mergeAll([ obj1, obj2, ... ]) 104 | ------------------------------ 105 | 106 | Like multi-argument `merge()` but operate on an array directly. 107 | 108 | has(key) 109 | -------- 110 | 111 | Return whether the hash has a key, `key`. 112 | 113 | valuesAt(keys) 114 | -------------- 115 | 116 | Return an Array with the values at the keys from `keys`. 117 | 118 | tap(cb) 119 | ------- 120 | 121 | Call `cb` with the present raw hash. 122 | This function is chainable. 123 | 124 | extract(keys) 125 | ------------- 126 | 127 | Filter by including only those keys in `keys` in the resulting hash. 128 | 129 | exclude(keys) 130 | ------------- 131 | 132 | Filter by excluding those keys in `keys` in the resulting hash. 133 | 134 | Attributes 135 | ========== 136 | 137 | These are attributes in the chaining interface and functions in the `Hash.xxx` 138 | interface. 139 | 140 | keys 141 | ---- 142 | 143 | Return all the enumerable attribute keys in the hash. 144 | 145 | values 146 | ------ 147 | 148 | Return all the enumerable attribute values in the hash. 149 | 150 | compact 151 | ------- 152 | 153 | Filter out values which are `=== undefined`. 154 | 155 | clone 156 | ----- 157 | 158 | Make a deep copy of the hash. 159 | 160 | copy 161 | ---- 162 | 163 | Make a shallow copy of the hash. 164 | 165 | length 166 | ------ 167 | 168 | Return the number of key/value pairs in the hash. 169 | Note: use `Hash.size()` for non-chain mode. 170 | 171 | size 172 | ---- 173 | 174 | Alias for `length` since `Hash.length` is masked by `Function.prototype`. 175 | 176 | See Also 177 | ======== 178 | 179 | See also [creationix's pattern/hash](http://github.com/creationix/pattern), 180 | which does a similar thing except with hash inputs and array outputs. 181 | 182 | Installation 183 | ============ 184 | 185 | To install with [npm](http://github.com/isaacs/npm): 186 | 187 | npm install hashish 188 | 189 | To run the tests with [expresso](http://github.com/visionmedia/expresso): 190 | 191 | expresso 192 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/examples/chain.js: -------------------------------------------------------------------------------- 1 | var Hash = require('hashish'); 2 | 3 | Hash({ a : 1, b : 2, c : 3, d : 4 }) 4 | .map(function (x) { return x * 10 }) 5 | .filter(function (x) { return x < 30 }) 6 | .forEach(function (x, key) { 7 | console.log(key + ' => ' + x); 8 | }) 9 | ; 10 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/examples/map.js: -------------------------------------------------------------------------------- 1 | var Hash = require('hashish'); 2 | var obj = { a : 1, b : 2, c : 3, d : 4 }; 3 | 4 | var mapped = Hash.map(obj, function (x) { 5 | return x * 10 6 | }); 7 | console.dir(mapped); 8 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/index.js: -------------------------------------------------------------------------------- 1 | module.exports = Hash; 2 | var Traverse = require('traverse'); 3 | 4 | function Hash (hash, xs) { 5 | if (Array.isArray(hash) && Array.isArray(xs)) { 6 | var to = Math.min(hash.length, xs.length); 7 | var acc = {}; 8 | for (var i = 0; i < to; i++) { 9 | acc[hash[i]] = xs[i]; 10 | } 11 | return Hash(acc); 12 | } 13 | 14 | if (hash === undefined) return Hash({}); 15 | 16 | var self = { 17 | map : function (f) { 18 | var acc = { __proto__ : hash.__proto__ }; 19 | Object.keys(hash).forEach(function (key) { 20 | acc[key] = f.call(self, hash[key], key); 21 | }); 22 | return Hash(acc); 23 | }, 24 | forEach : function (f) { 25 | Object.keys(hash).forEach(function (key) { 26 | f.call(self, hash[key], key); 27 | }); 28 | return self; 29 | }, 30 | filter : function (f) { 31 | var acc = { __proto__ : hash.__proto__ }; 32 | Object.keys(hash).forEach(function (key) { 33 | if (f.call(self, hash[key], key)) { 34 | acc[key] = hash[key]; 35 | } 36 | }); 37 | return Hash(acc); 38 | }, 39 | detect : function (f) { 40 | for (var key in hash) { 41 | if (f.call(self, hash[key], key)) { 42 | return hash[key]; 43 | } 44 | } 45 | return undefined; 46 | }, 47 | reduce : function (f, acc) { 48 | var keys = Object.keys(hash); 49 | if (acc === undefined) acc = keys.shift(); 50 | keys.forEach(function (key) { 51 | acc = f.call(self, acc, hash[key], key); 52 | }); 53 | return acc; 54 | }, 55 | some : function (f) { 56 | for (var key in hash) { 57 | if (f.call(self, hash[key], key)) return true; 58 | } 59 | return false; 60 | }, 61 | update : function (obj) { 62 | if (arguments.length > 1) { 63 | self.updateAll([].slice.call(arguments)); 64 | } 65 | else { 66 | Object.keys(obj).forEach(function (key) { 67 | hash[key] = obj[key]; 68 | }); 69 | } 70 | return self; 71 | }, 72 | updateAll : function (xs) { 73 | xs.filter(Boolean).forEach(function (x) { 74 | self.update(x); 75 | }); 76 | return self; 77 | }, 78 | merge : function (obj) { 79 | if (arguments.length > 1) { 80 | return self.copy.updateAll([].slice.call(arguments)); 81 | } 82 | else { 83 | return self.copy.update(obj); 84 | } 85 | }, 86 | mergeAll : function (xs) { 87 | return self.copy.updateAll(xs); 88 | }, 89 | has : function (key) { // only operates on enumerables 90 | return Array.isArray(key) 91 | ? key.every(function (k) { return self.has(k) }) 92 | : self.keys.indexOf(key.toString()) >= 0; 93 | }, 94 | valuesAt : function (keys) { 95 | return Array.isArray(keys) 96 | ? keys.map(function (key) { return hash[key] }) 97 | : hash[keys] 98 | ; 99 | }, 100 | tap : function (f) { 101 | f.call(self, hash); 102 | return self; 103 | }, 104 | extract : function (keys) { 105 | var acc = {}; 106 | keys.forEach(function (key) { 107 | acc[key] = hash[key]; 108 | }); 109 | return Hash(acc); 110 | }, 111 | exclude : function (keys) { 112 | return self.filter(function (_, key) { 113 | return keys.indexOf(key) < 0 114 | }); 115 | }, 116 | end : hash, 117 | items : hash 118 | }; 119 | 120 | var props = { 121 | keys : function () { return Object.keys(hash) }, 122 | values : function () { 123 | return Object.keys(hash).map(function (key) { return hash[key] }); 124 | }, 125 | compact : function () { 126 | return self.filter(function (x) { return x !== undefined }); 127 | }, 128 | clone : function () { return Hash(Hash.clone(hash)) }, 129 | copy : function () { return Hash(Hash.copy(hash)) }, 130 | length : function () { return Object.keys(hash).length }, 131 | size : function () { return self.length } 132 | }; 133 | 134 | if (Object.defineProperty) { 135 | // es5-shim has an Object.defineProperty but it throws for getters 136 | try { 137 | for (var key in props) { 138 | Object.defineProperty(self, key, { get : props[key] }); 139 | } 140 | } 141 | catch (err) { 142 | for (var key in props) { 143 | if (key !== 'clone' && key !== 'copy' && key !== 'compact') { 144 | // ^ those keys use Hash() so can't call them without 145 | // a stack overflow 146 | self[key] = props[key](); 147 | } 148 | } 149 | } 150 | } 151 | else if (self.__defineGetter__) { 152 | for (var key in props) { 153 | self.__defineGetter__(key, props[key]); 154 | } 155 | } 156 | else { 157 | // non-lazy version for browsers that suck >_< 158 | for (var key in props) { 159 | self[key] = props[key](); 160 | } 161 | } 162 | 163 | return self; 164 | }; 165 | 166 | // deep copy 167 | Hash.clone = function (ref) { 168 | return Traverse.clone(ref); 169 | }; 170 | 171 | // shallow copy 172 | Hash.copy = function (ref) { 173 | var hash = { __proto__ : ref.__proto__ }; 174 | Object.keys(ref).forEach(function (key) { 175 | hash[key] = ref[key]; 176 | }); 177 | return hash; 178 | }; 179 | 180 | Hash.map = function (ref, f) { 181 | return Hash(ref).map(f).items; 182 | }; 183 | 184 | Hash.forEach = function (ref, f) { 185 | Hash(ref).forEach(f); 186 | }; 187 | 188 | Hash.filter = function (ref, f) { 189 | return Hash(ref).filter(f).items; 190 | }; 191 | 192 | Hash.detect = function (ref, f) { 193 | return Hash(ref).detect(f); 194 | }; 195 | 196 | Hash.reduce = function (ref, f, acc) { 197 | return Hash(ref).reduce(f, acc); 198 | }; 199 | 200 | Hash.some = function (ref, f) { 201 | return Hash(ref).some(f); 202 | }; 203 | 204 | Hash.update = function (a /*, b, c, ... */) { 205 | var args = Array.prototype.slice.call(arguments, 1); 206 | var hash = Hash(a); 207 | return hash.update.apply(hash, args).items; 208 | }; 209 | 210 | Hash.merge = function (a /*, b, c, ... */) { 211 | var args = Array.prototype.slice.call(arguments, 1); 212 | var hash = Hash(a); 213 | return hash.merge.apply(hash, args).items; 214 | }; 215 | 216 | Hash.has = function (ref, key) { 217 | return Hash(ref).has(key); 218 | }; 219 | 220 | Hash.valuesAt = function (ref, keys) { 221 | return Hash(ref).valuesAt(keys); 222 | }; 223 | 224 | Hash.tap = function (ref, f) { 225 | return Hash(ref).tap(f).items; 226 | }; 227 | 228 | Hash.extract = function (ref, keys) { 229 | return Hash(ref).extract(keys).items; 230 | }; 231 | 232 | Hash.exclude = function (ref, keys) { 233 | return Hash(ref).exclude(keys).items; 234 | }; 235 | 236 | Hash.concat = function (xs) { 237 | var hash = Hash({}); 238 | xs.forEach(function (x) { hash.update(x) }); 239 | return hash.items; 240 | }; 241 | 242 | Hash.zip = function (xs, ys) { 243 | return Hash(xs, ys).items; 244 | }; 245 | 246 | // .length is already defined for function prototypes 247 | Hash.size = function (ref) { 248 | return Hash(ref).size; 249 | }; 250 | 251 | Hash.compact = function (ref) { 252 | return Hash(ref).compact.items; 253 | }; 254 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.6 4 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 James Halliday (mail@substack.net) 2 | 3 | This project is free software released under the MIT/X11 license: 4 | http://www.opensource.org/licenses/mit-license.php 5 | 6 | Copyright 2010 James Halliday (mail@substack.net) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/json.js: -------------------------------------------------------------------------------- 1 | var traverse = require('traverse'); 2 | 3 | var id = 54; 4 | var callbacks = {}; 5 | var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; 6 | 7 | var scrubbed = traverse(obj).map(function (x) { 8 | if (typeof x === 'function') { 9 | callbacks[id] = { id : id, f : x, path : this.path }; 10 | this.update('[Function]'); 11 | id++; 12 | } 13 | }); 14 | 15 | console.dir(scrubbed); 16 | console.dir(callbacks); 17 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/leaves.js: -------------------------------------------------------------------------------- 1 | var traverse = require('traverse'); 2 | 3 | var obj = { 4 | a : [1,2,3], 5 | b : 4, 6 | c : [5,6], 7 | d : { e : [7,8], f : 9 }, 8 | }; 9 | 10 | var leaves = traverse(obj).reduce(function (acc, x) { 11 | if (this.isLeaf) acc.push(x); 12 | return acc; 13 | }, []); 14 | 15 | console.dir(leaves); 16 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/negative.js: -------------------------------------------------------------------------------- 1 | var traverse = require('traverse'); 2 | var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; 3 | 4 | traverse(obj).forEach(function (x) { 5 | if (x < 0) this.update(x + 128); 6 | }); 7 | 8 | console.dir(obj); 9 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/scrub.js: -------------------------------------------------------------------------------- 1 | // scrub out circular references 2 | var traverse = require('traverse'); 3 | 4 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 5 | obj.c.push(obj); 6 | 7 | var scrubbed = traverse(obj).map(function (x) { 8 | if (this.circular) this.remove() 9 | }); 10 | console.dir(scrubbed); 11 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/stringify.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var traverse = require('traverse'); 3 | 4 | var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; 5 | 6 | var s = ''; 7 | traverse(obj).forEach(function to_s (node) { 8 | if (Array.isArray(node)) { 9 | this.before(function () { s += '[' }); 10 | this.post(function (child) { 11 | if (!child.isLast) s += ','; 12 | }); 13 | this.after(function () { s += ']' }); 14 | } 15 | else if (typeof node == 'object') { 16 | this.before(function () { s += '{' }); 17 | this.pre(function (x, key) { 18 | to_s(key); 19 | s += ':'; 20 | }); 21 | this.post(function (child) { 22 | if (!child.isLast) s += ','; 23 | }); 24 | this.after(function () { s += '}' }); 25 | } 26 | else if (typeof node == 'string') { 27 | s += '"' + node.toString().replace(/"/g, '\\"') + '"'; 28 | } 29 | else if (typeof node == 'function') { 30 | s += 'null'; 31 | } 32 | else { 33 | s += node.toString(); 34 | } 35 | }); 36 | 37 | console.log('JSON.stringify: ' + JSON.stringify(obj)); 38 | console.log('this stringify: ' + s); 39 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/index.js: -------------------------------------------------------------------------------- 1 | var traverse = module.exports = function (obj) { 2 | return new Traverse(obj); 3 | }; 4 | 5 | function Traverse (obj) { 6 | this.value = obj; 7 | } 8 | 9 | Traverse.prototype.get = function (ps) { 10 | var node = this.value; 11 | for (var i = 0; i < ps.length; i ++) { 12 | var key = ps[i]; 13 | if (!node || !hasOwnProperty.call(node, key)) { 14 | node = undefined; 15 | break; 16 | } 17 | node = node[key]; 18 | } 19 | return node; 20 | }; 21 | 22 | Traverse.prototype.has = function (ps) { 23 | var node = this.value; 24 | for (var i = 0; i < ps.length; i ++) { 25 | var key = ps[i]; 26 | if (!node || !hasOwnProperty.call(node, key)) { 27 | return false; 28 | } 29 | node = node[key]; 30 | } 31 | return true; 32 | }; 33 | 34 | Traverse.prototype.set = function (ps, value) { 35 | var node = this.value; 36 | for (var i = 0; i < ps.length - 1; i ++) { 37 | var key = ps[i]; 38 | if (!hasOwnProperty.call(node, key)) node[key] = {}; 39 | node = node[key]; 40 | } 41 | node[ps[i]] = value; 42 | return value; 43 | }; 44 | 45 | Traverse.prototype.map = function (cb) { 46 | return walk(this.value, cb, true); 47 | }; 48 | 49 | Traverse.prototype.forEach = function (cb) { 50 | this.value = walk(this.value, cb, false); 51 | return this.value; 52 | }; 53 | 54 | Traverse.prototype.reduce = function (cb, init) { 55 | var skip = arguments.length === 1; 56 | var acc = skip ? this.value : init; 57 | this.forEach(function (x) { 58 | if (!this.isRoot || !skip) { 59 | acc = cb.call(this, acc, x); 60 | } 61 | }); 62 | return acc; 63 | }; 64 | 65 | Traverse.prototype.paths = function () { 66 | var acc = []; 67 | this.forEach(function (x) { 68 | acc.push(this.path); 69 | }); 70 | return acc; 71 | }; 72 | 73 | Traverse.prototype.nodes = function () { 74 | var acc = []; 75 | this.forEach(function (x) { 76 | acc.push(this.node); 77 | }); 78 | return acc; 79 | }; 80 | 81 | Traverse.prototype.clone = function () { 82 | var parents = [], nodes = []; 83 | 84 | return (function clone (src) { 85 | for (var i = 0; i < parents.length; i++) { 86 | if (parents[i] === src) { 87 | return nodes[i]; 88 | } 89 | } 90 | 91 | if (typeof src === 'object' && src !== null) { 92 | var dst = copy(src); 93 | 94 | parents.push(src); 95 | nodes.push(dst); 96 | 97 | forEach(objectKeys(src), function (key) { 98 | dst[key] = clone(src[key]); 99 | }); 100 | 101 | parents.pop(); 102 | nodes.pop(); 103 | return dst; 104 | } 105 | else { 106 | return src; 107 | } 108 | })(this.value); 109 | }; 110 | 111 | function walk (root, cb, immutable) { 112 | var path = []; 113 | var parents = []; 114 | var alive = true; 115 | 116 | return (function walker (node_) { 117 | var node = immutable ? copy(node_) : node_; 118 | var modifiers = {}; 119 | 120 | var keepGoing = true; 121 | 122 | var state = { 123 | node : node, 124 | node_ : node_, 125 | path : [].concat(path), 126 | parent : parents[parents.length - 1], 127 | parents : parents, 128 | key : path.slice(-1)[0], 129 | isRoot : path.length === 0, 130 | level : path.length, 131 | circular : null, 132 | update : function (x, stopHere) { 133 | if (!state.isRoot) { 134 | state.parent.node[state.key] = x; 135 | } 136 | state.node = x; 137 | if (stopHere) keepGoing = false; 138 | }, 139 | 'delete' : function (stopHere) { 140 | delete state.parent.node[state.key]; 141 | if (stopHere) keepGoing = false; 142 | }, 143 | remove : function (stopHere) { 144 | if (isArray(state.parent.node)) { 145 | state.parent.node.splice(state.key, 1); 146 | } 147 | else { 148 | delete state.parent.node[state.key]; 149 | } 150 | if (stopHere) keepGoing = false; 151 | }, 152 | keys : null, 153 | before : function (f) { modifiers.before = f }, 154 | after : function (f) { modifiers.after = f }, 155 | pre : function (f) { modifiers.pre = f }, 156 | post : function (f) { modifiers.post = f }, 157 | stop : function () { alive = false }, 158 | block : function () { keepGoing = false } 159 | }; 160 | 161 | if (!alive) return state; 162 | 163 | function updateState() { 164 | if (typeof state.node === 'object' && state.node !== null) { 165 | if (!state.keys || state.node_ !== state.node) { 166 | state.keys = objectKeys(state.node) 167 | } 168 | 169 | state.isLeaf = state.keys.length == 0; 170 | 171 | for (var i = 0; i < parents.length; i++) { 172 | if (parents[i].node_ === node_) { 173 | state.circular = parents[i]; 174 | break; 175 | } 176 | } 177 | } 178 | else { 179 | state.isLeaf = true; 180 | state.keys = null; 181 | } 182 | 183 | state.notLeaf = !state.isLeaf; 184 | state.notRoot = !state.isRoot; 185 | } 186 | 187 | updateState(); 188 | 189 | // use return values to update if defined 190 | var ret = cb.call(state, state.node); 191 | if (ret !== undefined && state.update) state.update(ret); 192 | 193 | if (modifiers.before) modifiers.before.call(state, state.node); 194 | 195 | if (!keepGoing) return state; 196 | 197 | if (typeof state.node == 'object' 198 | && state.node !== null && !state.circular) { 199 | parents.push(state); 200 | 201 | updateState(); 202 | 203 | forEach(state.keys, function (key, i) { 204 | path.push(key); 205 | 206 | if (modifiers.pre) modifiers.pre.call(state, state.node[key], key); 207 | 208 | var child = walker(state.node[key]); 209 | if (immutable && hasOwnProperty.call(state.node, key)) { 210 | state.node[key] = child.node; 211 | } 212 | 213 | child.isLast = i == state.keys.length - 1; 214 | child.isFirst = i == 0; 215 | 216 | if (modifiers.post) modifiers.post.call(state, child); 217 | 218 | path.pop(); 219 | }); 220 | parents.pop(); 221 | } 222 | 223 | if (modifiers.after) modifiers.after.call(state, state.node); 224 | 225 | return state; 226 | })(root).node; 227 | } 228 | 229 | function copy (src) { 230 | if (typeof src === 'object' && src !== null) { 231 | var dst; 232 | 233 | if (isArray(src)) { 234 | dst = []; 235 | } 236 | else if (isDate(src)) { 237 | dst = new Date(src.getTime ? src.getTime() : src); 238 | } 239 | else if (isRegExp(src)) { 240 | dst = new RegExp(src); 241 | } 242 | else if (isError(src)) { 243 | dst = { message: src.message }; 244 | } 245 | else if (isBoolean(src)) { 246 | dst = new Boolean(src); 247 | } 248 | else if (isNumber(src)) { 249 | dst = new Number(src); 250 | } 251 | else if (isString(src)) { 252 | dst = new String(src); 253 | } 254 | else if (Object.create && Object.getPrototypeOf) { 255 | dst = Object.create(Object.getPrototypeOf(src)); 256 | } 257 | else if (src.constructor === Object) { 258 | dst = {}; 259 | } 260 | else { 261 | var proto = 262 | (src.constructor && src.constructor.prototype) 263 | || src.__proto__ 264 | || {} 265 | ; 266 | var T = function () {}; 267 | T.prototype = proto; 268 | dst = new T; 269 | } 270 | 271 | forEach(objectKeys(src), function (key) { 272 | dst[key] = src[key]; 273 | }); 274 | return dst; 275 | } 276 | else return src; 277 | } 278 | 279 | var objectKeys = Object.keys || function keys (obj) { 280 | var res = []; 281 | for (var key in obj) res.push(key) 282 | return res; 283 | }; 284 | 285 | function toS (obj) { return Object.prototype.toString.call(obj) } 286 | function isDate (obj) { return toS(obj) === '[object Date]' } 287 | function isRegExp (obj) { return toS(obj) === '[object RegExp]' } 288 | function isError (obj) { return toS(obj) === '[object Error]' } 289 | function isBoolean (obj) { return toS(obj) === '[object Boolean]' } 290 | function isNumber (obj) { return toS(obj) === '[object Number]' } 291 | function isString (obj) { return toS(obj) === '[object String]' } 292 | 293 | var isArray = Array.isArray || function isArray (xs) { 294 | return Object.prototype.toString.call(xs) === '[object Array]'; 295 | }; 296 | 297 | var forEach = function (xs, fn) { 298 | if (xs.forEach) return xs.forEach(fn) 299 | else for (var i = 0; i < xs.length; i++) { 300 | fn(xs[i], i, xs); 301 | } 302 | }; 303 | 304 | forEach(objectKeys(Traverse.prototype), function (key) { 305 | traverse[key] = function (obj) { 306 | var args = [].slice.call(arguments, 1); 307 | var t = new Traverse(obj); 308 | return t[key].apply(t, args); 309 | }; 310 | }); 311 | 312 | var hasOwnProperty = Object.hasOwnProperty || function (obj, key) { 313 | return key in obj; 314 | }; 315 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "traverse", 3 | "version": "0.6.6", 4 | "description": "traverse and transform objects by visiting every node on a recursive walk", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "example", 8 | "test": "test" 9 | }, 10 | "devDependencies": { 11 | "tape": "~1.0.4" 12 | }, 13 | "scripts": { 14 | "test": "tape test/*.js" 15 | }, 16 | "testling": { 17 | "files": "test/*.js", 18 | "browsers": { 19 | "iexplore": [ 20 | "6.0", 21 | "7.0", 22 | "8.0", 23 | "9.0" 24 | ], 25 | "chrome": [ 26 | "10.0", 27 | "20.0" 28 | ], 29 | "firefox": [ 30 | "10.0", 31 | "15.0" 32 | ], 33 | "safari": [ 34 | "5.1" 35 | ], 36 | "opera": [ 37 | "12.0" 38 | ] 39 | } 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git://github.com/substack/js-traverse.git" 44 | }, 45 | "homepage": "https://github.com/substack/js-traverse", 46 | "keywords": [ 47 | "traverse", 48 | "walk", 49 | "recursive", 50 | "map", 51 | "forEach", 52 | "deep", 53 | "clone" 54 | ], 55 | "author": { 56 | "name": "James Halliday", 57 | "email": "mail@substack.net", 58 | "url": "http://substack.net" 59 | }, 60 | "license": "MIT", 61 | "readme": "# traverse\n\nTraverse and transform objects by visiting every node on a recursive walk.\n\n[![browser support](http://ci.testling.com/substack/js-traverse.png)](http://ci.testling.com/substack/js-traverse)\n\n[![build status](https://secure.travis-ci.org/substack/js-traverse.png)](http://travis-ci.org/substack/js-traverse)\n\n# examples\n\n## transform negative numbers in-place\n\nnegative.js\n\n````javascript\nvar traverse = require('traverse');\nvar obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];\n\ntraverse(obj).forEach(function (x) {\n if (x < 0) this.update(x + 128);\n});\n\nconsole.dir(obj);\n````\n\nOutput:\n\n [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]\n\n## collect leaf nodes\n\nleaves.js\n\n````javascript\nvar traverse = require('traverse');\n\nvar obj = {\n a : [1,2,3],\n b : 4,\n c : [5,6],\n d : { e : [7,8], f : 9 },\n};\n\nvar leaves = traverse(obj).reduce(function (acc, x) {\n if (this.isLeaf) acc.push(x);\n return acc;\n}, []);\n\nconsole.dir(leaves);\n````\n\nOutput:\n\n [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n\n## scrub circular references\n\nscrub.js:\n\n````javascript\nvar traverse = require('traverse');\n\nvar obj = { a : 1, b : 2, c : [ 3, 4 ] };\nobj.c.push(obj);\n\nvar scrubbed = traverse(obj).map(function (x) {\n if (this.circular) this.remove()\n});\nconsole.dir(scrubbed);\n````\n\noutput:\n\n { a: 1, b: 2, c: [ 3, 4 ] }\n\n# methods\n\nEach method that takes an `fn` uses the context documented below in the context\nsection.\n\n## .map(fn)\n\nExecute `fn` for each node in the object and return a new object with the\nresults of the walk. To update nodes in the result use `this.update(value)`.\n\n## .forEach(fn)\n\nExecute `fn` for each node in the object but unlike `.map()`, when\n`this.update()` is called it updates the object in-place.\n\n## .reduce(fn, acc)\n\nFor each node in the object, perform a\n[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function))\nwith the return value of `fn(acc, node)`.\n\nIf `acc` isn't specified, `acc` is set to the root object for the first step\nand the root element is skipped.\n\n## .paths()\n\nReturn an `Array` of every possible non-cyclic path in the object.\nPaths are `Array`s of string keys.\n\n## .nodes()\n\nReturn an `Array` of every node in the object.\n\n## .clone()\n\nCreate a deep clone of the object.\n\n## .get(path)\n\nGet the element at the array `path`.\n\n## .set(path, value)\n\nSet the element at the array `path` to `value`.\n\n## .has(path)\n\nReturn whether the element at the array `path` exists.\n\n# context\n\nEach method that takes a callback has a context (its `this` object) with these\nattributes:\n\n## this.node\n\nThe present node on the recursive walk\n\n## this.path\n\nAn array of string keys from the root to the present node\n\n## this.parent\n\nThe context of the node's parent.\nThis is `undefined` for the root node.\n\n## this.key\n\nThe name of the key of the present node in its parent.\nThis is `undefined` for the root node.\n\n## this.isRoot, this.notRoot\n\nWhether the present node is the root node\n\n## this.isLeaf, this.notLeaf\n\nWhether or not the present node is a leaf node (has no children)\n\n## this.level\n\nDepth of the node within the traversal\n\n## this.circular\n\nIf the node equals one of its parents, the `circular` attribute is set to the\ncontext of that parent and the traversal progresses no deeper.\n\n## this.update(value, stopHere=false)\n\nSet a new value for the present node.\n\nAll the elements in `value` will be recursively traversed unless `stopHere` is\ntrue.\n\n## this.remove(stopHere=false)\n\nRemove the current element from the output. If the node is in an Array it will\nbe spliced off. Otherwise it will be deleted from its parent.\n\n## this.delete(stopHere=false)\n\nDelete the current element from its parent in the output. Calls `delete` even on\nArrays.\n\n## this.before(fn)\n\nCall this function before any of the children are traversed.\n\nYou can assign into `this.keys` here to traverse in a custom order.\n\n## this.after(fn)\n\nCall this function after any of the children are traversed.\n\n## this.pre(fn)\n\nCall this function before each of the children are traversed.\n\n## this.post(fn)\n\nCall this function after each of the children are traversed.\n\n\n# install\n\nUsing [npm](http://npmjs.org) do:\n\n $ npm install traverse\n\n# license\n\nMIT\n", 62 | "readmeFilename": "readme.markdown", 63 | "bugs": { 64 | "url": "https://github.com/substack/js-traverse/issues" 65 | }, 66 | "_id": "traverse@0.6.6", 67 | "dist": { 68 | "shasum": "887acce42e0d9aa00e0e7e4c00c29529d7df90f2" 69 | }, 70 | "_from": "traverse@>=0.2.4", 71 | "_resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz" 72 | } 73 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/readme.markdown: -------------------------------------------------------------------------------- 1 | # traverse 2 | 3 | Traverse and transform objects by visiting every node on a recursive walk. 4 | 5 | [![browser support](http://ci.testling.com/substack/js-traverse.png)](http://ci.testling.com/substack/js-traverse) 6 | 7 | [![build status](https://secure.travis-ci.org/substack/js-traverse.png)](http://travis-ci.org/substack/js-traverse) 8 | 9 | # examples 10 | 11 | ## transform negative numbers in-place 12 | 13 | negative.js 14 | 15 | ````javascript 16 | var traverse = require('traverse'); 17 | var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; 18 | 19 | traverse(obj).forEach(function (x) { 20 | if (x < 0) this.update(x + 128); 21 | }); 22 | 23 | console.dir(obj); 24 | ```` 25 | 26 | Output: 27 | 28 | [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ] 29 | 30 | ## collect leaf nodes 31 | 32 | leaves.js 33 | 34 | ````javascript 35 | var traverse = require('traverse'); 36 | 37 | var obj = { 38 | a : [1,2,3], 39 | b : 4, 40 | c : [5,6], 41 | d : { e : [7,8], f : 9 }, 42 | }; 43 | 44 | var leaves = traverse(obj).reduce(function (acc, x) { 45 | if (this.isLeaf) acc.push(x); 46 | return acc; 47 | }, []); 48 | 49 | console.dir(leaves); 50 | ```` 51 | 52 | Output: 53 | 54 | [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 55 | 56 | ## scrub circular references 57 | 58 | scrub.js: 59 | 60 | ````javascript 61 | var traverse = require('traverse'); 62 | 63 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 64 | obj.c.push(obj); 65 | 66 | var scrubbed = traverse(obj).map(function (x) { 67 | if (this.circular) this.remove() 68 | }); 69 | console.dir(scrubbed); 70 | ```` 71 | 72 | output: 73 | 74 | { a: 1, b: 2, c: [ 3, 4 ] } 75 | 76 | # methods 77 | 78 | Each method that takes an `fn` uses the context documented below in the context 79 | section. 80 | 81 | ## .map(fn) 82 | 83 | Execute `fn` for each node in the object and return a new object with the 84 | results of the walk. To update nodes in the result use `this.update(value)`. 85 | 86 | ## .forEach(fn) 87 | 88 | Execute `fn` for each node in the object but unlike `.map()`, when 89 | `this.update()` is called it updates the object in-place. 90 | 91 | ## .reduce(fn, acc) 92 | 93 | For each node in the object, perform a 94 | [left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function)) 95 | with the return value of `fn(acc, node)`. 96 | 97 | If `acc` isn't specified, `acc` is set to the root object for the first step 98 | and the root element is skipped. 99 | 100 | ## .paths() 101 | 102 | Return an `Array` of every possible non-cyclic path in the object. 103 | Paths are `Array`s of string keys. 104 | 105 | ## .nodes() 106 | 107 | Return an `Array` of every node in the object. 108 | 109 | ## .clone() 110 | 111 | Create a deep clone of the object. 112 | 113 | ## .get(path) 114 | 115 | Get the element at the array `path`. 116 | 117 | ## .set(path, value) 118 | 119 | Set the element at the array `path` to `value`. 120 | 121 | ## .has(path) 122 | 123 | Return whether the element at the array `path` exists. 124 | 125 | # context 126 | 127 | Each method that takes a callback has a context (its `this` object) with these 128 | attributes: 129 | 130 | ## this.node 131 | 132 | The present node on the recursive walk 133 | 134 | ## this.path 135 | 136 | An array of string keys from the root to the present node 137 | 138 | ## this.parent 139 | 140 | The context of the node's parent. 141 | This is `undefined` for the root node. 142 | 143 | ## this.key 144 | 145 | The name of the key of the present node in its parent. 146 | This is `undefined` for the root node. 147 | 148 | ## this.isRoot, this.notRoot 149 | 150 | Whether the present node is the root node 151 | 152 | ## this.isLeaf, this.notLeaf 153 | 154 | Whether or not the present node is a leaf node (has no children) 155 | 156 | ## this.level 157 | 158 | Depth of the node within the traversal 159 | 160 | ## this.circular 161 | 162 | If the node equals one of its parents, the `circular` attribute is set to the 163 | context of that parent and the traversal progresses no deeper. 164 | 165 | ## this.update(value, stopHere=false) 166 | 167 | Set a new value for the present node. 168 | 169 | All the elements in `value` will be recursively traversed unless `stopHere` is 170 | true. 171 | 172 | ## this.remove(stopHere=false) 173 | 174 | Remove the current element from the output. If the node is in an Array it will 175 | be spliced off. Otherwise it will be deleted from its parent. 176 | 177 | ## this.delete(stopHere=false) 178 | 179 | Delete the current element from its parent in the output. Calls `delete` even on 180 | Arrays. 181 | 182 | ## this.before(fn) 183 | 184 | Call this function before any of the children are traversed. 185 | 186 | You can assign into `this.keys` here to traverse in a custom order. 187 | 188 | ## this.after(fn) 189 | 190 | Call this function after any of the children are traversed. 191 | 192 | ## this.pre(fn) 193 | 194 | Call this function before each of the children are traversed. 195 | 196 | ## this.post(fn) 197 | 198 | Call this function after each of the children are traversed. 199 | 200 | 201 | # install 202 | 203 | Using [npm](http://npmjs.org) do: 204 | 205 | $ npm install traverse 206 | 207 | # license 208 | 209 | MIT 210 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/circular.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | var deepEqual = require('./lib/deep_equal'); 4 | var util = require('util'); 5 | 6 | test('circular', function (t) { 7 | t.plan(1); 8 | 9 | var obj = { x : 3 }; 10 | obj.y = obj; 11 | traverse(obj).forEach(function (x) { 12 | if (this.path.join('') == 'y') { 13 | t.equal( 14 | util.inspect(this.circular.node), 15 | util.inspect(obj) 16 | ); 17 | } 18 | }); 19 | }); 20 | 21 | test('deepCirc', function (t) { 22 | t.plan(2); 23 | var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; 24 | obj.y[2] = obj; 25 | 26 | var times = 0; 27 | traverse(obj).forEach(function (x) { 28 | if (this.circular) { 29 | t.same(this.circular.path, []); 30 | t.same(this.path, [ 'y', 2 ]); 31 | } 32 | }); 33 | }); 34 | 35 | test('doubleCirc', function (t) { 36 | var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; 37 | obj.y[2] = obj; 38 | obj.x.push(obj.y); 39 | 40 | var circs = []; 41 | traverse(obj).forEach(function (x) { 42 | if (this.circular) { 43 | circs.push({ circ : this.circular, self : this, node : x }); 44 | } 45 | }); 46 | 47 | t.same(circs[0].self.path, [ 'x', 3, 2 ]); 48 | t.same(circs[0].circ.path, []); 49 | 50 | t.same(circs[1].self.path, [ 'y', 2 ]); 51 | t.same(circs[1].circ.path, []); 52 | 53 | t.same(circs.length, 2); 54 | t.end(); 55 | }); 56 | 57 | test('circDubForEach', function (t) { 58 | var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; 59 | obj.y[2] = obj; 60 | obj.x.push(obj.y); 61 | 62 | traverse(obj).forEach(function (x) { 63 | if (this.circular) this.update('...'); 64 | }); 65 | 66 | t.same(obj, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] }); 67 | t.end(); 68 | }); 69 | 70 | test('circDubMap', function (t) { 71 | var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; 72 | obj.y[2] = obj; 73 | obj.x.push(obj.y); 74 | 75 | var c = traverse(obj).map(function (x) { 76 | if (this.circular) { 77 | this.update('...'); 78 | } 79 | }); 80 | 81 | t.same(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] }); 82 | t.end(); 83 | }); 84 | 85 | test('circClone', function (t) { 86 | var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] }; 87 | obj.y[2] = obj; 88 | obj.x.push(obj.y); 89 | 90 | var clone = traverse.clone(obj); 91 | t.ok(obj !== clone); 92 | 93 | t.ok(clone.y[2] === clone); 94 | t.ok(clone.y[2] !== obj); 95 | t.ok(clone.x[3][2] === clone); 96 | t.ok(clone.x[3][2] !== obj); 97 | t.same(clone.x.slice(0,3), [1,2,3]); 98 | t.same(clone.y.slice(0,2), [4,5]); 99 | t.end(); 100 | }); 101 | 102 | test('circMapScrub', function (t) { 103 | var obj = { a : 1, b : 2 }; 104 | obj.c = obj; 105 | 106 | var scrubbed = traverse(obj).map(function (node) { 107 | if (this.circular) this.remove(); 108 | }); 109 | t.same( 110 | Object.keys(scrubbed).sort(), 111 | [ 'a', 'b' ] 112 | ); 113 | t.ok(deepEqual(scrubbed, { a : 1, b : 2 })); 114 | 115 | t.equal(obj.c, obj); 116 | t.end(); 117 | }); 118 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/date.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('dateEach', function (t) { 5 | var obj = { x : new Date, y : 10, z : 5 }; 6 | 7 | var counts = {}; 8 | 9 | traverse(obj).forEach(function (node) { 10 | var t = (node instanceof Date && 'Date') || typeof node; 11 | counts[t] = (counts[t] || 0) + 1; 12 | }); 13 | 14 | t.same(counts, { 15 | object : 1, 16 | Date : 1, 17 | number : 2, 18 | }); 19 | t.end(); 20 | }); 21 | 22 | test('dateMap', function (t) { 23 | var obj = { x : new Date, y : 10, z : 5 }; 24 | 25 | var res = traverse(obj).map(function (node) { 26 | if (typeof node === 'number') this.update(node + 100); 27 | }); 28 | 29 | t.ok(obj.x !== res.x); 30 | t.same(res, { 31 | x : obj.x, 32 | y : 110, 33 | z : 105, 34 | }); 35 | t.end(); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/equal.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | var deepEqual = require('./lib/deep_equal'); 4 | 5 | test('deepDates', function (t) { 6 | t.plan(2); 7 | 8 | t.ok( 9 | deepEqual( 10 | { d : new Date, x : [ 1, 2, 3 ] }, 11 | { d : new Date, x : [ 1, 2, 3 ] } 12 | ), 13 | 'dates should be equal' 14 | ); 15 | 16 | var d0 = new Date; 17 | setTimeout(function () { 18 | t.ok( 19 | !deepEqual( 20 | { d : d0, x : [ 1, 2, 3 ], }, 21 | { d : new Date, x : [ 1, 2, 3 ] } 22 | ), 23 | 'microseconds should count in date equality' 24 | ); 25 | }, 5); 26 | }); 27 | 28 | test('deepCircular', function (t) { 29 | var a = [1]; 30 | a.push(a); // a = [ 1, *a ] 31 | 32 | var b = [1]; 33 | b.push(a); // b = [ 1, [ 1, *a ] ] 34 | 35 | t.ok( 36 | !deepEqual(a, b), 37 | 'circular ref mount points count towards equality' 38 | ); 39 | 40 | var c = [1]; 41 | c.push(c); // c = [ 1, *c ] 42 | t.ok( 43 | deepEqual(a, c), 44 | 'circular refs are structurally the same here' 45 | ); 46 | 47 | var d = [1]; 48 | d.push(a); // c = [ 1, [ 1, *d ] ] 49 | t.ok( 50 | deepEqual(b, d), 51 | 'non-root circular ref structural comparison' 52 | ); 53 | 54 | t.end(); 55 | }); 56 | 57 | test('deepInstances', function (t) { 58 | t.ok( 59 | !deepEqual([ new Boolean(false) ], [ false ]), 60 | 'boolean instances are not real booleans' 61 | ); 62 | 63 | t.ok( 64 | !deepEqual([ new String('x') ], [ 'x' ]), 65 | 'string instances are not real strings' 66 | ); 67 | 68 | t.ok( 69 | !deepEqual([ new Number(4) ], [ 4 ]), 70 | 'number instances are not real numbers' 71 | ); 72 | 73 | t.ok( 74 | deepEqual([ new RegExp('x') ], [ /x/ ]), 75 | 'regexp instances are real regexps' 76 | ); 77 | 78 | t.ok( 79 | !deepEqual([ new RegExp(/./) ], [ /../ ]), 80 | 'these regexps aren\'t the same' 81 | ); 82 | 83 | t.ok( 84 | !deepEqual( 85 | [ function (x) { return x * 2 } ], 86 | [ function (x) { return x * 2 } ] 87 | ), 88 | 'functions with the same .toString() aren\'t necessarily the same' 89 | ); 90 | 91 | var f = function (x) { return x * 2 }; 92 | t.ok( 93 | deepEqual([ f ], [ f ]), 94 | 'these functions are actually equal' 95 | ); 96 | 97 | t.end(); 98 | }); 99 | 100 | test('deepEqual', function (t) { 101 | t.ok( 102 | !deepEqual([ 1, 2, 3 ], { 0 : 1, 1 : 2, 2 : 3 }), 103 | 'arrays are not objects' 104 | ); 105 | t.end(); 106 | }); 107 | 108 | test('falsy', function (t) { 109 | t.ok( 110 | !deepEqual([ undefined ], [ null ]), 111 | 'null is not undefined!' 112 | ); 113 | 114 | t.ok( 115 | !deepEqual([ null ], [ undefined ]), 116 | 'undefined is not null!' 117 | ); 118 | 119 | t.ok( 120 | !deepEqual( 121 | { a : 1, b : 2, c : [ 3, undefined, 5 ] }, 122 | { a : 1, b : 2, c : [ 3, null, 5 ] } 123 | ), 124 | 'undefined is not null, however deeply!' 125 | ); 126 | 127 | t.ok( 128 | !deepEqual( 129 | { a : 1, b : 2, c : [ 3, undefined, 5 ] }, 130 | { a : 1, b : 2, c : [ 3, null, 5 ] } 131 | ), 132 | 'null is not undefined, however deeply!' 133 | ); 134 | 135 | t.ok( 136 | !deepEqual( 137 | { a : 1, b : 2, c : [ 3, undefined, 5 ] }, 138 | { a : 1, b : 2, c : [ 3, null, 5 ] } 139 | ), 140 | 'null is not undefined, however deeply!' 141 | ); 142 | 143 | t.end(); 144 | }); 145 | 146 | test('deletedArrayEqual', function (t) { 147 | var xs = [ 1, 2, 3, 4 ]; 148 | delete xs[2]; 149 | 150 | var ys = Object.create(Array.prototype); 151 | ys[0] = 1; 152 | ys[1] = 2; 153 | ys[3] = 4; 154 | 155 | t.ok( 156 | deepEqual(xs, ys), 157 | 'arrays with deleted elements are only equal to' 158 | + ' arrays with similarly deleted elements' 159 | ); 160 | 161 | t.ok( 162 | !deepEqual(xs, [ 1, 2, undefined, 4 ]), 163 | 'deleted array elements cannot be undefined' 164 | ); 165 | 166 | t.ok( 167 | !deepEqual(xs, [ 1, 2, null, 4 ]), 168 | 'deleted array elements cannot be null' 169 | ); 170 | 171 | t.end(); 172 | }); 173 | 174 | test('deletedObjectEqual', function (t) { 175 | var obj = { a : 1, b : 2, c : 3 }; 176 | delete obj.c; 177 | 178 | t.ok( 179 | deepEqual(obj, { a : 1, b : 2 }), 180 | 'deleted object elements should not show up' 181 | ); 182 | 183 | t.ok( 184 | !deepEqual(obj, { a : 1, b : 2, c : undefined }), 185 | 'deleted object elements are not undefined' 186 | ); 187 | 188 | t.ok( 189 | !deepEqual(obj, { a : 1, b : 2, c : null }), 190 | 'deleted object elements are not null' 191 | ); 192 | 193 | t.end(); 194 | }); 195 | 196 | test('emptyKeyEqual', function (t) { 197 | t.ok(!deepEqual( 198 | { a : 1 }, { a : 1, '' : 55 } 199 | )); 200 | 201 | t.end(); 202 | }); 203 | 204 | test('deepArguments', function (t) { 205 | t.ok( 206 | !deepEqual( 207 | [ 4, 5, 6 ], 208 | (function () { return arguments })(4, 5, 6) 209 | ), 210 | 'arguments are not arrays' 211 | ); 212 | 213 | t.ok( 214 | deepEqual( 215 | (function () { return arguments })(4, 5, 6), 216 | (function () { return arguments })(4, 5, 6) 217 | ), 218 | 'arguments should equal' 219 | ); 220 | 221 | t.end(); 222 | }); 223 | 224 | test('deepUn', function (t) { 225 | t.ok(!deepEqual({ a : 1, b : 2 }, undefined)); 226 | t.ok(!deepEqual({ a : 1, b : 2 }, {})); 227 | t.ok(!deepEqual(undefined, { a : 1, b : 2 })); 228 | t.ok(!deepEqual({}, { a : 1, b : 2 })); 229 | t.ok(deepEqual(undefined, undefined)); 230 | t.ok(deepEqual(null, null)); 231 | t.ok(!deepEqual(undefined, null)); 232 | 233 | t.end(); 234 | }); 235 | 236 | test('deepLevels', function (t) { 237 | var xs = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ]; 238 | t.ok(!deepEqual(xs, [])); 239 | t.end(); 240 | }); 241 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/error.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('traverse an Error', function (t) { 5 | var obj = new Error("test"); 6 | var results = traverse(obj).map(function (node) {}); 7 | t.same(results, { message: 'test' }); 8 | 9 | t.end(); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/has.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('has', function (t) { 5 | var obj = { a : 2, b : [ 4, 5, { c : 6 } ] }; 6 | 7 | t.equal(traverse(obj).has([ 'b', 2, 'c' ]), true) 8 | t.equal(traverse(obj).has([ 'b', 2, 'c', 0 ]), false) 9 | t.equal(traverse(obj).has([ 'b', 2, 'd' ]), false) 10 | t.equal(traverse(obj).has([]), true) 11 | t.equal(traverse(obj).has([ 'a' ]), true) 12 | t.equal(traverse(obj).has([ 'a', 2 ]), false) 13 | 14 | t.end(); 15 | }); 16 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/instance.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | var EventEmitter = require('events').EventEmitter; 4 | 5 | test('check instanceof on node elems', function (t) { 6 | var counts = { emitter : 0 }; 7 | 8 | traverse([ new EventEmitter, 3, 4, { ev : new EventEmitter }]) 9 | .forEach(function (node) { 10 | if (node instanceof EventEmitter) counts.emitter ++; 11 | }) 12 | ; 13 | 14 | t.equal(counts.emitter, 2); 15 | 16 | t.end(); 17 | }); 18 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/interface.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('interface map', function (t) { 5 | var obj = { a : [ 5,6,7 ], b : { c : [8] } }; 6 | 7 | t.same( 8 | traverse.paths(obj) 9 | .sort() 10 | .map(function (path) { return path.join('/') }) 11 | .slice(1) 12 | .join(' ') 13 | , 14 | 'a a/0 a/1 a/2 b b/c b/c/0' 15 | ); 16 | 17 | t.same( 18 | traverse.nodes(obj), 19 | [ 20 | { a: [ 5, 6, 7 ], b: { c: [ 8 ] } }, 21 | [ 5, 6, 7 ], 5, 6, 7, 22 | { c: [ 8 ] }, [ 8 ], 8 23 | ] 24 | ); 25 | 26 | t.same( 27 | traverse.map(obj, function (node) { 28 | if (typeof node == 'number') { 29 | return node + 1000; 30 | } 31 | else if (Array.isArray(node)) { 32 | return node.join(' '); 33 | } 34 | }), 35 | { a: '5 6 7', b: { c: '8' } } 36 | ); 37 | 38 | var nodes = 0; 39 | traverse.forEach(obj, function (node) { nodes ++ }); 40 | t.same(nodes, 8); 41 | 42 | t.end(); 43 | }); 44 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/json.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('json test', function (t) { 5 | var id = 54; 6 | var callbacks = {}; 7 | var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; 8 | 9 | var scrubbed = traverse(obj).map(function (x) { 10 | if (typeof x === 'function') { 11 | callbacks[id] = { id : id, f : x, path : this.path }; 12 | this.update('[Function]'); 13 | id++; 14 | } 15 | }); 16 | 17 | t.equal( 18 | scrubbed.moo, '[Function]', 19 | 'obj.moo replaced with "[Function]"' 20 | ); 21 | 22 | t.equal( 23 | scrubbed.foo[3], '[Function]', 24 | 'obj.foo[3] replaced with "[Function]"' 25 | ); 26 | 27 | t.same(scrubbed, { 28 | moo : '[Function]', 29 | foo : [ 2, 3, 4, "[Function]" ] 30 | }, 'Full JSON string matches'); 31 | 32 | t.same( 33 | typeof obj.moo, 'function', 34 | 'Original obj.moo still a function' 35 | ); 36 | 37 | t.same( 38 | typeof obj.foo[3], 'function', 39 | 'Original obj.foo[3] still a function' 40 | ); 41 | 42 | t.same(callbacks, { 43 | 54: { id: 54, f : obj.moo, path: [ 'moo' ] }, 44 | 55: { id: 55, f : obj.foo[3], path: [ 'foo', '3' ] }, 45 | }, 'Check the generated callbacks list'); 46 | 47 | t.end(); 48 | }); 49 | 50 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/keys.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('sort test', function (t) { 5 | var acc = []; 6 | traverse({ 7 | a: 30, 8 | b: 22, 9 | id: 9 10 | }).forEach(function (node) { 11 | if ((! Array.isArray(node)) && typeof node === 'object') { 12 | this.before(function(node) { 13 | this.keys = Object.keys(node); 14 | this.keys.sort(function(a, b) { 15 | a = [a === "id" ? 0 : 1, a]; 16 | b = [b === "id" ? 0 : 1, b]; 17 | return a < b ? -1 : a > b ? 1 : 0; 18 | }); 19 | }); 20 | } 21 | if (this.isLeaf) acc.push(node); 22 | }); 23 | 24 | t.equal( 25 | acc.join(' '), 26 | '9 30 22', 27 | 'Traversal in a custom order' 28 | ); 29 | 30 | t.end(); 31 | }); 32 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/leaves.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('leaves test', function (t) { 5 | var acc = []; 6 | traverse({ 7 | a : [1,2,3], 8 | b : 4, 9 | c : [5,6], 10 | d : { e : [7,8], f : 9 } 11 | }).forEach(function (x) { 12 | if (this.isLeaf) acc.push(x); 13 | }); 14 | 15 | t.equal( 16 | acc.join(' '), 17 | '1 2 3 4 5 6 7 8 9', 18 | 'Traversal in the right(?) order' 19 | ); 20 | 21 | t.end(); 22 | }); 23 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js: -------------------------------------------------------------------------------- 1 | var traverse = require('../../'); 2 | 3 | module.exports = function (a, b) { 4 | if (arguments.length !== 2) { 5 | throw new Error( 6 | 'deepEqual requires exactly two objects to compare against' 7 | ); 8 | } 9 | 10 | var equal = true; 11 | var node = b; 12 | 13 | traverse(a).forEach(function (y) { 14 | var notEqual = (function () { 15 | equal = false; 16 | //this.stop(); 17 | return undefined; 18 | }).bind(this); 19 | 20 | //if (node === undefined || node === null) return notEqual(); 21 | 22 | if (!this.isRoot) { 23 | /* 24 | if (!Object.hasOwnProperty.call(node, this.key)) { 25 | return notEqual(); 26 | } 27 | */ 28 | if (typeof node !== 'object') return notEqual(); 29 | node = node[this.key]; 30 | } 31 | 32 | var x = node; 33 | 34 | this.post(function () { 35 | node = x; 36 | }); 37 | 38 | var toS = function (o) { 39 | return Object.prototype.toString.call(o); 40 | }; 41 | 42 | if (this.circular) { 43 | if (traverse(b).get(this.circular.path) !== x) notEqual(); 44 | } 45 | else if (typeof x !== typeof y) { 46 | notEqual(); 47 | } 48 | else if (x === null || y === null || x === undefined || y === undefined) { 49 | if (x !== y) notEqual(); 50 | } 51 | else if (x.__proto__ !== y.__proto__) { 52 | notEqual(); 53 | } 54 | else if (x === y) { 55 | // nop 56 | } 57 | else if (typeof x === 'function') { 58 | if (x instanceof RegExp) { 59 | // both regexps on account of the __proto__ check 60 | if (x.toString() != y.toString()) notEqual(); 61 | } 62 | else if (x !== y) notEqual(); 63 | } 64 | else if (typeof x === 'object') { 65 | if (toS(y) === '[object Arguments]' 66 | || toS(x) === '[object Arguments]') { 67 | if (toS(x) !== toS(y)) { 68 | notEqual(); 69 | } 70 | } 71 | else if (toS(y) === '[object RegExp]' 72 | || toS(x) === '[object RegExp]') { 73 | if (!x || !y || x.toString() !== y.toString()) notEqual(); 74 | } 75 | else if (x instanceof Date || y instanceof Date) { 76 | if (!(x instanceof Date) || !(y instanceof Date) 77 | || x.getTime() !== y.getTime()) { 78 | notEqual(); 79 | } 80 | } 81 | else { 82 | var kx = Object.keys(x); 83 | var ky = Object.keys(y); 84 | if (kx.length !== ky.length) return notEqual(); 85 | for (var i = 0; i < kx.length; i++) { 86 | var k = kx[i]; 87 | if (!Object.hasOwnProperty.call(y, k)) { 88 | notEqual(); 89 | } 90 | } 91 | } 92 | } 93 | }); 94 | 95 | return equal; 96 | }; 97 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/mutability.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | var deepEqual = require('./lib/deep_equal'); 4 | 5 | test('mutate', function (t) { 6 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 7 | var res = traverse(obj).forEach(function (x) { 8 | if (typeof x === 'number' && x % 2 === 0) { 9 | this.update(x * 10); 10 | } 11 | }); 12 | t.same(obj, res); 13 | t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] }); 14 | t.end(); 15 | }); 16 | 17 | test('mutateT', function (t) { 18 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 19 | var res = traverse.forEach(obj, function (x) { 20 | if (typeof x === 'number' && x % 2 === 0) { 21 | this.update(x * 10); 22 | } 23 | }); 24 | t.same(obj, res); 25 | t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] }); 26 | t.end(); 27 | }); 28 | 29 | test('map', function (t) { 30 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 31 | var res = traverse(obj).map(function (x) { 32 | if (typeof x === 'number' && x % 2 === 0) { 33 | this.update(x * 10); 34 | } 35 | }); 36 | t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] }); 37 | t.same(res, { a : 1, b : 20, c : [ 3, 40 ] }); 38 | t.end(); 39 | }); 40 | 41 | test('mapT', function (t) { 42 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 43 | var res = traverse.map(obj, function (x) { 44 | if (typeof x === 'number' && x % 2 === 0) { 45 | this.update(x * 10); 46 | } 47 | }); 48 | t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] }); 49 | t.same(res, { a : 1, b : 20, c : [ 3, 40 ] }); 50 | t.end(); 51 | }); 52 | 53 | test('clone', function (t) { 54 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 55 | var res = traverse(obj).clone(); 56 | t.same(obj, res); 57 | t.ok(obj !== res); 58 | obj.a ++; 59 | t.same(res.a, 1); 60 | obj.c.push(5); 61 | t.same(res.c, [ 3, 4 ]); 62 | t.end(); 63 | }); 64 | 65 | test('cloneT', function (t) { 66 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 67 | var res = traverse.clone(obj); 68 | t.same(obj, res); 69 | t.ok(obj !== res); 70 | obj.a ++; 71 | t.same(res.a, 1); 72 | obj.c.push(5); 73 | t.same(res.c, [ 3, 4 ]); 74 | t.end(); 75 | }); 76 | 77 | test('reduce', function (t) { 78 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 79 | var res = traverse(obj).reduce(function (acc, x) { 80 | if (this.isLeaf) acc.push(x); 81 | return acc; 82 | }, []); 83 | t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] }); 84 | t.same(res, [ 1, 2, 3, 4 ]); 85 | t.end(); 86 | }); 87 | 88 | test('reduceInit', function (t) { 89 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 90 | var res = traverse(obj).reduce(function (acc, x) { 91 | if (this.isRoot) assert.fail('got root'); 92 | return acc; 93 | }); 94 | t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] }); 95 | t.same(res, obj); 96 | t.end(); 97 | }); 98 | 99 | test('remove', function (t) { 100 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 101 | traverse(obj).forEach(function (x) { 102 | if (this.isLeaf && x % 2 == 0) this.remove(); 103 | }); 104 | 105 | t.same(obj, { a : 1, c : [ 3 ] }); 106 | t.end(); 107 | }); 108 | 109 | exports.removeNoStop = function() { 110 | var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 }; 111 | 112 | var keys = []; 113 | traverse(obj).forEach(function (x) { 114 | keys.push(this.key) 115 | if (this.key == 'c') this.remove(); 116 | }); 117 | 118 | t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e', 'f']) 119 | t.end(); 120 | } 121 | 122 | exports.removeStop = function() { 123 | var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 }; 124 | 125 | var keys = []; 126 | traverse(obj).forEach(function (x) { 127 | keys.push(this.key) 128 | if (this.key == 'c') this.remove(true); 129 | }); 130 | 131 | t.same(keys, [undefined, 'a', 'b', 'c', 'f']) 132 | t.end(); 133 | } 134 | 135 | test('removeMap', function (t) { 136 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 137 | var res = traverse(obj).map(function (x) { 138 | if (this.isLeaf && x % 2 == 0) this.remove(); 139 | }); 140 | 141 | t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] }); 142 | t.same(res, { a : 1, c : [ 3 ] }); 143 | t.end(); 144 | }); 145 | 146 | test('delete', function (t) { 147 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 148 | traverse(obj).forEach(function (x) { 149 | if (this.isLeaf && x % 2 == 0) this.delete(); 150 | }); 151 | 152 | t.ok(!deepEqual( 153 | obj, { a : 1, c : [ 3, undefined ] } 154 | )); 155 | 156 | t.ok(deepEqual( 157 | obj, { a : 1, c : [ 3 ] } 158 | )); 159 | 160 | t.ok(!deepEqual( 161 | obj, { a : 1, c : [ 3, null ] } 162 | )); 163 | t.end(); 164 | }); 165 | 166 | test('deleteNoStop', function (t) { 167 | var obj = { a : 1, b : 2, c : { d: 3, e: 4 } }; 168 | 169 | var keys = []; 170 | traverse(obj).forEach(function (x) { 171 | keys.push(this.key) 172 | if (this.key == 'c') this.delete(); 173 | }); 174 | 175 | t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e']) 176 | t.end(); 177 | }); 178 | 179 | test('deleteStop', function (t) { 180 | var obj = { a : 1, b : 2, c : { d: 3, e: 4 } }; 181 | 182 | var keys = []; 183 | traverse(obj).forEach(function (x) { 184 | keys.push(this.key) 185 | if (this.key == 'c') this.delete(true); 186 | }); 187 | 188 | t.same(keys, [undefined, 'a', 'b', 'c']) 189 | t.end(); 190 | }); 191 | 192 | test('deleteRedux', function (t) { 193 | var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] }; 194 | traverse(obj).forEach(function (x) { 195 | if (this.isLeaf && x % 2 == 0) this.delete(); 196 | }); 197 | 198 | t.ok(!deepEqual( 199 | obj, { a : 1, c : [ 3, undefined, 5 ] } 200 | )); 201 | 202 | t.ok(deepEqual( 203 | obj, { a : 1, c : [ 3 ,, 5 ] } 204 | )); 205 | 206 | t.ok(!deepEqual( 207 | obj, { a : 1, c : [ 3, null, 5 ] } 208 | )); 209 | 210 | t.ok(!deepEqual( 211 | obj, { a : 1, c : [ 3, 5 ] } 212 | )); 213 | 214 | t.end(); 215 | }); 216 | 217 | test('deleteMap', function (t) { 218 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 219 | var res = traverse(obj).map(function (x) { 220 | if (this.isLeaf && x % 2 == 0) this.delete(); 221 | }); 222 | 223 | t.ok(deepEqual( 224 | obj, 225 | { a : 1, b : 2, c : [ 3, 4 ] } 226 | )); 227 | 228 | var xs = [ 3, 4 ]; 229 | delete xs[1]; 230 | 231 | t.ok(deepEqual( 232 | res, { a : 1, c : xs } 233 | )); 234 | 235 | t.ok(deepEqual( 236 | res, { a : 1, c : [ 3, ] } 237 | )); 238 | 239 | t.ok(deepEqual( 240 | res, { a : 1, c : [ 3 ] } 241 | )); 242 | 243 | t.end(); 244 | }); 245 | 246 | test('deleteMapRedux', function (t) { 247 | var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] }; 248 | var res = traverse(obj).map(function (x) { 249 | if (this.isLeaf && x % 2 == 0) this.delete(); 250 | }); 251 | 252 | t.ok(deepEqual( 253 | obj, 254 | { a : 1, b : 2, c : [ 3, 4, 5 ] } 255 | )); 256 | 257 | var xs = [ 3, 4, 5 ]; 258 | delete xs[1]; 259 | 260 | t.ok(deepEqual( 261 | res, { a : 1, c : xs } 262 | )); 263 | 264 | t.ok(!deepEqual( 265 | res, { a : 1, c : [ 3, 5 ] } 266 | )); 267 | 268 | t.ok(deepEqual( 269 | res, { a : 1, c : [ 3 ,, 5 ] } 270 | )); 271 | 272 | t.end(); 273 | }); 274 | 275 | test('objectToString', function (t) { 276 | var obj = { a : 1, b : 2, c : [ 3, 4 ] }; 277 | var res = traverse(obj).forEach(function (x) { 278 | if (typeof x === 'object' && !this.isRoot) { 279 | this.update(JSON.stringify(x)); 280 | } 281 | }); 282 | t.same(obj, res); 283 | t.same(obj, { a : 1, b : 2, c : "[3,4]" }); 284 | t.end(); 285 | }); 286 | 287 | test('stringToObject', function (t) { 288 | var obj = { a : 1, b : 2, c : "[3,4]" }; 289 | var res = traverse(obj).forEach(function (x) { 290 | if (typeof x === 'string') { 291 | this.update(JSON.parse(x)); 292 | } 293 | else if (typeof x === 'number' && x % 2 === 0) { 294 | this.update(x * 10); 295 | } 296 | }); 297 | t.deepEqual(obj, res); 298 | t.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] }); 299 | t.end(); 300 | }); 301 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/negative.js: -------------------------------------------------------------------------------- 1 | var traverse = require('../'); 2 | var test = require('tape'); 3 | 4 | test('negative update test', function (t) { 5 | var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; 6 | var fixed = traverse.map(obj, function (x) { 7 | if (x < 0) this.update(x + 128); 8 | }); 9 | 10 | t.same(fixed, 11 | [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ], 12 | 'Negative values += 128' 13 | ); 14 | 15 | t.same(obj, 16 | [ 5, 6, -3, [ 7, 8, -2, 1 ], { f: 10, g: -13 } ], 17 | 'Original references not modified' 18 | ); 19 | 20 | t.end(); 21 | }); 22 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/obj.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('traverse an object with nested functions', function (t) { 5 | t.plan(1); 6 | 7 | function Cons (x) { 8 | t.equal(x, 10) 9 | }; 10 | traverse(new Cons(10)); 11 | }); 12 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/siblings.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('siblings', function (t) { 5 | var obj = { a : 1, b : 2, c : [ 4, 5, 6 ] }; 6 | 7 | var res = traverse(obj).reduce(function (acc, x) { 8 | var p = '/' + this.path.join('/'); 9 | if (this.parent) { 10 | acc[p] = { 11 | siblings : this.parent.keys, 12 | key : this.key, 13 | index : this.parent.keys.indexOf(this.key) 14 | }; 15 | } 16 | else { 17 | acc[p] = { 18 | siblings : [], 19 | key : this.key, 20 | index : -1 21 | } 22 | } 23 | return acc; 24 | }, {}); 25 | 26 | t.same(res, { 27 | '/' : { siblings : [], key : undefined, index : -1 }, 28 | '/a' : { siblings : [ 'a', 'b', 'c' ], key : 'a', index : 0 }, 29 | '/b' : { siblings : [ 'a', 'b', 'c' ], key : 'b', index : 1 }, 30 | '/c' : { siblings : [ 'a', 'b', 'c' ], key : 'c', index : 2 }, 31 | '/c/0' : { siblings : [ '0', '1', '2' ], key : '0', index : 0 }, 32 | '/c/1' : { siblings : [ '0', '1', '2' ], key : '1', index : 1 }, 33 | '/c/2' : { siblings : [ '0', '1', '2' ], key : '2', index : 2 } 34 | }); 35 | 36 | t.end(); 37 | }); 38 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/stop.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('stop', function (t) { 5 | var visits = 0; 6 | traverse('abcdefghij'.split('')).forEach(function (node) { 7 | if (typeof node === 'string') { 8 | visits ++; 9 | if (node === 'e') this.stop() 10 | } 11 | }); 12 | 13 | t.equal(visits, 5); 14 | t.end(); 15 | }); 16 | 17 | test('stopMap', function (t) { 18 | var s = traverse('abcdefghij'.split('')).map(function (node) { 19 | if (typeof node === 'string') { 20 | if (node === 'e') this.stop() 21 | return node.toUpperCase(); 22 | } 23 | }).join(''); 24 | 25 | t.equal(s, 'ABCDEfghij'); 26 | t.end(); 27 | }); 28 | 29 | test('stopReduce', function (t) { 30 | var obj = { 31 | a : [ 4, 5 ], 32 | b : [ 6, [ 7, 8, 9 ] ] 33 | }; 34 | var xs = traverse(obj).reduce(function (acc, node) { 35 | if (this.isLeaf) { 36 | if (node === 7) this.stop(); 37 | else acc.push(node) 38 | } 39 | return acc; 40 | }, []); 41 | 42 | t.same(xs, [ 4, 5, 6 ]); 43 | t.end(); 44 | }); 45 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/stringify.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | 4 | test('stringify', function (t) { 5 | var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; 6 | 7 | var s = ''; 8 | traverse(obj).forEach(function (node) { 9 | if (Array.isArray(node)) { 10 | this.before(function () { s += '[' }); 11 | this.post(function (child) { 12 | if (!child.isLast) s += ','; 13 | }); 14 | this.after(function () { s += ']' }); 15 | } 16 | else if (typeof node == 'object') { 17 | this.before(function () { s += '{' }); 18 | this.pre(function (x, key) { 19 | s += '"' + key + '"' + ':'; 20 | }); 21 | this.post(function (child) { 22 | if (!child.isLast) s += ','; 23 | }); 24 | this.after(function () { s += '}' }); 25 | } 26 | else if (typeof node == 'function') { 27 | s += 'null'; 28 | } 29 | else { 30 | s += node.toString(); 31 | } 32 | }); 33 | 34 | t.equal(s, JSON.stringify(obj)); 35 | t.end(); 36 | }); 37 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/subexpr.js: -------------------------------------------------------------------------------- 1 | var traverse = require('../'); 2 | var test = require('tape'); 3 | 4 | test('subexpr', function (t) { 5 | var obj = [ 'a', 4, 'b', 5, 'c', 6 ]; 6 | var r = traverse(obj).map(function (x) { 7 | if (typeof x === 'number') { 8 | this.update([ x - 0.1, x, x + 0.1 ], true); 9 | } 10 | }); 11 | 12 | t.same(obj, [ 'a', 4, 'b', 5, 'c', 6 ]); 13 | t.same(r, [ 14 | 'a', [ 3.9, 4, 4.1 ], 15 | 'b', [ 4.9, 5, 5.1 ], 16 | 'c', [ 5.9, 6, 6.1 ], 17 | ]); 18 | t.end(); 19 | }); 20 | 21 | test('block', function (t) { 22 | var obj = [ [ 1 ], [ 2 ], [ 3 ] ]; 23 | var r = traverse(obj).map(function (x) { 24 | if (Array.isArray(x) && !this.isRoot) { 25 | if (x[0] === 5) this.block() 26 | else this.update([ [ x[0] + 1 ] ]) 27 | } 28 | }); 29 | 30 | t.same(r, [ 31 | [ [ [ [ [ 5 ] ] ] ] ], 32 | [ [ [ [ 5 ] ] ] ], 33 | [ [ [ 5 ] ] ], 34 | ]); 35 | t.end(); 36 | }); 37 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/super_deep.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var traverse = require('../'); 3 | var deepEqual = require('./lib/deep_equal'); 4 | 5 | test('super_deep', function (t) { 6 | var util = require('util'); 7 | var a0 = make(); 8 | var a1 = make(); 9 | t.ok(deepEqual(a0, a1)); 10 | 11 | a0.c.d.moo = true; 12 | t.ok(!deepEqual(a0, a1)); 13 | 14 | a1.c.d.moo = true; 15 | t.ok(deepEqual(a0, a1)); 16 | 17 | // TODO: this one 18 | //a0.c.a = a1; 19 | //t.ok(!deepEqual(a0, a1)); 20 | t.end(); 21 | }); 22 | 23 | function make () { 24 | var a = { self : 'a' }; 25 | var b = { self : 'b' }; 26 | var c = { self : 'c' }; 27 | var d = { self : 'd' }; 28 | var e = { self : 'e' }; 29 | 30 | a.a = a; 31 | a.b = b; 32 | a.c = c; 33 | 34 | b.a = a; 35 | b.b = b; 36 | b.c = c; 37 | 38 | c.a = a; 39 | c.b = b; 40 | c.c = c; 41 | c.d = d; 42 | 43 | d.a = a; 44 | d.b = b; 45 | d.c = c; 46 | d.d = d; 47 | d.e = e; 48 | 49 | e.a = a; 50 | e.b = b; 51 | e.c = c; 52 | e.d = d; 53 | e.e = e; 54 | 55 | return a; 56 | } 57 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/node_modules/traverse/testling/leaves.js: -------------------------------------------------------------------------------- 1 | var traverse = require('./'); 2 | var test = require('testling'); 3 | 4 | test('leaves', function (t) { 5 | var obj = { 6 | a : [1,2,3], 7 | b : 4, 8 | c : [5,6], 9 | d : { e : [7,8], f : 9 } 10 | }; 11 | 12 | var acc = []; 13 | traverse(obj).forEach(function (x) { 14 | if (this.isLeaf) acc.push(x); 15 | }); 16 | 17 | t.deepEqual( 18 | acc, [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ], 19 | 'traversal in the proper order' 20 | ); 21 | t.end(); 22 | }); 23 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hashish", 3 | "version": "0.0.4", 4 | "description": "Hash data structure manipulation functions", 5 | "main": "./index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "http://github.com/substack/node-hashish.git" 9 | }, 10 | "keywords": [ 11 | "hash", 12 | "object", 13 | "convenience", 14 | "manipulation", 15 | "data structure" 16 | ], 17 | "author": { 18 | "name": "James Halliday", 19 | "email": "mail@substack.net", 20 | "url": "http://substack.net" 21 | }, 22 | "dependencies": { 23 | "traverse": ">=0.2.4" 24 | }, 25 | "devDependencies": { 26 | "expresso": ">=0.6.0" 27 | }, 28 | "scripts": { 29 | "test": "expresso" 30 | }, 31 | "license": "MIT/X11", 32 | "engine": [ 33 | "node >=0.2.0" 34 | ], 35 | "readme": "Hashish\n=======\n\nHashish is a node.js library for manipulating hash data structures.\nIt is distilled from the finest that ruby, perl, and haskell have to offer by\nway of hash/map interfaces.\n\nHashish provides a chaining interface, where you can do:\n\n var Hash = require('hashish');\n \n Hash({ a : 1, b : 2, c : 3, d : 4 })\n .map(function (x) { return x * 10 })\n .filter(function (x) { return x < 30 })\n .forEach(function (x, key) {\n console.log(key + ' => ' + x);\n })\n ;\n \nOutput:\n\n a => 10\n b => 20\n\nSome functions and attributes in the chaining interface are terminal, like\n`.items` or `.detect()`. They return values of their own instead of the chain\ncontext.\n\nEach function in the chainable interface is also attached to `Hash` in chainless\nform:\n\n var Hash = require('hashish');\n var obj = { a : 1, b : 2, c : 3, d : 4 };\n \n var mapped = Hash.map(obj, function (x) {\n return x * 10\n });\n \n console.dir(mapped);\n\nOutput:\n\n { a: 10, b: 20, c: 30, d: 40 }\n\nIn either case, the 'this' context of the function calls is the same object that\nthe chained functions return, so you can make nested chains.\n\nMethods\n=======\n\nforEach(cb)\n-----------\n\nFor each key/value in the hash, calls `cb(value, key)`.\n\nmap(cb)\n-------\n\nFor each key/value in the hash, calls `cb(value, key)`.\nThe return value of `cb` is the new value at `key` in the resulting hash.\n\nfilter(cb)\n----------\n\nFor each key/value in the hash, calls `cb(value, key)`.\nThe resulting hash omits key/value pairs where `cb` returned a falsy value.\n\ndetect(cb)\n----------\n\nReturns the first value in the hash for which `cb(value, key)` is non-falsy.\nOrder of hashes is not well-defined so watch out for that.\n\nreduce(cb)\n----------\n\nReturns the accumulated value of a left-fold over the key/value pairs.\n\nsome(cb)\n--------\n\nReturns a boolean: whether or not `cb(value, key)` ever returned a non-falsy\nvalue.\n\nupdate(obj1, [obj2, obj3, ...])\n-----------\n\nMutate the context hash, merging the key/value pairs from the passed objects\nand overwriting keys from the context hash if the current `obj` has keys of\nthe same name. Falsy arguments are silently ignored.\n\nupdateAll([ obj1, obj2, ... ])\n------------------------------\n\nLike multi-argument `update()` but operate on an array directly.\n\nmerge(obj1, [obj2, obj3, ...])\n----------\n\nMerge the key/value pairs from the passed objects into the resultant hash\nwithout modifying the context hash. Falsy arguments are silently ignored.\n\nmergeAll([ obj1, obj2, ... ])\n------------------------------\n\nLike multi-argument `merge()` but operate on an array directly.\n\nhas(key)\n--------\n\nReturn whether the hash has a key, `key`.\n\nvaluesAt(keys)\n--------------\n\nReturn an Array with the values at the keys from `keys`.\n\ntap(cb)\n-------\n\nCall `cb` with the present raw hash.\nThis function is chainable.\n\nextract(keys)\n-------------\n\nFilter by including only those keys in `keys` in the resulting hash.\n\nexclude(keys)\n-------------\n\nFilter by excluding those keys in `keys` in the resulting hash.\n\nAttributes\n==========\n\nThese are attributes in the chaining interface and functions in the `Hash.xxx`\ninterface.\n\nkeys\n----\n\nReturn all the enumerable attribute keys in the hash.\n\nvalues\n------\n\nReturn all the enumerable attribute values in the hash.\n\ncompact\n-------\n\nFilter out values which are `=== undefined`.\n\nclone\n-----\n\nMake a deep copy of the hash.\n\ncopy\n----\n\nMake a shallow copy of the hash.\n\nlength\n------\n\nReturn the number of key/value pairs in the hash.\nNote: use `Hash.size()` for non-chain mode.\n\nsize\n----\n\nAlias for `length` since `Hash.length` is masked by `Function.prototype`.\n\nSee Also\n========\n\nSee also [creationix's pattern/hash](http://github.com/creationix/pattern),\nwhich does a similar thing except with hash inputs and array outputs.\n\nInstallation\n============\n\nTo install with [npm](http://github.com/isaacs/npm):\n \n npm install hashish\n\nTo run the tests with [expresso](http://github.com/visionmedia/expresso):\n\n expresso\n", 36 | "readmeFilename": "README.markdown", 37 | "bugs": { 38 | "url": "https://github.com/substack/node-hashish/issues" 39 | }, 40 | "_id": "hashish@0.0.4", 41 | "dist": { 42 | "shasum": "ef5af4bf63fee968e4dc040692c558a8fb4429f6" 43 | }, 44 | "_from": "hashish@*", 45 | "_resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz" 46 | } 47 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/test/hash.js: -------------------------------------------------------------------------------- 1 | var Hash = require('hashish'); 2 | var assert = require('assert'); 3 | 4 | exports.map = function () { 5 | var ref = { a : 1, b : 2 }; 6 | var items = Hash(ref).map(function (v) { return v + 1 }).items; 7 | var hash = Hash.map(ref, function (v) { return v + 1 }); 8 | assert.deepEqual(ref, { a : 1, b : 2 }); 9 | assert.deepEqual(items, { a : 2, b : 3 }); 10 | assert.deepEqual(hash, { a : 2, b : 3 }); 11 | }; 12 | 13 | exports['cloned map'] = function () { 14 | var ref = { foo : [1,2], bar : [4,5] }; 15 | var hash = Hash(ref).clone.map( 16 | function (v) { v.unshift(v[0] - 1); return v } 17 | ).items; 18 | assert.deepEqual(ref.foo, [1,2]); 19 | assert.deepEqual(ref.bar, [4,5]); 20 | assert.deepEqual(hash.foo, [0,1,2]); 21 | assert.deepEqual(hash.bar, [3,4,5]); 22 | }; 23 | 24 | exports.forEach = function () { 25 | var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' }; 26 | var xs = []; 27 | Hash(ref).forEach(function (x, i) { 28 | xs.push([ i, x ]); 29 | }); 30 | 31 | assert.eql( 32 | xs.map(function (x) { return x[0] }).sort(), 33 | [ '1337', 'a', 'b', 'c' ] 34 | ); 35 | 36 | assert.eql( 37 | xs.map(function (x) { return x[1] }).sort(), 38 | [ 2, 5, 7, 'leet' ] 39 | ); 40 | 41 | var ys = []; 42 | Hash.forEach(ref, function (x, i) { 43 | ys.push([ i, x ]); 44 | }); 45 | 46 | assert.eql(xs.sort(), ys.sort()); 47 | }; 48 | 49 | exports.filter_items = function () { 50 | var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' }; 51 | var items = Hash(ref).filter(function (v, k) { 52 | return v > 5 || k > 5 53 | }).items; 54 | var hash = Hash.filter(ref, function (v, k) { return v > 5 || k > 5 }); 55 | assert.deepEqual(items, { 1337 : 'leet', c : 7 }); 56 | assert.deepEqual(hash, { 1337 : 'leet', c : 7 }); 57 | assert.deepEqual(ref, { a : 5, b : 2, c : 7, 1337 : 'leet' }); 58 | assert.equal(Hash(ref).length, 4); 59 | }; 60 | 61 | exports.detect = function () { 62 | var h = { a : 5, b : 6, c : 7, d : 8 }; 63 | var hh = Hash(h); 64 | var gt6hh = hh.detect(function (x) { return x > 6 }); 65 | assert.ok(gt6hh == 7 || gt6hh == 8); 66 | var gt6h = Hash.detect(h, function (x) { return x > 6 }); 67 | assert.ok(gt6h == 7 || gt6h == 8); 68 | assert.equal(hh.detect(function (x) { return x > 100 }), undefined); 69 | }; 70 | 71 | exports.reduce = function () { 72 | var ref = { foo : [1,2], bar : [4,5] }; 73 | 74 | var sum1 = Hash(ref).reduce(function (acc, v) { 75 | return acc + v.length 76 | }, 0); 77 | assert.equal(sum1, 4); 78 | 79 | var sum2 = Hash.reduce(ref, function (acc, v) { 80 | return acc + v.length 81 | }, 0); 82 | assert.equal(sum2, 4); 83 | }; 84 | 85 | exports.some = function () { 86 | var h = { a : 5, b : 6, c : 7, d : 8 }; 87 | var hh = Hash(h); 88 | assert.ok(Hash.some(h, function (x) { return x > 7 })); 89 | assert.ok(Hash.some(h, function (x) { return x < 6 })); 90 | assert.ok(!Hash.some(h, function (x) { return x > 10 })); 91 | assert.ok(!Hash.some(h, function (x) { return x < 0 })); 92 | 93 | assert.ok(hh.some(function (x) { return x > 7 })); 94 | assert.ok(hh.some(function (x) { return x < 6 })); 95 | assert.ok(!hh.some(function (x) { return x > 10 })); 96 | assert.ok(!hh.some(function (x) { return x < 0 })); 97 | }; 98 | 99 | exports.update = function () { 100 | var ref = { a : 1, b : 2 }; 101 | var items = Hash(ref).clone.update({ c : 3, a : 0 }).items; 102 | assert.deepEqual(ref, { a : 1, b : 2 }); 103 | assert.deepEqual(items, { a : 0, b : 2, c : 3 }); 104 | 105 | var hash = Hash.update(ref, { c : 3, a : 0 }); 106 | assert.deepEqual(ref, hash); 107 | assert.deepEqual(hash, { a : 0, b : 2, c : 3 }); 108 | 109 | var ref2 = {a: 1}; 110 | var hash2 = Hash.update(ref2, { b: 2, c: 3 }, undefined, { d: 4 }); 111 | assert.deepEqual(ref2, { a: 1, b: 2, c: 3, d: 4 }); 112 | }; 113 | 114 | exports.merge = function () { 115 | var ref = { a : 1, b : 2 }; 116 | var items = Hash(ref).merge({ b : 3, c : 3.14 }).items; 117 | var hash = Hash.merge(ref, { b : 3, c : 3.14 }); 118 | 119 | assert.deepEqual(ref, { a : 1, b : 2 }); 120 | assert.deepEqual(items, { a : 1, b : 3, c : 3.14 }); 121 | assert.deepEqual(hash, { a : 1, b : 3, c : 3.14 }); 122 | 123 | var ref2 = { a : 1 }; 124 | var hash2 = Hash.merge(ref, { b: 2, c: 3 }, undefined, { d: 4 }); 125 | assert.deepEqual(hash2, { a: 1, b: 2, c: 3, d: 4 }); 126 | }; 127 | 128 | exports.has = function () { 129 | var h = { a : 4, b : 5 }; 130 | var hh = Hash(h); 131 | 132 | assert.ok(hh.has('a')); 133 | assert.equal(hh.has('c'), false); 134 | assert.ok(hh.has(['a','b'])); 135 | assert.equal(hh.has(['a','b','c']), false); 136 | 137 | assert.ok(Hash.has(h, 'a')); 138 | assert.equal(Hash.has(h, 'c'), false); 139 | assert.ok(Hash.has(h, ['a','b'])); 140 | assert.equal(Hash.has(h, ['a','b','c']), false); 141 | }; 142 | 143 | exports.valuesAt = function () { 144 | var h = { a : 4, b : 5, c : 6 }; 145 | assert.equal(Hash(h).valuesAt('a'), 4); 146 | assert.equal(Hash(h).valuesAt(['a'])[0], 4); 147 | assert.deepEqual(Hash(h).valuesAt(['a','b']), [4,5]); 148 | assert.equal(Hash.valuesAt(h, 'a'), 4); 149 | assert.deepEqual(Hash.valuesAt(h, ['a']), [4]); 150 | assert.deepEqual(Hash.valuesAt(h, ['a','b']), [4,5]); 151 | }; 152 | 153 | exports.tap = function () { 154 | var h = { a : 4, b : 5, c : 6 }; 155 | var hh = Hash(h); 156 | hh.tap(function (x) { 157 | assert.ok(this === hh) 158 | assert.eql(x, h); 159 | }); 160 | 161 | Hash.tap(h, function (x) { 162 | assert.eql( 163 | Object.keys(this).sort(), 164 | Object.keys(hh).sort() 165 | ); 166 | assert.eql(x, h); 167 | }); 168 | }; 169 | 170 | exports.extract = function () { 171 | var hash = Hash({ a : 1, b : 2, c : 3 }).clone; 172 | var extracted = hash.extract(['a','b']); 173 | assert.equal(extracted.length, 2); 174 | assert.deepEqual(extracted.items, { a : 1, b : 2 }); 175 | }; 176 | 177 | exports.exclude = function () { 178 | var hash = Hash({ a : 1, b : 2, c : 3 }).clone; 179 | var extracted = hash.exclude(['a','b']); 180 | assert.equal(extracted.length, 1); 181 | assert.deepEqual(extracted.items, { c : 3 }); 182 | }; 183 | 184 | exports.concat = function () { 185 | var ref1 = { a : 1, b : 2 }; 186 | var ref2 = { foo : 100, bar : 200 }; 187 | var ref3 = { b : 3, c : 4, bar : 300 }; 188 | 189 | assert.deepEqual( 190 | Hash.concat([ ref1, ref2 ]), 191 | { a : 1, b : 2, foo : 100, bar : 200 } 192 | ); 193 | 194 | assert.deepEqual( 195 | Hash.concat([ ref1, ref2, ref3 ]), 196 | { a : 1, b : 3, c : 4, foo : 100, bar : 300 } 197 | ); 198 | }; 199 | 200 | exports.zip = function () { 201 | var xs = ['a','b','c']; 202 | var ys = [1,2,3,4]; 203 | var h = Hash(xs,ys); 204 | assert.equal(h.length, 3); 205 | assert.deepEqual(h.items, { a : 1, b : 2, c : 3 }); 206 | 207 | var zipped = Hash.zip(xs,ys); 208 | assert.deepEqual(zipped, { a : 1, b : 2, c : 3 }); 209 | }; 210 | 211 | exports.length = function () { 212 | assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).length, 3); 213 | assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).size, 3); 214 | assert.equal(Hash.size({ a : 1, b : [2,3], c : 4 }), 3); 215 | }; 216 | 217 | exports.compact = function () { 218 | var hash = { 219 | a : 1, 220 | b : undefined, 221 | c : false, 222 | d : 4, 223 | e : [ undefined, 4 ], 224 | f : null 225 | }; 226 | var compacted = Hash(hash).compact; 227 | assert.deepEqual( 228 | { 229 | a : 1, 230 | b : undefined, 231 | c : false, 232 | d : 4, 233 | e : [ undefined, 4 ], 234 | f : null 235 | }, 236 | hash, 'compact modified the hash' 237 | ); 238 | assert.deepEqual( 239 | compacted.items, 240 | { 241 | a : 1, 242 | c : false, 243 | d : 4, 244 | e : [ undefined, 4 ], 245 | f : null 246 | } 247 | ); 248 | var h = Hash.compact(hash); 249 | assert.deepEqual(h, compacted.items); 250 | }; 251 | -------------------------------------------------------------------------------- /test/modules-checked-in/node_modules/hashish/test/property.js: -------------------------------------------------------------------------------- 1 | var Hash = require('hashish'); 2 | var assert = require('assert'); 3 | var vm = require('vm'); 4 | var fs = require('fs'); 5 | 6 | var src = fs.readFileSync(__dirname + '/../index.js', 'utf8'); 7 | 8 | exports.defineGetter = function () { 9 | var context = { 10 | module : { exports : {} }, 11 | Object : { 12 | keys : Object.keys, 13 | defineProperty : undefined, 14 | }, 15 | require : require, 16 | }; 17 | context.exports = context.module.exports; 18 | 19 | vm.runInNewContext('(function () {' + src + '})()', context); 20 | var Hash_ = context.module.exports; 21 | 22 | var times = 0; 23 | Hash_.__proto__.__proto__.__defineGetter__ = function () { 24 | times ++; 25 | return Object.__defineGetter__.apply(this, arguments); 26 | }; 27 | 28 | assert.equal(vm.runInNewContext('Object.defineProperty', context), null); 29 | 30 | assert.deepEqual( 31 | Hash_({ a : 1, b : 2, c : 3 }).values, 32 | [ 1, 2, 3 ] 33 | ); 34 | 35 | assert.ok(times > 5); 36 | }; 37 | 38 | exports.defineProperty = function () { 39 | var times = 0; 40 | var context = { 41 | module : { exports : {} }, 42 | Object : { 43 | keys : Object.keys, 44 | defineProperty : function (prop) { 45 | times ++; 46 | if (prop.get) throw new TypeError('engine does not support') 47 | assert.fail('should have asserted by now'); 48 | }, 49 | }, 50 | require : require 51 | }; 52 | context.exports = context.module.exports; 53 | 54 | vm.runInNewContext('(function () {' + src + '})()', context); 55 | var Hash_ = context.module.exports; 56 | 57 | Hash_.__proto__.__proto__.__defineGetter__ = function () { 58 | assert.fail('getter called when a perfectly good' 59 | + ' defineProperty was available' 60 | ); 61 | }; 62 | 63 | assert.deepEqual( 64 | Hash_({ a : 1, b : 2, c : 3 }).values, 65 | [ 1, 2, 3 ] 66 | ); 67 | 68 | assert.equal(times, 1); 69 | }; 70 | -------------------------------------------------------------------------------- /test/modules-checked-in/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "dependencies": { 10 | "hashish": "*" 11 | }, 12 | "engines": { 13 | "node": "~0.10.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/no-package-json/Gemfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/strongloop-buildpacks/f66c7048ae813c8174a3f2526b3762916aa9893a/test/no-package-json/Gemfile -------------------------------------------------------------------------------- /test/no-script-hooks/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/no-script-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": "~0.10.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/no-version/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/no-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/range-with-space/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/range-with-space/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": ">= 0.8.x" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/script-hooks/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/script-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": "~0.10.0" 11 | }, 12 | "scripts" : { 13 | "preinstall" : "echo preinstall hook message" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/stable-node/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/stable-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "dependencies": { 10 | "hashish": "*" 11 | }, 12 | "engines": { 13 | "node": "~0.10.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/unstable-version/README.md: -------------------------------------------------------------------------------- 1 | A fake README, to keep npm from polluting stderr. -------------------------------------------------------------------------------- /test/unstable-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-buildpack-test-app", 3 | "version": "0.0.1", 4 | "description": "node buildpack integration test app", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "http://github.com/example/example.git" 8 | }, 9 | "engines": { 10 | "node": ">0.11.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /vendor/README: -------------------------------------------------------------------------------- 1 | json: https://github.com/trentm/json 2 | node-semver: http://github.com/isaacs/node-semver 3 | -------------------------------------------------------------------------------- /vendor/jq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/strongloop/strongloop-buildpacks/f66c7048ae813c8174a3f2526b3762916aa9893a/vendor/jq -------------------------------------------------------------------------------- /vendor/shunit2/shunit2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # 8 | # shUnit2 -- Unit testing framework for Unix shell scripts. 9 | # http://code.google.com/p/shunit2/ 10 | # 11 | # Author: kate.ward@forestent.com (Kate Ward) 12 | # 13 | # shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is 14 | # based on the popular JUnit unit testing framework for Java. 15 | 16 | # return if shunit already loaded 17 | [ -n "${SHUNIT_VERSION:-}" ] && exit 0 18 | 19 | SHUNIT_VERSION='2.1.6' 20 | 21 | SHUNIT_TRUE=0 22 | SHUNIT_FALSE=1 23 | SHUNIT_ERROR=2 24 | 25 | # enable strict mode by default 26 | SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} 27 | 28 | _shunit_warn() { echo "shunit2:WARN $@" >&2; } 29 | _shunit_error() { echo "shunit2:ERROR $@" >&2; } 30 | _shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } 31 | 32 | # specific shell checks 33 | if [ -n "${ZSH_VERSION:-}" ]; then 34 | setopt |grep "^shwordsplit$" >/dev/null 35 | if [ $? -ne ${SHUNIT_TRUE} ]; then 36 | _shunit_fatal 'zsh shwordsplit option is required for proper operation' 37 | fi 38 | if [ -z "${SHUNIT_PARENT:-}" ]; then 39 | _shunit_fatal "zsh does not pass \$0 through properly. please declare \ 40 | \"SHUNIT_PARENT=\$0\" before calling shUnit2" 41 | fi 42 | fi 43 | 44 | # 45 | # constants 46 | # 47 | 48 | __SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' 49 | __SHUNIT_MODE_SOURCED='sourced' 50 | __SHUNIT_MODE_STANDALONE='standalone' 51 | __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} 52 | 53 | # set the constants readonly 54 | shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` 55 | echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ 56 | shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` 57 | for shunit_constant_ in ${shunit_constants_}; do 58 | shunit_ro_opts_='' 59 | case ${ZSH_VERSION:-} in 60 | '') ;; # this isn't zsh 61 | [123].*) ;; # early versions (1.x, 2.x, 3.x) 62 | *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally 63 | esac 64 | readonly ${shunit_ro_opts_} ${shunit_constant_} 65 | done 66 | unset shunit_constant_ shunit_constants_ shunit_ro_opts_ 67 | 68 | # variables 69 | __shunit_lineno='' # line number of executed test 70 | __shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode 71 | __shunit_reportGenerated=${SHUNIT_FALSE} # is report generated 72 | __shunit_script='' # filename of unittest script (standalone mode) 73 | __shunit_skip=${SHUNIT_FALSE} # is skipping enabled 74 | __shunit_suite='' # suite of tests to execute 75 | 76 | # counts of tests 77 | __shunit_testSuccess=${SHUNIT_TRUE} 78 | __shunit_testsTotal=0 79 | __shunit_testsPassed=0 80 | __shunit_testsFailed=0 81 | 82 | # counts of asserts 83 | __shunit_assertsTotal=0 84 | __shunit_assertsPassed=0 85 | __shunit_assertsFailed=0 86 | __shunit_assertsSkipped=0 87 | 88 | # macros 89 | _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' 90 | 91 | #----------------------------------------------------------------------------- 92 | # assert functions 93 | # 94 | 95 | # Assert that two values are equal to one another. 96 | # 97 | # Args: 98 | # message: string: failure message [optional] 99 | # expected: string: expected value 100 | # actual: string: actual value 101 | # Returns: 102 | # integer: success (TRUE/FALSE/ERROR constant) 103 | assertEquals() 104 | { 105 | ${_SHUNIT_LINENO_} 106 | if [ $# -lt 2 -o $# -gt 3 ]; then 107 | _shunit_error "assertEquals() requires two or three arguments; $# given" 108 | _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" 109 | return ${SHUNIT_ERROR} 110 | fi 111 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 112 | 113 | shunit_message_=${__shunit_lineno} 114 | if [ $# -eq 3 ]; then 115 | shunit_message_="${shunit_message_}$1" 116 | shift 117 | fi 118 | shunit_expected_=$1 119 | shunit_actual_=$2 120 | 121 | shunit_return=${SHUNIT_TRUE} 122 | if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then 123 | _shunit_assertPass 124 | else 125 | failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" 126 | shunit_return=${SHUNIT_FALSE} 127 | fi 128 | 129 | unset shunit_message_ shunit_expected_ shunit_actual_ 130 | return ${shunit_return} 131 | } 132 | _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' 133 | 134 | # Assert that two values are not equal to one another. 135 | # 136 | # Args: 137 | # message: string: failure message [optional] 138 | # expected: string: expected value 139 | # actual: string: actual value 140 | # Returns: 141 | # integer: success (TRUE/FALSE/ERROR constant) 142 | assertNotEquals() 143 | { 144 | ${_SHUNIT_LINENO_} 145 | if [ $# -lt 2 -o $# -gt 3 ]; then 146 | _shunit_error "assertNotEquals() requires two or three arguments; $# given" 147 | return ${SHUNIT_ERROR} 148 | fi 149 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 150 | 151 | shunit_message_=${__shunit_lineno} 152 | if [ $# -eq 3 ]; then 153 | shunit_message_="${shunit_message_}$1" 154 | shift 155 | fi 156 | shunit_expected_=$1 157 | shunit_actual_=$2 158 | 159 | shunit_return=${SHUNIT_TRUE} 160 | if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then 161 | _shunit_assertPass 162 | else 163 | failSame "${shunit_message_}" "$@" 164 | shunit_return=${SHUNIT_FALSE} 165 | fi 166 | 167 | unset shunit_message_ shunit_expected_ shunit_actual_ 168 | return ${shunit_return} 169 | } 170 | _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' 171 | 172 | # Assert that a value is null (i.e. an empty string) 173 | # 174 | # Args: 175 | # message: string: failure message [optional] 176 | # actual: string: actual value 177 | # Returns: 178 | # integer: success (TRUE/FALSE/ERROR constant) 179 | assertNull() 180 | { 181 | ${_SHUNIT_LINENO_} 182 | if [ $# -lt 1 -o $# -gt 2 ]; then 183 | _shunit_error "assertNull() requires one or two arguments; $# given" 184 | return ${SHUNIT_ERROR} 185 | fi 186 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 187 | 188 | shunit_message_=${__shunit_lineno} 189 | if [ $# -eq 2 ]; then 190 | shunit_message_="${shunit_message_}$1" 191 | shift 192 | fi 193 | assertTrue "${shunit_message_}" "[ -z '$1' ]" 194 | shunit_return=$? 195 | 196 | unset shunit_message_ 197 | return ${shunit_return} 198 | } 199 | _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' 200 | 201 | # Assert that a value is not null (i.e. a non-empty string) 202 | # 203 | # Args: 204 | # message: string: failure message [optional] 205 | # actual: string: actual value 206 | # Returns: 207 | # integer: success (TRUE/FALSE/ERROR constant) 208 | assertNotNull() 209 | { 210 | ${_SHUNIT_LINENO_} 211 | if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null 212 | _shunit_error "assertNotNull() requires one or two arguments; $# given" 213 | return ${SHUNIT_ERROR} 214 | fi 215 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 216 | 217 | shunit_message_=${__shunit_lineno} 218 | if [ $# -eq 2 ]; then 219 | shunit_message_="${shunit_message_}$1" 220 | shift 221 | fi 222 | shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` 223 | test -n "${shunit_actual_}" 224 | assertTrue "${shunit_message_}" $? 225 | shunit_return=$? 226 | 227 | unset shunit_actual_ shunit_message_ 228 | return ${shunit_return} 229 | } 230 | _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' 231 | 232 | # Assert that two values are the same (i.e. equal to one another). 233 | # 234 | # Args: 235 | # message: string: failure message [optional] 236 | # expected: string: expected value 237 | # actual: string: actual value 238 | # Returns: 239 | # integer: success (TRUE/FALSE/ERROR constant) 240 | assertSame() 241 | { 242 | ${_SHUNIT_LINENO_} 243 | if [ $# -lt 2 -o $# -gt 3 ]; then 244 | _shunit_error "assertSame() requires two or three arguments; $# given" 245 | return ${SHUNIT_ERROR} 246 | fi 247 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 248 | 249 | shunit_message_=${__shunit_lineno} 250 | if [ $# -eq 3 ]; then 251 | shunit_message_="${shunit_message_}$1" 252 | shift 253 | fi 254 | assertEquals "${shunit_message_}" "$1" "$2" 255 | shunit_return=$? 256 | 257 | unset shunit_message_ 258 | return ${shunit_return} 259 | } 260 | _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' 261 | 262 | # Assert that two values are not the same (i.e. not equal to one another). 263 | # 264 | # Args: 265 | # message: string: failure message [optional] 266 | # expected: string: expected value 267 | # actual: string: actual value 268 | # Returns: 269 | # integer: success (TRUE/FALSE/ERROR constant) 270 | assertNotSame() 271 | { 272 | ${_SHUNIT_LINENO_} 273 | if [ $# -lt 2 -o $# -gt 3 ]; then 274 | _shunit_error "assertNotSame() requires two or three arguments; $# given" 275 | return ${SHUNIT_ERROR} 276 | fi 277 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 278 | 279 | shunit_message_=${__shunit_lineno} 280 | if [ $# -eq 3 ]; then 281 | shunit_message_="${shunit_message_:-}$1" 282 | shift 283 | fi 284 | assertNotEquals "${shunit_message_}" "$1" "$2" 285 | shunit_return=$? 286 | 287 | unset shunit_message_ 288 | return ${shunit_return} 289 | } 290 | _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' 291 | 292 | # Assert that a value or shell test condition is true. 293 | # 294 | # In shell, a value of 0 is true and a non-zero value is false. Any integer 295 | # value passed can thereby be tested. 296 | # 297 | # Shell supports much more complicated tests though, and a means to support 298 | # them was needed. As such, this function tests that conditions are true or 299 | # false through evaluation rather than just looking for a true or false. 300 | # 301 | # The following test will succeed: 302 | # assertTrue 0 303 | # assertTrue "[ 34 -gt 23 ]" 304 | # The folloing test will fail with a message: 305 | # assertTrue 123 306 | # assertTrue "test failed" "[ -r '/non/existant/file' ]" 307 | # 308 | # Args: 309 | # message: string: failure message [optional] 310 | # condition: string: integer value or shell conditional statement 311 | # Returns: 312 | # integer: success (TRUE/FALSE/ERROR constant) 313 | assertTrue() 314 | { 315 | ${_SHUNIT_LINENO_} 316 | if [ $# -gt 2 ]; then 317 | _shunit_error "assertTrue() takes one two arguments; $# given" 318 | return ${SHUNIT_ERROR} 319 | fi 320 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 321 | 322 | shunit_message_=${__shunit_lineno} 323 | if [ $# -eq 2 ]; then 324 | shunit_message_="${shunit_message_}$1" 325 | shift 326 | fi 327 | shunit_condition_=$1 328 | 329 | # see if condition is an integer, i.e. a return value 330 | shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 331 | shunit_return=${SHUNIT_TRUE} 332 | if [ -z "${shunit_condition_}" ]; then 333 | # null condition 334 | shunit_return=${SHUNIT_FALSE} 335 | elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 336 | then 337 | # possible return value. treating 0 as true, and non-zero as false. 338 | [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} 339 | else 340 | # (hopefully) a condition 341 | ( eval ${shunit_condition_} ) >/dev/null 2>&1 342 | [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} 343 | fi 344 | 345 | # record the test 346 | if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 347 | _shunit_assertPass 348 | else 349 | _shunit_assertFail "${shunit_message_}" 350 | fi 351 | 352 | unset shunit_message_ shunit_condition_ shunit_match_ 353 | return ${shunit_return} 354 | } 355 | _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' 356 | 357 | # Assert that a value or shell test condition is false. 358 | # 359 | # In shell, a value of 0 is true and a non-zero value is false. Any integer 360 | # value passed can thereby be tested. 361 | # 362 | # Shell supports much more complicated tests though, and a means to support 363 | # them was needed. As such, this function tests that conditions are true or 364 | # false through evaluation rather than just looking for a true or false. 365 | # 366 | # The following test will succeed: 367 | # assertFalse 1 368 | # assertFalse "[ 'apples' = 'oranges' ]" 369 | # The folloing test will fail with a message: 370 | # assertFalse 0 371 | # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" 372 | # 373 | # Args: 374 | # message: string: failure message [optional] 375 | # condition: string: integer value or shell conditional statement 376 | # Returns: 377 | # integer: success (TRUE/FALSE/ERROR constant) 378 | assertFalse() 379 | { 380 | ${_SHUNIT_LINENO_} 381 | if [ $# -lt 1 -o $# -gt 2 ]; then 382 | _shunit_error "assertFalse() quires one or two arguments; $# given" 383 | return ${SHUNIT_ERROR} 384 | fi 385 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 386 | 387 | shunit_message_=${__shunit_lineno} 388 | if [ $# -eq 2 ]; then 389 | shunit_message_="${shunit_message_}$1" 390 | shift 391 | fi 392 | shunit_condition_=$1 393 | 394 | # see if condition is an integer, i.e. a return value 395 | shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 396 | shunit_return=${SHUNIT_TRUE} 397 | if [ -z "${shunit_condition_}" ]; then 398 | # null condition 399 | shunit_return=${SHUNIT_FALSE} 400 | elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 401 | then 402 | # possible return value. treating 0 as true, and non-zero as false. 403 | [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} 404 | else 405 | # (hopefully) a condition 406 | ( eval ${shunit_condition_} ) >/dev/null 2>&1 407 | [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} 408 | fi 409 | 410 | # record the test 411 | if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 412 | _shunit_assertPass 413 | else 414 | _shunit_assertFail "${shunit_message_}" 415 | fi 416 | 417 | unset shunit_message_ shunit_condition_ shunit_match_ 418 | return ${shunit_return} 419 | } 420 | _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' 421 | 422 | #----------------------------------------------------------------------------- 423 | # failure functions 424 | # 425 | 426 | # Records a test failure. 427 | # 428 | # Args: 429 | # message: string: failure message [optional] 430 | # Returns: 431 | # integer: success (TRUE/FALSE/ERROR constant) 432 | fail() 433 | { 434 | ${_SHUNIT_LINENO_} 435 | if [ $# -gt 1 ]; then 436 | _shunit_error "fail() requires zero or one arguments; $# given" 437 | return ${SHUNIT_ERROR} 438 | fi 439 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 440 | 441 | shunit_message_=${__shunit_lineno} 442 | if [ $# -eq 1 ]; then 443 | shunit_message_="${shunit_message_}$1" 444 | shift 445 | fi 446 | 447 | _shunit_assertFail "${shunit_message_}" 448 | 449 | unset shunit_message_ 450 | return ${SHUNIT_FALSE} 451 | } 452 | _FAIL_='eval fail --lineno "${LINENO:-}"' 453 | 454 | # Records a test failure, stating two values were not equal. 455 | # 456 | # Args: 457 | # message: string: failure message [optional] 458 | # expected: string: expected value 459 | # actual: string: actual value 460 | # Returns: 461 | # integer: success (TRUE/FALSE/ERROR constant) 462 | failNotEquals() 463 | { 464 | ${_SHUNIT_LINENO_} 465 | if [ $# -lt 2 -o $# -gt 3 ]; then 466 | _shunit_error "failNotEquals() requires one or two arguments; $# given" 467 | return ${SHUNIT_ERROR} 468 | fi 469 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 470 | 471 | shunit_message_=${__shunit_lineno} 472 | if [ $# -eq 3 ]; then 473 | shunit_message_="${shunit_message_}$1" 474 | shift 475 | fi 476 | shunit_expected_=$1 477 | shunit_actual_=$2 478 | 479 | _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" 480 | 481 | unset shunit_message_ shunit_expected_ shunit_actual_ 482 | return ${SHUNIT_FALSE} 483 | } 484 | _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' 485 | 486 | # Records a test failure, stating two values should have been the same. 487 | # 488 | # Args: 489 | # message: string: failure message [optional] 490 | # expected: string: expected value 491 | # actual: string: actual value 492 | # Returns: 493 | # integer: success (TRUE/FALSE/ERROR constant) 494 | failSame() 495 | { 496 | ${_SHUNIT_LINENO_} 497 | if [ $# -lt 2 -o $# -gt 3 ]; then 498 | _shunit_error "failSame() requires two or three arguments; $# given" 499 | return ${SHUNIT_ERROR} 500 | fi 501 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 502 | 503 | shunit_message_=${__shunit_lineno} 504 | if [ $# -eq 3 ]; then 505 | shunit_message_="${shunit_message_}$1" 506 | shift 507 | fi 508 | 509 | _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" 510 | 511 | unset shunit_message_ 512 | return ${SHUNIT_FALSE} 513 | } 514 | _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' 515 | 516 | # Records a test failure, stating two values were not equal. 517 | # 518 | # This is functionally equivalent to calling failNotEquals(). 519 | # 520 | # Args: 521 | # message: string: failure message [optional] 522 | # expected: string: expected value 523 | # actual: string: actual value 524 | # Returns: 525 | # integer: success (TRUE/FALSE/ERROR constant) 526 | failNotSame() 527 | { 528 | ${_SHUNIT_LINENO_} 529 | if [ $# -lt 2 -o $# -gt 3 ]; then 530 | _shunit_error "failNotEquals() requires one or two arguments; $# given" 531 | return ${SHUNIT_ERROR} 532 | fi 533 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 534 | 535 | shunit_message_=${__shunit_lineno} 536 | if [ $# -eq 3 ]; then 537 | shunit_message_="${shunit_message_}$1" 538 | shift 539 | fi 540 | failNotEquals "${shunit_message_}" "$1" "$2" 541 | shunit_return=$? 542 | 543 | unset shunit_message_ 544 | return ${shunit_return} 545 | } 546 | _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' 547 | 548 | #----------------------------------------------------------------------------- 549 | # skipping functions 550 | # 551 | 552 | # Force remaining assert and fail functions to be "skipped". 553 | # 554 | # This function forces the remaining assert and fail functions to be "skipped", 555 | # i.e. they will have no effect. Each function skipped will be recorded so that 556 | # the total of asserts and fails will not be altered. 557 | # 558 | # Args: 559 | # None 560 | startSkipping() 561 | { 562 | __shunit_skip=${SHUNIT_TRUE} 563 | } 564 | 565 | # Resume the normal recording behavior of assert and fail calls. 566 | # 567 | # Args: 568 | # None 569 | endSkipping() 570 | { 571 | __shunit_skip=${SHUNIT_FALSE} 572 | } 573 | 574 | # Returns the state of assert and fail call skipping. 575 | # 576 | # Args: 577 | # None 578 | # Returns: 579 | # boolean: (TRUE/FALSE constant) 580 | isSkipping() 581 | { 582 | return ${__shunit_skip} 583 | } 584 | 585 | #----------------------------------------------------------------------------- 586 | # suite functions 587 | # 588 | 589 | # Stub. This function should contains all unit test calls to be made. 590 | # 591 | # DEPRECATED (as of 2.1.0) 592 | # 593 | # This function can be optionally overridden by the user in their test suite. 594 | # 595 | # If this function exists, it will be called when shunit2 is sourced. If it 596 | # does not exist, shunit2 will search the parent script for all functions 597 | # beginning with the word 'test', and they will be added dynamically to the 598 | # test suite. 599 | # 600 | # This function should be overridden by the user in their unit test suite. 601 | # Note: see _shunit_mktempFunc() for actual implementation 602 | # 603 | # Args: 604 | # None 605 | #suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION 606 | 607 | # Adds a function name to the list of tests schedule for execution. 608 | # 609 | # This function should only be called from within the suite() function. 610 | # 611 | # Args: 612 | # function: string: name of a function to add to current unit test suite 613 | suite_addTest() 614 | { 615 | shunit_func_=${1:-} 616 | 617 | __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" 618 | __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` 619 | 620 | unset shunit_func_ 621 | } 622 | 623 | # Stub. This function will be called once before any tests are run. 624 | # 625 | # Common one-time environment preparation tasks shared by all tests can be 626 | # defined here. 627 | # 628 | # This function should be overridden by the user in their unit test suite. 629 | # Note: see _shunit_mktempFunc() for actual implementation 630 | # 631 | # Args: 632 | # None 633 | #oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION 634 | 635 | # Stub. This function will be called once after all tests are finished. 636 | # 637 | # Common one-time environment cleanup tasks shared by all tests can be defined 638 | # here. 639 | # 640 | # This function should be overridden by the user in their unit test suite. 641 | # Note: see _shunit_mktempFunc() for actual implementation 642 | # 643 | # Args: 644 | # None 645 | #oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 646 | 647 | # Stub. This function will be called before each test is run. 648 | # 649 | # Common environment preparation tasks shared by all tests can be defined here. 650 | # 651 | # This function should be overridden by the user in their unit test suite. 652 | # Note: see _shunit_mktempFunc() for actual implementation 653 | # 654 | # Args: 655 | # None 656 | #setUp() { :; } 657 | 658 | # Note: see _shunit_mktempFunc() for actual implementation 659 | # Stub. This function will be called after each test is run. 660 | # 661 | # Common environment cleanup tasks shared by all tests can be defined here. 662 | # 663 | # This function should be overridden by the user in their unit test suite. 664 | # Note: see _shunit_mktempFunc() for actual implementation 665 | # 666 | # Args: 667 | # None 668 | #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 669 | 670 | #------------------------------------------------------------------------------ 671 | # internal shUnit2 functions 672 | # 673 | 674 | # Create a temporary directory to store various run-time files in. 675 | # 676 | # This function is a cross-platform temporary directory creation tool. Not all 677 | # OSes have the mktemp function, so one is included here. 678 | # 679 | # Args: 680 | # None 681 | # Outputs: 682 | # string: the temporary directory that was created 683 | _shunit_mktempDir() 684 | { 685 | # try the standard mktemp function 686 | ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return 687 | 688 | # the standard mktemp didn't work. doing our own. 689 | if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then 690 | _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" 719 | #! /bin/sh 720 | exit ${SHUNIT_TRUE} 721 | EOF 722 | chmod +x "${_shunit_file_}" 723 | done 724 | 725 | unset _shunit_file_ 726 | } 727 | 728 | # Final cleanup function to leave things as we found them. 729 | # 730 | # Besides removing the temporary directory, this function is in charge of the 731 | # final exit code of the unit test. The exit code is based on how the script 732 | # was ended (e.g. normal exit, or via Ctrl-C). 733 | # 734 | # Args: 735 | # name: string: name of the trap called (specified when trap defined) 736 | _shunit_cleanup() 737 | { 738 | _shunit_name_=$1 739 | 740 | case ${_shunit_name_} in 741 | EXIT) _shunit_signal_=0 ;; 742 | INT) _shunit_signal_=2 ;; 743 | TERM) _shunit_signal_=15 ;; 744 | *) 745 | _shunit_warn "unrecognized trap value (${_shunit_name_})" 746 | _shunit_signal_=0 747 | ;; 748 | esac 749 | 750 | # do our work 751 | rm -fr "${__shunit_tmpDir}" 752 | 753 | # exit for all non-EXIT signals 754 | if [ ${_shunit_name_} != 'EXIT' ]; then 755 | _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" 756 | # disable EXIT trap 757 | trap 0 758 | # add 128 to signal and exit 759 | exit `expr ${_shunit_signal_} + 128` 760 | elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then 761 | _shunit_assertFail 'Unknown failure encountered running a test' 762 | _shunit_generateReport 763 | exit ${SHUNIT_ERROR} 764 | fi 765 | 766 | unset _shunit_name_ _shunit_signal_ 767 | } 768 | 769 | # The actual running of the tests happens here. 770 | # 771 | # Args: 772 | # None 773 | _shunit_execSuite() 774 | { 775 | for _shunit_test_ in ${__shunit_suite}; do 776 | __shunit_testSuccess=${SHUNIT_TRUE} 777 | 778 | # disable skipping 779 | endSkipping 780 | 781 | # execute the per-test setup function 782 | setUp 783 | 784 | # execute the test 785 | echo "${_shunit_test_}" 786 | eval ${_shunit_test_} 787 | 788 | # execute the per-test tear-down function 789 | tearDown 790 | 791 | # update stats 792 | if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then 793 | __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` 794 | else 795 | __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` 796 | fi 797 | done 798 | 799 | unset _shunit_test_ 800 | } 801 | 802 | # Generates the user friendly report with appropriate OK/FAILED message. 803 | # 804 | # Args: 805 | # None 806 | # Output: 807 | # string: the report of successful and failed tests, as well as totals. 808 | _shunit_generateReport() 809 | { 810 | _shunit_ok_=${SHUNIT_TRUE} 811 | 812 | # if no exit code was provided one, determine an appropriate one 813 | [ ${__shunit_testsFailed} -gt 0 \ 814 | -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ 815 | && _shunit_ok_=${SHUNIT_FALSE} 816 | 817 | echo 818 | if [ ${__shunit_testsTotal} -eq 1 ]; then 819 | echo "Ran ${__shunit_testsTotal} test." 820 | else 821 | echo "Ran ${__shunit_testsTotal} tests." 822 | fi 823 | 824 | _shunit_failures_='' 825 | _shunit_skipped_='' 826 | [ ${__shunit_assertsFailed} -gt 0 ] \ 827 | && _shunit_failures_="failures=${__shunit_assertsFailed}" 828 | [ ${__shunit_assertsSkipped} -gt 0 ] \ 829 | && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" 830 | 831 | if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then 832 | _shunit_msg_='OK' 833 | [ -n "${_shunit_skipped_}" ] \ 834 | && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" 835 | else 836 | _shunit_msg_="FAILED (${_shunit_failures_}" 837 | [ -n "${_shunit_skipped_}" ] \ 838 | && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" 839 | _shunit_msg_="${_shunit_msg_})" 840 | fi 841 | 842 | echo 843 | echo ${_shunit_msg_} 844 | __shunit_reportGenerated=${SHUNIT_TRUE} 845 | 846 | unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ 847 | } 848 | 849 | # Test for whether a function should be skipped. 850 | # 851 | # Args: 852 | # None 853 | # Returns: 854 | # boolean: whether the test should be skipped (TRUE/FALSE constant) 855 | _shunit_shouldSkip() 856 | { 857 | [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} 858 | _shunit_assertSkip 859 | } 860 | 861 | # Records a successful test. 862 | # 863 | # Args: 864 | # None 865 | _shunit_assertPass() 866 | { 867 | __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` 868 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 869 | } 870 | 871 | # Records a test failure. 872 | # 873 | # Args: 874 | # message: string: failure message to provide user 875 | _shunit_assertFail() 876 | { 877 | _shunit_msg_=$1 878 | 879 | __shunit_testSuccess=${SHUNIT_FALSE} 880 | __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` 881 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 882 | echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" 883 | 884 | unset _shunit_msg_ 885 | } 886 | 887 | # Records a skipped test. 888 | # 889 | # Args: 890 | # None 891 | _shunit_assertSkip() 892 | { 893 | __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` 894 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 895 | } 896 | 897 | # Prepare a script filename for sourcing. 898 | # 899 | # Args: 900 | # script: string: path to a script to source 901 | # Returns: 902 | # string: filename prefixed with ./ (if necessary) 903 | _shunit_prepForSourcing() 904 | { 905 | _shunit_script_=$1 906 | case "${_shunit_script_}" in 907 | /*|./*) echo "${_shunit_script_}" ;; 908 | *) echo "./${_shunit_script_}" ;; 909 | esac 910 | unset _shunit_script_ 911 | } 912 | 913 | # Escape a character in a string. 914 | # 915 | # Args: 916 | # c: string: unescaped character 917 | # s: string: to escape character in 918 | # Returns: 919 | # string: with escaped character(s) 920 | _shunit_escapeCharInStr() 921 | { 922 | [ -n "$2" ] || return # no point in doing work on an empty string 923 | 924 | # Note: using shorter variable names to prevent conflicts with 925 | # _shunit_escapeCharactersInString(). 926 | _shunit_c_=$1 927 | _shunit_s_=$2 928 | 929 | 930 | # escape the character 931 | echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' 932 | 933 | unset _shunit_c_ _shunit_s_ 934 | } 935 | 936 | # Escape a character in a string. 937 | # 938 | # Args: 939 | # str: string: to escape characters in 940 | # Returns: 941 | # string: with escaped character(s) 942 | _shunit_escapeCharactersInString() 943 | { 944 | [ -n "$1" ] || return # no point in doing work on an empty string 945 | 946 | _shunit_str_=$1 947 | 948 | # Note: using longer variable names to prevent conflicts with 949 | # _shunit_escapeCharInStr(). 950 | for _shunit_char_ in '"' '$' "'" '`'; do 951 | _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` 952 | done 953 | 954 | echo "${_shunit_str_}" 955 | unset _shunit_char_ _shunit_str_ 956 | } 957 | 958 | # Extract list of functions to run tests against. 959 | # 960 | # Args: 961 | # script: string: name of script to extract functions from 962 | # Returns: 963 | # string: of function names 964 | _shunit_extractTestFunctions() 965 | { 966 | _shunit_script_=$1 967 | 968 | # extract the lines with test function names, strip of anything besides the 969 | # function name, and output everything on a single line. 970 | _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' 971 | egrep "${_shunit_regex_}" "${_shunit_script_}" \ 972 | |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ 973 | |xargs 974 | 975 | unset _shunit_regex_ _shunit_script_ 976 | } 977 | 978 | #------------------------------------------------------------------------------ 979 | # main 980 | # 981 | 982 | # determine the operating mode 983 | if [ $# -eq 0 ]; then 984 | __shunit_script=${__SHUNIT_PARENT} 985 | __shunit_mode=${__SHUNIT_MODE_SOURCED} 986 | else 987 | __shunit_script=$1 988 | [ -r "${__shunit_script}" ] || \ 989 | _shunit_fatal "unable to read from ${__shunit_script}" 990 | __shunit_mode=${__SHUNIT_MODE_STANDALONE} 991 | fi 992 | 993 | # create a temporary storage location 994 | __shunit_tmpDir=`_shunit_mktempDir` 995 | 996 | # provide a public temporary directory for unit test scripts 997 | # TODO(kward): document this 998 | SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" 999 | mkdir "${SHUNIT_TMPDIR}" 1000 | 1001 | # setup traps to clean up after ourselves 1002 | trap '_shunit_cleanup EXIT' 0 1003 | trap '_shunit_cleanup INT' 2 1004 | trap '_shunit_cleanup TERM' 15 1005 | 1006 | # create phantom functions to work around issues with Cygwin 1007 | _shunit_mktempFunc 1008 | PATH="${__shunit_tmpDir}:${PATH}" 1009 | 1010 | # make sure phantom functions are executable. this will bite if /tmp (or the 1011 | # current $TMPDIR) points to a path on a partition that was mounted with the 1012 | # 'noexec' option. the noexec command was created with _shunit_mktempFunc(). 1013 | noexec 2>/dev/null || _shunit_fatal \ 1014 | 'please declare TMPDIR with path on partition with exec permission' 1015 | 1016 | # we must manually source the tests in standalone mode 1017 | if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then 1018 | . "`_shunit_prepForSourcing \"${__shunit_script}\"`" 1019 | fi 1020 | 1021 | # execute the oneTimeSetUp function (if it exists) 1022 | oneTimeSetUp 1023 | 1024 | # execute the suite function defined in the parent test script 1025 | # deprecated as of 2.1.0 1026 | suite 1027 | 1028 | # if no suite function was defined, dynamically build a list of functions 1029 | if [ -z "${__shunit_suite}" ]; then 1030 | shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` 1031 | for shunit_func_ in ${shunit_funcs_}; do 1032 | suite_addTest ${shunit_func_} 1033 | done 1034 | fi 1035 | unset shunit_func_ shunit_funcs_ 1036 | 1037 | # execute the tests 1038 | _shunit_execSuite 1039 | 1040 | # execute the oneTimeTearDown function (if it exists) 1041 | oneTimeTearDown 1042 | 1043 | # generate the report 1044 | _shunit_generateReport 1045 | 1046 | # that's it folks 1047 | [ ${__shunit_testsFailed} -eq 0 ] 1048 | exit $? 1049 | -------------------------------------------------------------------------------- /vendor/test-utils/test-utils: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # taken from 4 | # https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh 5 | 6 | oneTimeSetUp() 7 | { 8 | TEST_SUITE_CACHE="$(mktemp -d ${SHUNIT_TMPDIR}/test_suite_cache.XXXX)" 9 | } 10 | 11 | oneTimeTearDown() 12 | { 13 | rm -rf ${TEST_SUITE_CACHE} 14 | } 15 | 16 | setUp() 17 | { 18 | OUTPUT_DIR="$(mktemp -d ${SHUNIT_TMPDIR}/output.XXXX)" 19 | STD_OUT="${OUTPUT_DIR}/stdout" 20 | STD_ERR="${OUTPUT_DIR}/stderr" 21 | BUILD_DIR="${OUTPUT_DIR}/build" 22 | CACHE_DIR="${OUTPUT_DIR}/cache" 23 | mkdir -p ${OUTPUT_DIR} 24 | mkdir -p ${BUILD_DIR} 25 | mkdir -p ${CACHE_DIR} 26 | } 27 | 28 | tearDown() 29 | { 30 | rm -rf ${OUTPUT_DIR} 31 | } 32 | 33 | capture() 34 | { 35 | resetCapture 36 | 37 | LAST_COMMAND="$@" 38 | 39 | $@ >${STD_OUT} 2>${STD_ERR} 40 | RETURN=$? 41 | rtrn=${RETURN} # deprecated 42 | } 43 | 44 | resetCapture() 45 | { 46 | if [ -f ${STD_OUT} ]; then 47 | rm ${STD_OUT} 48 | fi 49 | 50 | if [ -f ${STD_ERR} ]; then 51 | rm ${STD_ERR} 52 | fi 53 | 54 | unset LAST_COMMAND 55 | unset RETURN 56 | unset rtrn # deprecated 57 | } 58 | 59 | detect() 60 | { 61 | capture ${BUILDPACK_HOME}/bin/detect ${BUILD_DIR} 62 | } 63 | 64 | compile() 65 | { 66 | capture ${BUILDPACK_HOME}/bin/compile ${BUILD_DIR} ${CACHE_DIR} 67 | } 68 | 69 | release() 70 | { 71 | capture ${BUILDPACK_HOME}/bin/release ${BUILD_DIR} 72 | } 73 | 74 | assertCapturedEquals() 75 | { 76 | assertEquals "$@" "$(cat ${STD_OUT})" 77 | } 78 | 79 | assertCapturedNotEquals() 80 | { 81 | assertNotEquals "$@" "$(cat ${STD_OUT})" 82 | } 83 | 84 | assertCaptured() 85 | { 86 | assertFileContains "$@" "${STD_OUT}" 87 | } 88 | 89 | assertNotCaptured() 90 | { 91 | assertFileNotContains "$@" "${STD_OUT}" 92 | } 93 | 94 | assertCapturedSuccess() 95 | { 96 | assertEquals "Expected captured exit code to be 0; was <${RETURN}>" "0" "${RETURN}" 97 | assertEquals "Expected STD_ERR to be empty; was <$(cat ${STD_ERR})>" "" "$(cat ${STD_ERR})" 98 | } 99 | 100 | # assertCapturedError [[expectedErrorCode] expectedErrorMsg] 101 | assertCapturedError() 102 | { 103 | if [ $# -gt 1 ]; then 104 | expectedErrorCode=${1} 105 | shift 106 | fi 107 | 108 | expectedErrorMsg=${1:-""} 109 | 110 | if [ -z ${expectedErrorCode} ]; then 111 | assertTrue "Expected captured exit code to be greater than 0; was <${RETURN}>" "[ ${RETURN} -gt 0 ]" 112 | else 113 | assertTrue "Expected captured exit code to be <${expectedErrorCode}>; was <${RETURN}>" "[ ${RETURN} -eq ${expectedErrorCode} ]" 114 | fi 115 | 116 | if [ "${expectedErrorMsg}" != "" ]; then 117 | assertFileContains "Expected STD_ERR to contain error <${expectedErrorMsg}>" "${expectedErrorMsg}" "${STD_ERR}" 118 | fi 119 | } 120 | 121 | _assertContains() 122 | { 123 | if [ 5 -eq $# ]; then 124 | msg=$1 125 | shift 126 | elif [ ! 4 -eq $# ]; then 127 | fail "Expected 4 or 5 parameters; Receieved $# parameters" 128 | fi 129 | 130 | needle=$1 131 | haystack=$2 132 | expectation=$3 133 | haystack_type=$4 134 | 135 | case "${haystack_type}" in 136 | "file") grep -q -F -e "${needle}" ${haystack} ;; 137 | "text") echo "${haystack}" | grep -q -F -e "${needle}" ;; 138 | esac 139 | 140 | if [ "${expectation}" != "$?" ]; then 141 | case "${expectation}" in 142 | 0) default_msg="Expected <${haystack}> to contain <${needle}>" ;; 143 | 1) default_msg="Did not expect <${haystack}> to contain <${needle}>" ;; 144 | esac 145 | 146 | fail "${msg:-${default_msg}}" 147 | fi 148 | } 149 | 150 | assertContains() 151 | { 152 | _assertContains "$@" 0 "text" 153 | } 154 | 155 | assertNotContains() 156 | { 157 | _assertContains "$@" 1 "text" 158 | } 159 | 160 | assertFileContains() 161 | { 162 | _assertContains "$@" 0 "file" 163 | } 164 | 165 | assertFileNotContains() 166 | { 167 | _assertContains "$@" 1 "file" 168 | } 169 | 170 | command_exists () { 171 | type "$1" > /dev/null 2>&1 ; 172 | } 173 | 174 | assertFileMD5() 175 | { 176 | expectedHash=$1 177 | filename=$2 178 | 179 | if command_exists "md5sum"; then 180 | md5_cmd="md5sum ${filename}" 181 | expected_md5_cmd_output="${expectedHash} ${filename}" 182 | elif command_exists "md5"; then 183 | md5_cmd="md5 ${filename}" 184 | expected_md5_cmd_output="MD5 (${filename}) = ${expectedHash}" 185 | else 186 | fail "no suitable MD5 hashing command found on this system" 187 | fi 188 | 189 | assertEquals "${expected_md5_cmd_output}" "`${md5_cmd}`" 190 | } 191 | --------------------------------------------------------------------------------