#!/usr/bin/env bash
# See README.md for info on running these tests.

testDetectWithPackageJson() {
  detect "stable-node"
  assertCaptured "Node.js"
  assertCapturedSuccess
}

testDetectWithServer() {
  detect "server-present-only"
  assertCaptured "Node.js"
  assertCapturedSuccess
}

testDetectWithoutPackageJson() {
  detect "no-package-json"
  assertCapturedError 1 ""
}

testBadJson() {
  compile "bad-json"
  assertCaptured "Build failed"
  assertCaptured "We're sorry this build is failing"
  assertNotCaptured "build directory..."
  assertNotCaptured "Installing binaries"
  assertCapturedError 1 "Unable to parse"
}

testIoJs() {
  compile "iojs"
  assertCaptured "Node engine:         1.0."
  assertCaptured "(iojs)"
  assertCaptured "detected node version: v1.0."
  assertCapturedSuccess
}

testNoVersion() {
  compile "no-version"
  assertCaptured "Node engine:         unspecified"
  assertCaptured "WARNING: Node version not specified in package.json"
  assertCaptured "Resolving node version (latest stable) via semver.io"
  assertCaptured "Downloading and installing node 0.10"
  assertNotCaptured "We're sorry this build is failing"
  assertCapturedSuccess
}

testSpecificVersion() {
  compile "specific-version"
  assertNotCaptured "Resolving node version"
  assertCaptured "Downloading and installing node 0.10.29"
  assertCaptured "Using default npm version: 1.4.14"
  assertNotCaptured "We're sorry this build is failing"
  assertCapturedSuccess
}

testStableVersion() {
  compile "stable-node"
  assertCaptured "Downloading and installing node 0.10"
  assertNotCaptured "We're sorry this build is failing"
  assertCapturedSuccess
}

testUnstableVersion() {
  compile "unstable-version"
  assertCaptured "Resolving node version 0.11.x via semver.io"
  assertCaptured "Downloading and installing node 0.11"
  assertCapturedSuccess
}

testOldNpm() {
  compile "old-npm"
  assertCaptured "WARNING: This version of npm (1.2.8000) has several known issues - consider upgrading to the latest release (2."
  assertNotCaptured "integer expression expected"
  assertCapturedSuccess
}

testNonexistentNpm() {
  compile "nonexistent-npm"
  assertCaptured "version not found: npm@1.1.65"
  assertCapturedError 1 ""
}

testSameNpm() {
  compile "same-npm"
  assertCaptured "npm 1.4.28 already installed"
  assertCapturedSuccess
}

testNpmVersionRange() {
  compile "npm-version-range"
  assertCaptured "Resolving npm version"
  assertCaptured "installing npm 1.4."
  assertCapturedSuccess
}

testNpmVersionSpecific() {
  compile "npm-version-specific"
  assertCaptured "installing npm 2.1.11"
  assertNotCaptured "Resolving npm version"
  assertNotCaptured "WARNING"
  assertCapturedSuccess
}

testFailingBuild() {
  compile "failing-build"
  assertCaptured "Building dependencies"
  assertCaptured "Build failed"
  assertCaptured "We're sorry this build is failing"
  assertNotCaptured "Checking startup method"
  assertCapturedError 1 ""
}

testInfoEmpty() {
  compile "info-empty"
  assertCaptured "Node engine:         unspecified"
  assertCaptured "Npm engine:          unspecified"
  assertCaptured "Start mechanism:     none"
  assertCaptured "node_modules source: package.json"
  assertCaptured "node_modules cached: false"
  assertCapturedSuccess
}

testDangerousRangeStar() {
  compile "dangerous-range-star"
  assertCaptured "WARNING: Avoid semver ranges like '*'"
  assertCaptured "Node engine:         *"
  assertCaptured "Resolving node version * via semver.io"
  assertCaptured "Downloading and installing node 0.10"
  assertCapturedSuccess
}

testDangerousRangeGreaterThan() {
  compile "dangerous-range-greater-than"
  assertCaptured "WARNING: Avoid semver ranges starting with '>'"
  assertCaptured "Resolving node version >0.4 via semver.io"
  assertCaptured "Downloading and installing node 0.10"
  assertCapturedSuccess
}

testRangeWithSpace() {
  compile "range-with-space"
  assertCaptured "Resolving node version >= 0.8.x via semver.io"
  assertCaptured "Downloading and installing node 0.10"
  assertCapturedSuccess
}

testInvalidDependency() {
  compile "invalid-dependency"
  assertCaptured "npm ERR! 404"
  assertCapturedError 1 ""
}

testNodeModulesCached() {
  cache=$(mktmpdir)
  compile "caching" $cache
  assertCaptured "Caching results for future builds"
  assertEquals "1" "$(ls -1 $cache/ | grep node | wc -l)"
  assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l)"
}

testBuildWithCache() {
  cache=$(mktmpdir)
  compile "stable-node" $cache
  assertCaptured "node_modules cached: false"
  assertCaptured "Caching results for future builds"
  assertCapturedSuccess

  compile "stable-node" $cache
  assertCaptured "node_modules cached: true"
  assertCaptured "Restoring node modules from cache"
  assertCapturedSuccess
}

testModulesCheckedIn() {
  compile "modules-checked-in"
  assertCaptured "node_modules source: prebuilt"
  assertCaptured "Rebuilding any native modules for this architecture"
  assertCaptured "(preinstall script)"
  assertCaptured "Installing any new modules"
  assertCaptured "(postinstall script)"
  assertNotCaptured "Restoring node modules"
  assertNotCaptured "Pruning unused dependencies"
  assertCapturedSuccess
}

testUserConfig() {
  compile "userconfig"
  assertCaptured "www.google.com"
  assertCaptured "registry error"
  assertCapturedError 1 ""
}

testProcfile() {
  compile "procfile-present-only"
  assertCaptured "Start mechanism:     Procfile"
  assertNotCaptured "new Procfile"
  assertCapturedSuccess
}

testProcfileAbsentNpmStartPresent() {
  compile "procfile-absent-npm-start-present"
  assertCaptured "Start mechanism:     npm start"
  assertCaptured "Adding 'web: npm start' to new Procfile"
  assertFile "web: npm start" "Procfile"
  assertCapturedSuccess
}

testProcfileAbsentNpmStartAbsent() {
  compile "procfile-absent-npm-start-absent"
  assertCaptured "Start mechanism:     none"
  assertCaptured "None found"
  assertNotCaptured "new Procfile"
  assertCapturedSuccess
}

testDynamicProcfile() {
  compile "dynamic-procfile"
  assertCaptured "Procfile created during build"
  assertFileContains "web: node index.js customArg" "${compile_dir}/Procfile"
  assertCapturedSuccess
}

testProcfileAbsentServerPresent() {
  compile "procfile-absent-server-present"
  assertCaptured "Start mechanism:     server.js"
  assertCaptured "'web: node server.js' to new Procfile"
  assertFile "web: node server.js" "Procfile"
  assertCapturedSuccess
}

testServerPresentOnly() {
  compile "server-present-only"
  assertCaptured "WARNING: No package.json found"
  assertCaptured "Skipping dependencies"
  assertCaptured "'web: node server.js' to new Procfile"
  assertFile "web: node server.js" "Procfile"
  assertCapturedSuccess
}

testEnvVars() {
  env_dir=$(mktmpdir)
  echo "false" > $env_dir/NPM_CONFIG_PRODUCTION
  compile "stable-node" "$(mktmpdir)" $env_dir
  assertCaptured "NPM_CONFIG_PRODUCTION=false"
  assertCapturedSuccess
}

testNoEnvVars() {
  env_dir=$(mktmpdir)
  compile "stable-node" "$(mktmpdir)" $env_dir
  assertCaptured "NPM_CONFIG_PRODUCTION=true"
  assertCapturedSuccess
}

testNonFileEnvVars() {
  export NPM_CONFIG_FOO=bar
  export NPM_CONFIG_PRODUCTION=false
  compile "stable-node"
  assertCaptured "NPM_CONFIG_FOO=bar"
  assertCaptured "NPM_CONFIG_PRODUCTION=false"
  assertCapturedSuccess
  unset NPM_CONFIG_FOO
  unset NPM_CONFIG_PRODUCTION
}

testNoDevDependencies() {
  compile "dev-dependencies"
  assertNotCaptured "lodash"
  assertCapturedSuccess
}

testDevDependencies() {
  env_dir=$(mktmpdir)
  echo "false" > $env_dir/NPM_CONFIG_PRODUCTION
  compile "dev-dependencies" "$(mktmpdir)" $env_dir
  assertCaptured "lodash"
  assertCapturedSuccess
}

testOptionalDependencies() {
  env_dir=$(mktmpdir)
  #echo "true" > $env_dir/NPM_CONFIG_OPTIONAL
  compile "optional-dependencies" "$(mktmpdir)" $env_dir
  assertNotCaptured "NPM_CONFIG_OPTIONAL"
  assertCaptured "less"
  assertCaptured "mime"
  assertCaptured "mkdirp"
  assertCaptured "clean-css"
  assertCaptured "request"
  assertCapturedSuccess
}

testNoOptionalDependencies() {
  env_dir=$(mktmpdir)
  echo "false" > $env_dir/NPM_CONFIG_OPTIONAL
  compile "optional-dependencies" "$(mktmpdir)" $env_dir
  assertCaptured "NPM_CONFIG_OPTIONAL=false"
  assertCaptured "less"
  assertNotCaptured "mime"
  assertNotCaptured "mkdirp"
  assertNotCaptured "clean-css"
  assertNotCaptured "request"
  assertCapturedSuccess
}

testDisableCache() {
  cache=$(mktmpdir)
  env_dir=$(mktmpdir)

  compile "node-modules-cache-1" $cache
  assertCaptured "lodash@1.0.0"
  assertCapturedSuccess

  compile "node-modules-cache-2" $cache
  assertCaptured "lodash@1.0.0"
  assertCapturedSuccess

  echo "false" > $env_dir/NODE_MODULES_CACHE
  compile "node-modules-cache-2" $cache $env_dir
  assertCaptured "lodash@1.3.1"
  assertCapturedSuccess
}

testNpmrc() {
  compile "dev-dependencies"
  assertNotCaptured "lodash"
  assertCapturedSuccess

  compile "dev-dependencies-npmrc"
  assertCaptured "lodash"
  assertCapturedSuccess
}

testShrinkwrap() {
  compile "shrinkwrap"
  assertCaptured "express@4.10.4"
  assertCaptured "lodash@2.4.0"
  assertNotCaptured "mocha"
  assertCapturedSuccess
}

testProfileExport() {
  compile "stable-node"
  assertCaptured "Creating runtime environment"
  assertFileContains "export PATH=\"\$HOME/.heroku/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" "${compile_dir}/.profile.d/nodejs.sh"
  assertFileContains "export NODE_HOME=\"\$HOME/.heroku/node\"" "${compile_dir}/.profile.d/nodejs.sh"
  assertCapturedSuccess
}

testMultiExport() {
  compile "stable-node"
  assertFileContains "export PATH=" "${bp_dir}/export"
  assertFileContains "/.heroku/node/bin:" "${bp_dir}/export"
  assertFileContains "/node_modules/.bin:\$PATH" "${bp_dir}/export"
  assertFileContains "export NODE_HOME=" "${bp_dir}/export"
  assertFileContains "/.heroku/node\"" "${bp_dir}/export"
  assertCapturedSuccess
}

testConcurrency1X() {
  MEMORY_AVAILABLE=512 capture ${bp_dir}/lib/concurrency.sh
  assertCaptured "Detected 512 MB available memory, 512 MB limit per process (WEB_MEMORY)"
  assertCaptured "Recommending WEB_CONCURRENCY=1"
  assertCapturedSuccess
}

testConcurrency2X() {
  MEMORY_AVAILABLE=1024 capture ${bp_dir}/lib/concurrency.sh
  assertCaptured "Detected 1024 MB available memory, 512 MB limit per process (WEB_MEMORY)"
  assertCaptured "Recommending WEB_CONCURRENCY=2"
  assertCapturedSuccess
}

testConcurrencyPX() {
  MEMORY_AVAILABLE=6144 capture ${bp_dir}/lib/concurrency.sh
  assertCaptured "Detected 6144 MB available memory, 512 MB limit per process (WEB_MEMORY)"
  assertCaptured "Recommending WEB_CONCURRENCY=12"
  assertCapturedSuccess
}

testConcurrencyCustomLimit() {
  MEMORY_AVAILABLE=1024 WEB_MEMORY=256 capture ${bp_dir}/lib/concurrency.sh
  assertCaptured "Detected 1024 MB available memory, 256 MB limit per process (WEB_MEMORY)"
  assertCaptured "Recommending WEB_CONCURRENCY=4"
  assertCapturedSuccess
}

testConcurrencySaneMaximum() {
  MEMORY_AVAILABLE=6144 WEB_MEMORY=32 capture ${bp_dir}/lib/concurrency.sh
  assertCaptured "Detected 6144 MB available memory, 32 MB limit per process (WEB_MEMORY)"
  assertCaptured "Recommending WEB_CONCURRENCY=32"
  assertCapturedSuccess
}


# Utils

pushd $(dirname 0) >/dev/null
bp_dir=$(pwd)
popd >/dev/null

source ${bp_dir}/test/utils

mktmpdir() {
  dir=$(mktemp -t testXXXXX)
  rm -rf $dir
  mkdir $dir
  echo $dir
}

detect() {
  capture ${bp_dir}/bin/detect ${bp_dir}/test/fixtures/$1
}

compile_dir=""

compile() {
  compile_dir=$(mktmpdir)
  cp -r ${bp_dir}/test/fixtures/$1/. ${compile_dir}
  capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} $3
}

assertFile() {
  assertEquals "$1" "$(cat ${compile_dir}/$2)"
}

source ${bp_dir}/test/shunit2
