<commit_before>"use strict";
var ap = require('argparse').ArgumentParser
  , pkgObj = require('../../package.json')
  , path = require('path')
  , _ = require('underscore');

var args = [
  [['--shell'], {
    required: false
  , defaultValue: null
  , help: 'Enter REPL mode'
  , nargs: 0
  }],

  [['--localizable-strings-dir'], {
    required: false
  , dest: 'localizableStringsDir'
  , defaultValue: 'en.lproj'
  , help: 'IOS only: the relative path of the dir where Localizable.strings file resides '
  , example: "en.lproj"
  }],

  [['--app'], {
    required: false
  , defaultValue: null
  , help: 'IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file'
  , example: "/abs/path/to/my.app"
  }],

  [['--ipa'], {
    required: false
  , defaultValue: null
  , help: '(IOS-only) abs path to compiled .ipa file'
  , example: "/abs/path/to/my.ipa"
  }],

  [['-q', '--quiet'], {
    required: false
  , defaultValue: false
  , action: 'storeTrue'
  , help: "Don't use verbose logging output (deprecated, use --log-level instead)"
  , nargs: 0
  }],

  [['-U', '--udid'], {
    required: false
  , defaultValue: null
  , example: "1adsf-sdfas-asdf-123sdf"
  , help: 'Unique device identifier of the connected physical device'
  }],

  [['-a', '--address'], {
    defaultValue: '0.0.0.0'
  , required: false
  , example: "0.0.0.0"
  , help: 'IP Address to listen on'
  }],

  [['-p', '--port'], {
    defaultValue: 4723
  , required: false
  , type: 'int'
  , example: "4723"
  , help: 'port to listen on'
  }],

  [['-bp', '--bootstrap-port'], {
    defaultValue: 4724
  , dest: 'bootstrapPort'
  , required: false
  , type: 'int'
  , example: "4724"
  , help: '(Android-only) port to use on device to talk to Appium'
  }],

  [['-k', '--keep-artifacts'], {
    defaultValue: false
  , dest: 'keepArtifacts'
  , action: 'storeTrue'
  , required: false
  , help: '(IOS-only) Keep Instruments trace directories'
  , nargs: 0
  }],

  [['-r', '--backend-retries'], {
    defaultValue: 3
  , dest: 'backendRetries'
  , required: false
  , type: 'int'
  , example: "3"
  , help: '(iOS-only) How many times to retry launching Instruments ' +
          'before saying it crashed or timed out'
  }],

  [['--session-override'], {
    defaultValue: false
  , dest: 'sessionOverride'
  , action: 'storeTrue'
  , required: false
  , help: 'Enables session override (clobbering)'
  , nargs: 0
  }],

  [['--full-reset'], {
    defaultValue: false
  , dest: 'fullReset'
  , action: 'storeTrue'
  , required: false
  , help: '(iOS) Delete the entire simulator folder. (Android) Reset app ' +
          'state by uninstalling app instead of clearing app data. On ' +
          'Android, this will also remove the app after the session is complete.'
  , nargs: 0
  }],

  [['--no-reset'], {
    defaultValue: false
  , dest: 'noReset'
  , action: 'storeTrue'
  , required: false
  , help: "Don't reset app state between sessions (IOS: don't delete app " +
          "plist files; Android: don't uninstall app before new session)"
  , nargs: 0
  }],

  [['-l', '--pre-launch'], {
    defaultValue: false
  , dest: 'launch'
  , action: 'storeTrue'
  , required: false
  , help: 'Pre-launch the application before allowing the first session ' +
          '(Requires --app and, for Android, --app-pkg and --app-activity)'
  , nargs: 0
  }],

  [['-lt', '--launch-timeout'], {
    defaultValue: 90000
  , dest: 'launchTimeout'
  , required: false
  , help: '(iOS-only) how long in ms to wait for Instruments to launch'
  }],

  [['-g', '--log'], {
    defaultValue: null
  , required: false
  , example: "/path/to/appium.log"
  , help: 'Also send log output to this file'
  }],

  [['--log-level'], {
    choices: ['debug','info','warn', 'error']
  , dest: 'logLevel'
  , required: false
  , example: "debug"
  , help: 'log level (default: infozw)'
  }],

  [['--log-timestamp'], {
    defaultValue: false
  , required: false
  , help: 'Show timestamps in console output'
  , nargs: 0
  , action: 'storeTrue'
  , dest: 'logTimestamp'
  }],

  [['--log-no-colors'], {
    defaultValue: false
  , required: false
  , help: "Don't use colors in console output"
  , nargs: 0
  , action: 'storeTrue'
  , dest: 'logNoColors'
  }],

  [['-G', '--webhook'], {
    defaultValue: null
  , required: false
  , example: "localhost:9876"
  , help: 'Also send log output to this HTTP listener'
  }],

  [['--native-instruments-lib'], {
    defaultValue: false
  , dest: 'nativeInstrumentsLib'
  , action: 'storeTrue'
  , required: false
  , help: '(IOS-only) IOS has a weird built-in unavoidable ' +
          'delay. We patch this in appium. If you do not want it patched, ' +
          'pass in this flag.'
  , nargs: 0
  }],

  [['--force-quit-instruments', '-fqi'], {
    defaultValue: false
  , dest: 'forceQuitInstruments'
  , action: 'storeTrue'
  , required: false
  , help: "Run the watcher process that will force-kill an " +
          "unresponsive instruments"
  , nargs: 0
  }],

  [['--app-pkg'], {
    dest: 'androidPackage'
  , defaultValue: null
  , required: false
  , example: "com.example.android.myApp"
  , help: "(Android-only) Java package of the Android app you want to run " +
          "(e.g., com.example.android.myApp)"
  }],

  [['--app-activity'], {
    dest: 'androidActivity'
  , defaultValue: null
  , required: false
  , example: "MainActivity"
  , help: "(Android-only) Activity name for the Android activity you want " +
          "to launch from your package (e.g., MainActivity)"
  }],

  [['--app-wait-package'], {
    dest: 'androidWaitPackage'
  , defaultValue: false
  , required: false
  , example: "com.example.android.myApp"
  , help: "(Android-only) Package name for the Android activity you want " +
          "to wait for (e.g., com.example.android.myApp)"
  }],

  [['--app-wait-activity'], {
    dest: 'androidWaitActivity'
  , defaultValue: false
  , required: false
  , example: "SplashActivity"
  , help: "(Android-only) Activity name for the Android activity you want " +
          "to wait for (e.g., SplashActivity)"
  }],

  [['--android-coverage'], {
    dest: 'androidCoverage'
  , defaultValue: false
  , required: false
  , example: 'com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation'
  , help: "(Android-only) Fully qualified instrumentation class. Passed to -w in " +
      "adb shell am instrument -e coverage true -w "
  }],

  [['--avd'], {
    defaultValue: null
  , required: false
  , example: "@default"
  , help: "(Android-only) Name of the avd to launch"
  }],

  [['--avd-args'], {
    dest: 'avdArgs'
  , defaultValue: null
  , required: false
  , example: "-no-snapshot-load"
  , help: "(Android-only) Additional emulator arguments to launch the avd"
  }],

  [['--device-ready-timeout'], {
    dest: 'androidDeviceReadyTimeout'
  , defaultValue: '5'
  , required: false
  , example: "5"
  , help: "(Android-only) Timeout in seconds while waiting for device to become ready"
  }],

  [['--safari'], {
    defaultValue: false
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-Only) Use the safari app"
  , nargs: 0
  }],

  [['--device-name'], {
    dest: 'deviceName'
  , defaultValue: null
  , required: false
  , example: "iPhone Retina (4-inch), Android Emulator"
  , help: "Name of the mobile device to use"
  }],

  [['--platform-name'], {
    dest: 'platformName'
  , defaultValue: null
  , required: false
  , example: "iOS"
  , help: "Name of the mobile platform: iOS, Android, or FirefoxOS"
  }],

  [['--platform-version'], {
    dest: 'platformVersion'
  , defaultValue: null
  , required: false
  , example: "7.1"
  , help: "Version of the mobile platform"
  }],

  [['--automation-name'], {
    dest: 'automationName'
  , defaultValue: null
  , required: false
  , example: "Appium"
  , help: "Name of the automation tool: Appium or Selendroid"
  }],

  [['--browser-name'], {
    dest: 'browserName'
  , defaultValue: null
  , required: false
  , example: "Safari"
  , help: "Name of the mobile browser: Safari or Chrome"
  }],

  [['--default-device', '-dd'], {
    dest: 'defaultDevice'
  , defaultValue: false
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-Simulator-only) use the default simulator that instruments " +
          "launches on its own"
  }],

  [['--force-iphone'], {
    defaultValue: false
  , dest: 'forceIphone'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) Use the iPhone Simulator no matter what the app wants"
  , nargs: 0
  }],

  [['--force-ipad'], {
    defaultValue: false
  , dest: 'forceIpad'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) Use the iPad Simulator no matter what the app wants"
  , nargs: 0
  }],

  [['--language'], {
    defaultValue: null
  , dest: 'language'
  , required: false
  , example: "en"
  , help: 'Language for the iOS simulator / Android Emulator'
  }],

  [['--locale'], {
    defaultValue: null
  , dest: 'locale'
  , required: false
  , example: "en_US"
  , help: 'Locale for the iOS simulator / Android Emulator'
  }],

  [['--calendar-format'], {
    defaultValue: null
  , dest: 'calendarFormat'
  , required: false
  , example: "gregorian"
  , help: '(IOS-only) calendar format for the iOS simulator'
  }],

  [['--orientation'], {
    defaultValue: null
  , required: false
  , example: "LANDSCAPE"
  , help: "(IOS-only) use LANDSCAPE or PORTRAIT to initialize all requests " +
          "to this orientation"
  }],

  [['--tracetemplate'], {
    defaultValue: null
  , dest: 'automationTraceTemplatePath'
  , required: false
  , example: "/Users/me/Automation.tracetemplate"
  , help: "(IOS-only) .tracetemplate file to use with Instruments"
  }],

  [['--show-sim-log'], {
    defaultValue: false
  , dest: 'showSimulatorLog'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) if set, the iOS simulator log will be written to the console"
  , nargs: 0
  }],

  [['--nodeconfig'], {
    required: false
  , defaultValue: null
  , help: 'Configuration JSON file to register appium with selenium grid'
  , example: "/abs/path/to/nodeconfig.json"
  }],

  [['-ra', '--robot-address'], {
    defaultValue: '0.0.0.0'
  , dest: 'robotAddress'
  , required: false
  , example: "0.0.0.0"
  , help: 'IP Address of robot'
  }],

  [['-rp', '--robot-port'], {
    defaultValue: -1
  , dest: 'robotPort'
  , required: false
  , type: 'int'
  , example: "4242"
  , help: 'port for robot'
  }],

  [['--selendroid-port'], {
    defaultValue: 8080
  , dest: 'selendroidPort'
  , required: false
  , type: 'int'
  , example: "8080"
  , help: 'Local port used for communication with Selendroid'
  }],

  [['--chromedriver-port'], {
    defaultValue: 9515
  , dest: 'chromeDriverPort'
  , required: false
  , type: 'int'
  , example: '9515'
  , help: 'Port upon which ChromeDriver will run'
  }],

  [['--chromedriver-executable'], {
    defaultValue: null
  , dest: 'chromedriverExecutable'
  , required: false
  , help: 'ChromeDriver executable full path'
  }],

  [['--use-keystore'], {
    defaultValue: false
  , dest: 'useKeystore'
  , action: 'storeTrue'
  , required: false
  , help: '(Android-only) When set the keystore will be used to sign apks.'
  }],

  [['--keystore-path'], {
    defaultValue: path.resolve(process.env.HOME || process.env.USERPROFILE || '', '.android', 'debug.keystore')
  , dest: 'keystorePath'
  , required: false
  , help: '(Android-only) Path to keystore'
  }],

  [['--keystore-password'], {
    defaultValue: 'android'
  , dest: 'keystorePassword'
  , required: false
  , help: '(Android-only) Password to keystore'
  }],

  [['--key-alias'], {
    defaultValue: 'androiddebugkey'
  , dest: 'keyAlias'
  , required: false
  , help: '(Android-only) Key alias'
  }],

  [['--key-password'], {
    defaultValue: 'android'
  , dest: 'keyPassword'
  , required: false
  , help: '(Android-only) Key password'
  }],

  [['--show-config'], {
    defaultValue: false
  , dest: 'showConfig'
  , action: 'storeTrue'
  , required: false
  , help: 'Show info about the appium server configuration and exit'
  }],

  [['--command-timeout'], {
    defaultValue: 60
  , dest: 'defaultCommandTimeout'
  , type: 'int'
  , required: false
  , help: 'The default command timeout for the server to use for all ' +
          'sessions. Will still be overridden by newCommandTimeout cap'
  }],

  [['--keep-keychains'], {
    defaultValue: false
  , dest: 'keepKeyChains'
  , action: 'storeTrue'
  , required: false
  , help: "(iOS) Whether to keep keychains (Library/Keychains) when reset app between sessions"
  , nargs: 0
  }],

  [['--strict-caps'], {
    defaultValue: false
  , dest: 'enforceStrictCaps'
  , action: 'storeTrue'
  , required: false
  , help: "Cause sessions to fail if desired caps are sent in that Appium " +
          "does not recognize as valid for the selected device"
  , nargs: 0
  }],

  [['--tmp'], {
    defaultValue: null
  , dest: 'tmpDir'
  , required: false
  , help: 'Absolute path to directory Appium can use to manage temporary ' +
          'files, like built-in iOS apps it needs to move around. On *nix/Mac ' +
          'defaults to /tmp, on Windows defaults to C:\\Windows\\Temp'
  }]

];

// Setup all the command line argument parsing
module.exports = function () {
  var parser = new ap({
    version: pkgObj.version,
    addHelp: true,
    description: 'A webdriver-compatible server for use with native and hybrid iOS and Android applications.'
  });

  _.each(args, function (arg) {
    parser.addArgument(arg[0], arg[1]);
  });

  parser.rawArgs = args;

  return parser;
};
<commit_msg>Set most verbose log level as default<commit_after>"use strict";
var ap = require('argparse').ArgumentParser
  , pkgObj = require('../../package.json')
  , path = require('path')
  , _ = require('underscore');

var args = [
  [['--shell'], {
    required: false
  , defaultValue: null
  , help: 'Enter REPL mode'
  , nargs: 0
  }],

  [['--localizable-strings-dir'], {
    required: false
  , dest: 'localizableStringsDir'
  , defaultValue: 'en.lproj'
  , help: 'IOS only: the relative path of the dir where Localizable.strings file resides '
  , example: "en.lproj"
  }],

  [['--app'], {
    required: false
  , defaultValue: null
  , help: 'IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file'
  , example: "/abs/path/to/my.app"
  }],

  [['--ipa'], {
    required: false
  , defaultValue: null
  , help: '(IOS-only) abs path to compiled .ipa file'
  , example: "/abs/path/to/my.ipa"
  }],

  [['-q', '--quiet'], {
    required: false
  , defaultValue: false
  , action: 'storeTrue'
  , help: "Don't use verbose logging output (deprecated, use --log-level instead)"
  , nargs: 0
  }],

  [['-U', '--udid'], {
    required: false
  , defaultValue: null
  , example: "1adsf-sdfas-asdf-123sdf"
  , help: 'Unique device identifier of the connected physical device'
  }],

  [['-a', '--address'], {
    defaultValue: '0.0.0.0'
  , required: false
  , example: "0.0.0.0"
  , help: 'IP Address to listen on'
  }],

  [['-p', '--port'], {
    defaultValue: 4723
  , required: false
  , type: 'int'
  , example: "4723"
  , help: 'port to listen on'
  }],

  [['-bp', '--bootstrap-port'], {
    defaultValue: 4724
  , dest: 'bootstrapPort'
  , required: false
  , type: 'int'
  , example: "4724"
  , help: '(Android-only) port to use on device to talk to Appium'
  }],

  [['-k', '--keep-artifacts'], {
    defaultValue: false
  , dest: 'keepArtifacts'
  , action: 'storeTrue'
  , required: false
  , help: '(IOS-only) Keep Instruments trace directories'
  , nargs: 0
  }],

  [['-r', '--backend-retries'], {
    defaultValue: 3
  , dest: 'backendRetries'
  , required: false
  , type: 'int'
  , example: "3"
  , help: '(iOS-only) How many times to retry launching Instruments ' +
          'before saying it crashed or timed out'
  }],

  [['--session-override'], {
    defaultValue: false
  , dest: 'sessionOverride'
  , action: 'storeTrue'
  , required: false
  , help: 'Enables session override (clobbering)'
  , nargs: 0
  }],

  [['--full-reset'], {
    defaultValue: false
  , dest: 'fullReset'
  , action: 'storeTrue'
  , required: false
  , help: '(iOS) Delete the entire simulator folder. (Android) Reset app ' +
          'state by uninstalling app instead of clearing app data. On ' +
          'Android, this will also remove the app after the session is complete.'
  , nargs: 0
  }],

  [['--no-reset'], {
    defaultValue: false
  , dest: 'noReset'
  , action: 'storeTrue'
  , required: false
  , help: "Don't reset app state between sessions (IOS: don't delete app " +
          "plist files; Android: don't uninstall app before new session)"
  , nargs: 0
  }],

  [['-l', '--pre-launch'], {
    defaultValue: false
  , dest: 'launch'
  , action: 'storeTrue'
  , required: false
  , help: 'Pre-launch the application before allowing the first session ' +
          '(Requires --app and, for Android, --app-pkg and --app-activity)'
  , nargs: 0
  }],

  [['-lt', '--launch-timeout'], {
    defaultValue: 90000
  , dest: 'launchTimeout'
  , required: false
  , help: '(iOS-only) how long in ms to wait for Instruments to launch'
  }],

  [['-g', '--log'], {
    defaultValue: null
  , required: false
  , example: "/path/to/appium.log"
  , help: 'Also send log output to this file'
  }],

  [['--log-level'], {
    choices: ['debug','info','warn', 'error']
  , defaultValue: 'debug'
  , dest: 'logLevel'
  , required: false
  , example: "debug"
  , help: 'log level (default: infozw)'
  }],

  [['--log-timestamp'], {
    defaultValue: false
  , required: false
  , help: 'Show timestamps in console output'
  , nargs: 0
  , action: 'storeTrue'
  , dest: 'logTimestamp'
  }],

  [['--log-no-colors'], {
    defaultValue: false
  , required: false
  , help: "Don't use colors in console output"
  , nargs: 0
  , action: 'storeTrue'
  , dest: 'logNoColors'
  }],

  [['-G', '--webhook'], {
    defaultValue: null
  , required: false
  , example: "localhost:9876"
  , help: 'Also send log output to this HTTP listener'
  }],

  [['--native-instruments-lib'], {
    defaultValue: false
  , dest: 'nativeInstrumentsLib'
  , action: 'storeTrue'
  , required: false
  , help: '(IOS-only) IOS has a weird built-in unavoidable ' +
          'delay. We patch this in appium. If you do not want it patched, ' +
          'pass in this flag.'
  , nargs: 0
  }],

  [['--force-quit-instruments', '-fqi'], {
    defaultValue: false
  , dest: 'forceQuitInstruments'
  , action: 'storeTrue'
  , required: false
  , help: "Run the watcher process that will force-kill an " +
          "unresponsive instruments"
  , nargs: 0
  }],

  [['--app-pkg'], {
    dest: 'androidPackage'
  , defaultValue: null
  , required: false
  , example: "com.example.android.myApp"
  , help: "(Android-only) Java package of the Android app you want to run " +
          "(e.g., com.example.android.myApp)"
  }],

  [['--app-activity'], {
    dest: 'androidActivity'
  , defaultValue: null
  , required: false
  , example: "MainActivity"
  , help: "(Android-only) Activity name for the Android activity you want " +
          "to launch from your package (e.g., MainActivity)"
  }],

  [['--app-wait-package'], {
    dest: 'androidWaitPackage'
  , defaultValue: false
  , required: false
  , example: "com.example.android.myApp"
  , help: "(Android-only) Package name for the Android activity you want " +
          "to wait for (e.g., com.example.android.myApp)"
  }],

  [['--app-wait-activity'], {
    dest: 'androidWaitActivity'
  , defaultValue: false
  , required: false
  , example: "SplashActivity"
  , help: "(Android-only) Activity name for the Android activity you want " +
          "to wait for (e.g., SplashActivity)"
  }],

  [['--android-coverage'], {
    dest: 'androidCoverage'
  , defaultValue: false
  , required: false
  , example: 'com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation'
  , help: "(Android-only) Fully qualified instrumentation class. Passed to -w in " +
      "adb shell am instrument -e coverage true -w "
  }],

  [['--avd'], {
    defaultValue: null
  , required: false
  , example: "@default"
  , help: "(Android-only) Name of the avd to launch"
  }],

  [['--avd-args'], {
    dest: 'avdArgs'
  , defaultValue: null
  , required: false
  , example: "-no-snapshot-load"
  , help: "(Android-only) Additional emulator arguments to launch the avd"
  }],

  [['--device-ready-timeout'], {
    dest: 'androidDeviceReadyTimeout'
  , defaultValue: '5'
  , required: false
  , example: "5"
  , help: "(Android-only) Timeout in seconds while waiting for device to become ready"
  }],

  [['--safari'], {
    defaultValue: false
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-Only) Use the safari app"
  , nargs: 0
  }],

  [['--device-name'], {
    dest: 'deviceName'
  , defaultValue: null
  , required: false
  , example: "iPhone Retina (4-inch), Android Emulator"
  , help: "Name of the mobile device to use"
  }],

  [['--platform-name'], {
    dest: 'platformName'
  , defaultValue: null
  , required: false
  , example: "iOS"
  , help: "Name of the mobile platform: iOS, Android, or FirefoxOS"
  }],

  [['--platform-version'], {
    dest: 'platformVersion'
  , defaultValue: null
  , required: false
  , example: "7.1"
  , help: "Version of the mobile platform"
  }],

  [['--automation-name'], {
    dest: 'automationName'
  , defaultValue: null
  , required: false
  , example: "Appium"
  , help: "Name of the automation tool: Appium or Selendroid"
  }],

  [['--browser-name'], {
    dest: 'browserName'
  , defaultValue: null
  , required: false
  , example: "Safari"
  , help: "Name of the mobile browser: Safari or Chrome"
  }],

  [['--default-device', '-dd'], {
    dest: 'defaultDevice'
  , defaultValue: false
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-Simulator-only) use the default simulator that instruments " +
          "launches on its own"
  }],

  [['--force-iphone'], {
    defaultValue: false
  , dest: 'forceIphone'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) Use the iPhone Simulator no matter what the app wants"
  , nargs: 0
  }],

  [['--force-ipad'], {
    defaultValue: false
  , dest: 'forceIpad'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) Use the iPad Simulator no matter what the app wants"
  , nargs: 0
  }],

  [['--language'], {
    defaultValue: null
  , dest: 'language'
  , required: false
  , example: "en"
  , help: 'Language for the iOS simulator / Android Emulator'
  }],

  [['--locale'], {
    defaultValue: null
  , dest: 'locale'
  , required: false
  , example: "en_US"
  , help: 'Locale for the iOS simulator / Android Emulator'
  }],

  [['--calendar-format'], {
    defaultValue: null
  , dest: 'calendarFormat'
  , required: false
  , example: "gregorian"
  , help: '(IOS-only) calendar format for the iOS simulator'
  }],

  [['--orientation'], {
    defaultValue: null
  , required: false
  , example: "LANDSCAPE"
  , help: "(IOS-only) use LANDSCAPE or PORTRAIT to initialize all requests " +
          "to this orientation"
  }],

  [['--tracetemplate'], {
    defaultValue: null
  , dest: 'automationTraceTemplatePath'
  , required: false
  , example: "/Users/me/Automation.tracetemplate"
  , help: "(IOS-only) .tracetemplate file to use with Instruments"
  }],

  [['--show-sim-log'], {
    defaultValue: false
  , dest: 'showSimulatorLog'
  , action: 'storeTrue'
  , required: false
  , help: "(IOS-only) if set, the iOS simulator log will be written to the console"
  , nargs: 0
  }],

  [['--nodeconfig'], {
    required: false
  , defaultValue: null
  , help: 'Configuration JSON file to register appium with selenium grid'
  , example: "/abs/path/to/nodeconfig.json"
  }],

  [['-ra', '--robot-address'], {
    defaultValue: '0.0.0.0'
  , dest: 'robotAddress'
  , required: false
  , example: "0.0.0.0"
  , help: 'IP Address of robot'
  }],

  [['-rp', '--robot-port'], {
    defaultValue: -1
  , dest: 'robotPort'
  , required: false
  , type: 'int'
  , example: "4242"
  , help: 'port for robot'
  }],

  [['--selendroid-port'], {
    defaultValue: 8080
  , dest: 'selendroidPort'
  , required: false
  , type: 'int'
  , example: "8080"
  , help: 'Local port used for communication with Selendroid'
  }],

  [['--chromedriver-port'], {
    defaultValue: 9515
  , dest: 'chromeDriverPort'
  , required: false
  , type: 'int'
  , example: '9515'
  , help: 'Port upon which ChromeDriver will run'
  }],

  [['--chromedriver-executable'], {
    defaultValue: null
  , dest: 'chromedriverExecutable'
  , required: false
  , help: 'ChromeDriver executable full path'
  }],

  [['--use-keystore'], {
    defaultValue: false
  , dest: 'useKeystore'
  , action: 'storeTrue'
  , required: false
  , help: '(Android-only) When set the keystore will be used to sign apks.'
  }],

  [['--keystore-path'], {
    defaultValue: path.resolve(process.env.HOME || process.env.USERPROFILE || '', '.android', 'debug.keystore')
  , dest: 'keystorePath'
  , required: false
  , help: '(Android-only) Path to keystore'
  }],

  [['--keystore-password'], {
    defaultValue: 'android'
  , dest: 'keystorePassword'
  , required: false
  , help: '(Android-only) Password to keystore'
  }],

  [['--key-alias'], {
    defaultValue: 'androiddebugkey'
  , dest: 'keyAlias'
  , required: false
  , help: '(Android-only) Key alias'
  }],

  [['--key-password'], {
    defaultValue: 'android'
  , dest: 'keyPassword'
  , required: false
  , help: '(Android-only) Key password'
  }],

  [['--show-config'], {
    defaultValue: false
  , dest: 'showConfig'
  , action: 'storeTrue'
  , required: false
  , help: 'Show info about the appium server configuration and exit'
  }],

  [['--command-timeout'], {
    defaultValue: 60
  , dest: 'defaultCommandTimeout'
  , type: 'int'
  , required: false
  , help: 'The default command timeout for the server to use for all ' +
          'sessions. Will still be overridden by newCommandTimeout cap'
  }],

  [['--keep-keychains'], {
    defaultValue: false
  , dest: 'keepKeyChains'
  , action: 'storeTrue'
  , required: false
  , help: "(iOS) Whether to keep keychains (Library/Keychains) when reset app between sessions"
  , nargs: 0
  }],

  [['--strict-caps'], {
    defaultValue: false
  , dest: 'enforceStrictCaps'
  , action: 'storeTrue'
  , required: false
  , help: "Cause sessions to fail if desired caps are sent in that Appium " +
          "does not recognize as valid for the selected device"
  , nargs: 0
  }],

  [['--tmp'], {
    defaultValue: null
  , dest: 'tmpDir'
  , required: false
  , help: 'Absolute path to directory Appium can use to manage temporary ' +
          'files, like built-in iOS apps it needs to move around. On *nix/Mac ' +
          'defaults to /tmp, on Windows defaults to C:\\Windows\\Temp'
  }]

];

// Setup all the command line argument parsing
module.exports = function () {
  var parser = new ap({
    version: pkgObj.version,
    addHelp: true,
    description: 'A webdriver-compatible server for use with native and hybrid iOS and Android applications.'
  });

  _.each(args, function (arg) {
    parser.addArgument(arg[0], arg[1]);
  });

  parser.rawArgs = args;

  return parser;
};
<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
const root = require('window-or-global');
const detectPort = require('detect-port');
const macacaReporterRender = require('macaca-reporter/lib/render');

root.mockData = require('macaca-reporter/test/mock');

// TODO: remove this after clean template data in macaca-reporter
root.mockData.stats.passes = 0;
root.mockData.stats.passPercent = 0;
root.mockData.stats.duration = 0;
root.mockData.stats.skipped = 0;
root.mockData.stats.hasSkipped = false;

const _ = require('../common/helper');

let server = require('http').createServer();
let io = require('socket.io')(server);
let socketed = false;
let connected = false;

module.exports = function(app) {

  app.use(function *() {

    if (socketed) {
      /** Update content */
      this.body = fs.readFileSync(path.join(__dirname, '..', '..', 'reports', 'index.html'), 'utf8');
      return;
    } else {
      socketed = true;
    }

    var port = yield detectPort(56788);

    /** Listen to port and update change */
    server.listen(port);
    io.on('connection', function(socket) {
      if (connected === false) {
        connected = true;
        console.log('socket connected');
        setInterval(() => {
          io.sockets.emit('update reporter', root.mockData);
        }, 2000);

        socket.on('disconnect', function() {});
      }
    });

    /** Update content */
    this.body = fs.readFileSync(path.join(__dirname, '..', '..', 'reports', 'index.html'), 'utf8');

    /** Detect port and render data */
    macacaReporterRender(root.mockData, {
      socket: {
        server: `http://${_.ipv4}:${port}`
      }
    });
  });
};

/** Add event emmiter for picking up changes */
if (!root.eventEmmiter) {
  root.eventEmmiter = new EventEmitter();
}

root.eventEmmiter.addListener('screenRefresh', data => {
  let action = null;
  let i = 0;
  for (; i < data.currentNode.actions.length; i++) {
    if (data.currentNode.actions[i].isTriggered === false) {
      action = data.currentNode.actions[i];
      break;
    }
  }

  root.mockData.stats.duration = Date.now() - root.mockData.stats.start.getTime();
  root.mockData.stats.passPercent = (100 * root.mockData.stats.passes / (root.mockData.stats.tests ? root.mockData.stats.tests : 0)).toFixed(1);
  root.mockData.current.image = `./${data.fileName}` ;
  root.mockData.current.list = [];
  root.mockData.current.list.push({'title': 'digest', 'value': data.currentNode.digest});
  root.mockData.current.list.push({'title': 'actions-done', 'value': i});
  root.mockData.current.list.push({'title': 'actions-total', 'value': data.currentNode.actions.length});
  root.mockData.current.list.push({'title': 'action-path', 'value': action ? action.location : 'all action cleared'});
  root.mockData.current.list.push({'title': 'depth', 'value': data.currentNode.depth});
  root.mockData.current.list.push({'title': 'node-type', 'value': data.currentNode.type});
  root.mockData.current.list.push({'title': 'action-description', 'value': action ? JSON.stringify(action.source) : ''});
});

root.eventEmmiter.addListener('terminateCrawling', data => {
  socketed.disconnected();
  process.exist();
});
<commit_msg>refine data refresh<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
const root = require('window-or-global');
const detectPort = require('detect-port');
const macacaReporterRender = require('macaca-reporter/lib/render');

root.mockData = require('macaca-reporter/test/mock');

// TODO: remove this after clean template data in macaca-reporter
root.mockData.stats.passes = 0;
root.mockData.stats.passPercent = 0;
root.mockData.stats.duration = 0;
root.mockData.stats.skipped = 0;
root.mockData.stats.hasSkipped = false;

const _ = require('../common/helper');

let server = require('http').createServer();
let io = require('socket.io')(server);
let socketed = false;
let connected = false;

module.exports = function(app) {

  app.use(function *() {

    if (socketed) {
      /** Update content */
      this.body = fs.readFileSync(path.join(__dirname, '..', '..', 'reports', 'index.html'), 'utf8');
      return;
    } else {
      socketed = true;
    }

    var port = yield detectPort(56788);

    /** Listen to port and update change */
    server.listen(port);
    io.on('connection', function(socket) {
      if (connected === false) {
        connected = true;
        console.log('socket connected');
        setInterval(() => {
          root.mockData.stats.duration = Date.now() - root.mockData.stats.start.getTime();
          root.mockData.stats.passPercent = (100 * root.mockData.stats.passes / (root.mockData.stats.tests ? root.mockData.stats.tests : 0)).toFixed(1);
          io.sockets.emit('update reporter', root.mockData);
        }, 2000);

        socket.on('disconnect', function() {});
      }
    });

    /** Update content */
    this.body = fs.readFileSync(path.join(__dirname, '..', '..', 'reports', 'index.html'), 'utf8');

    /** Detect port and render data */
    macacaReporterRender(root.mockData, {
      socket: {
        server: `http://${_.ipv4}:${port}`
      }
    });
  });
};

/** Add event emmiter for picking up changes */
if (!root.eventEmmiter) {
  root.eventEmmiter = new EventEmitter();
}

root.eventEmmiter.addListener('screenRefresh', data => {
  let action = null;
  let i = 0;
  for (; i < data.currentNode.actions.length; i++) {
    if (data.currentNode.actions[i].isTriggered === false) {
      action = data.currentNode.actions[i];
      break;
    }
  }

  root.mockData.current.image = `./${data.fileName}` ;
  root.mockData.current.list = [];
  root.mockData.current.list.push({'title': 'digest', 'value': data.currentNode.digest});
  root.mockData.current.list.push({'title': 'actions-done', 'value': i});
  root.mockData.current.list.push({'title': 'actions-total', 'value': data.currentNode.actions.length});
  root.mockData.current.list.push({'title': 'action-path', 'value': action ? action.location : 'all action cleared'});
  root.mockData.current.list.push({'title': 'depth', 'value': data.currentNode.depth});
  root.mockData.current.list.push({'title': 'node-type', 'value': data.currentNode.type});
  root.mockData.current.list.push({'title': 'action-description', 'value': action ? JSON.stringify(action.source) : ''});
});

root.eventEmmiter.addListener('terminateCrawling', data => {
  socketed.disconnected();
  process.exist();
});
<|endoftext|>


<commit_before>define([
    'handlers/app/main',
    'handlers/assets',
    'continuation-local-storage',
    'cluster',
    'handlers/ctlNavigate',
    'fs',
    'hapi',
    'path',
    'resolver/main',
    'handlers/safe',
    'handlers/stream',
    'handlers/tunnel'
], function (appHandler, assetsHandler, cls, cluster, ctlNavHandler, fs, hapi, path, resolver, safeHandler, streamHandler, tunnelHandler) {

    'use strict';

    var lazoNs = cls.createNamespace('lazojs');

    return {

        initialize: function (errHandlers, cb) {
            LAZO.logger.warn('[server.initialize] Initializing server...')

            this.errHandlers = errHandlers;
            this.cb = cb;
            this._cluster(); // cluster server if !this.DEV
        },

        _worker: function () {
            this._create() // create server instance
                ._views()
                ._extensions() // server extensions
                ._routes() // define app routes and add app handlers
                ._handlers() // add all other route handlers
                ._error() // init logger & error handling
                ._tail()
                ._start();
        },

        _create: function () {
            LAZO._server = this.server = new hapi.Server('0.0.0.0', LAZO.options.server.port, {
                debug: false,
                maxSockets: LAZO.options.server.maxSockets,
                payload: { maxBytes: 10485760 },
                state: { cookies: { failAction: 'log', strictHeader: false } }
            });

            if (LAZO.options.sslServer) {
                LAZO._sslServer = this.sslServer = new hapi.Server('0.0.0.0', LAZO.options.sslServer.port, {
                    debug: false,
                    maxSockets: LAZO.options.sslServer.maxSockets,
                    payload: { maxBytes: 10485760 },
                    state: { cookies: { failAction: 'log', strictHeader: false } },
                    tls: {
                        key: fs.readFileSync(path.resolve(path.normalize(LAZO.FILE_REPO_DIR + '/config/' + LAZO.options.sslServer.tls.key))),
                        cert: fs.readFileSync(path.resolve(path.normalize(LAZO.FILE_REPO_DIR + '/config/' + LAZO.options.sslServer.tls.cert)))
                    }
                });
            }

            return this;
        },

        _views: function () {
            var viewOptions = {
                engines: {
                    hbs: {
                        module: 'handlebars'
                    }
                },
                allowAbsolutePaths: true
            };
            this.server.views(viewOptions);
            this.sslServer && this.sslServer.views(viewOptions);

            return this;
        },

        _extensions: function () {
            var self = this;

            var preResponseHandler = function (request, next) {
                var response = request.response();

                // do not serve server code
                if (request.url.path.indexOf('/server/') !== -1 ||
                    request.url.path.lastIndexOf('/server') !== -1 ||
                    request.url.path.indexOf('/node_modules/') !== -1 ||
                    request.url.path.lastIndexOf('/node_modules') !== -1) {
                    return next(hapi.error.forbidden());
                    // if server render fails then send up HTML view, else return JSON error object
                } else if (response.isBoom) {
                    LAZO.logger.error('[server._extensions] Internal server error', request.url.href, response.response.code, response.message, response.trace);

                    if (LAZO.CLUSTER && !LAZO.ROBUST && response.response.code >= 500 && response.response.code <= 599) {
                        self._stop();
                    }

                    if (request.raw.req.headers['x-requested-with'] !== 'XMLHttpRequest') {
                        var errHandler = self.errHandlers[response.response.code];

                        if (errHandler) {
                            return next(request.generateView(errHandler.server, response.response.payload));
                        }
                    }
                }

                return next();
            };

            this.server.ext('onPreResponse', preResponseHandler);
            this.sslServer && this.sslServer.ext('onPreResponse', preResponseHandler);

            var onRequest = function (request, next) {
                lazoNs.run(function () {
                    lazoNs.set('request', request);
                    next();
                });
            };

            this.server.ext('onRequest', onRequest);
            this.sslServer && this.sslServer.ext('onRequest', onRequest);

            return this;
        },

        _routes: function () {
            var self = this,
                routes,
                routeDefs = LAZO.routes,
                processRoute = function (route, svr) {
                    routes = resolver.transformRoute(route);

                    if (routes.routeNoTrailingSlash) {
                        self._addAppRouteHandler('GET', routes.routeNoTrailingSlash, route, svr);
                        self._addAppRouteHandler('POST', routes.routeNoTrailingSlash, route, svr);
                    }

                    self._addAppRouteHandler('GET', routes.route, route, svr);
                    self._addAppRouteHandler('POST', routes.route, route, svr);
                };

            // give server a reference to routes, used later when handling the routes
            this.server._routes = routeDefs;

            for (var route in routeDefs) {
                processRoute(route, this.server);
            }

            if (LAZO.options.sslServer && LAZO.options.sslServer._routes) {
                // give ssl server a reference to routes, used later when handling the routes
                this.sslServer._routes = LAZO.options.sslServer._routes;
                for (var route in LAZO.options.sslServer._routes) {
                    processRoute(route, this.sslServer);
                }
            }
            return this;
        },

        _addAppRouteHandler: function (method, path, route, svr) {
            var self = this,
                definition = { method: method, path: path };

            if (method === 'GET') {
                definition.handler = function (request) {
                    appHandler(request, route, svr);
                };
            } else {
                definition.config = {
                    handler: function (request) {
                        appHandler(request, route, svr);
                    },
                    payload: 'parse'
                };
            }

            this._setServerRoute([svr], definition);

            return this;
        },

        _handlers: function () {
            this._tunnelHandler()
                ._assetsHandler()
                ._staticFilesHandler()
                ._ctlNavigate();

            return this;
        },

        _tunnelHandler: function () {
            var tunnelOptions = {
                method: 'POST',
                path: '/tunnel',
                config: {
                    handler: tunnelHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], tunnelOptions);

            var postFcaOptions = {
                method: 'POST',
                path: '/fn/{compName}/{action}',
                config: {
                    handler: streamHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], postFcaOptions);

            var postFaOptions = {
                method: 'POST',
                path: '/fn/{action}',
                config: {
                    handler: streamHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], postFaOptions);

            var getFcaOptions = {
                method: 'GET',
                path: '/fn/{compName}/{action}',
                config: {
                    handler: streamHandler
                }
            };

            this._setServerRoute([this.server, this.sslServer], getFcaOptions);

            var getFaOptions = {
                method: 'GET',
                path: '/fn/{action}',
                config: {
                    handler: streamHandler
                }
            };

            this._setServerRoute([this.server, this.sslServer], getFaOptions);

            return this;
        },

        _assetsHandler: function () {
            var assetOptions = {
                method: 'GET',
                path: '/assets',
                handler: assetsHandler
            };

            this._setServerRoute([this.server, this.sslServer], assetOptions);

            return this;
        },

        _staticFilesHandler: function () {
            var pathsOptions = {
                method: 'GET',
                path: '/{path*}',
                handler: {
                    directory: {
                        path: [
                            LAZO.BASE_REPO_DIR,
                            LAZO.FILE_REPO_DIR,
                            LAZO.BASE_PATH,
                            LAZO.BASE_PATH + '/lib'
                        ],
                        listing: false,
                        index: true
                    }
                }
            };

            this._setServerRoute([this.server, this.sslServer], pathsOptions);

            var libOptions = {
                method: 'GET',
                path: '/lib/{path*}',
                handler: {
                    directory: { path: [LAZO.BASE_PATH + '/lib'], listing: true, index: true }
                }
            };

            this._setServerRoute([this.server, this.sslServer], libOptions);

            var baseOptions = {
                method: 'GET',
                path: '/base/{path*}',
                handler: {
                    directory: { path: [LAZO.BASE_PATH + '/base'], listing: true, index: true }
                }
            };

            this._setServerRoute([this.server, this.sslServer], baseOptions);

            return this;
        },

        _ctlNavigate: function () {
            var navOptions = {
                method: 'POST',
                path: '/navigate',
                config: {
                    handler: ctlNavHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], navOptions);

            return this;
        },

        _error: function () {
            var ev = this.server.on ? this.server : this.server.events;

            ev.on('internalError', function (request, error) {
                LAZO.logger.debug('[server._error] Internal server error', request, error);
            });

            return this;
        },

        _tail: function () {
            var ev = this.server.on ? this.server : this.server.events;

            ev.on('tail', function (request) {
                LAZO.logger.debug('[server._tail]', request._response._code, request.method, request.url.path, request.info);
            });

            return this;
        },

        _start: function () {
            var self = this;

            this.server.pack.require('crumb', [
                { ext: true }
            ], function (err) {
                if (!err) {
                    self.server.start();
                    if (!self.sslServer) {
                        self.cb();
                    }
                }
            });

            this.sslServer && this.sslServer.pack.require('crumb', [
                { ext: true }
            ], function (err) {
                if (!err) {
                    self.sslServer.start();
                    self.cb();
                }
                else {
                    LAZO.logger.error('[server._start] Error while starting SSL server...', err);
                }
            });

            return this;
        },

        _stop: function () {
            var self = this;
            try {
                if (cluster.isWorker) {
                    cluster.worker.disconnect();
                }

                this.server.stop(function () {
                    if (!self.sslServer) {
                        return process.exit(1);
                    }

                    self.sslServer.stop(function () {
                        process.exit(1);
                    });
                });

            } catch (err) {
                LAZO.logger.error('[server._stop] Error while stopping server and disconnecting worker.', err);
            }
        },

        _cluster: function () {
            var cpus,
                sslPort = LAZO.options.sslServer && LAZO.options.sslServer.port;

            if (!LAZO.CLUSTER) {
                this._worker();
                LAZO.logger.warn('[server._cluster] Server started with single process, listening on port %d (SSL=%d)...',
                    LAZO.PORT, sslPort);
                return this;
            }

            cpus = process.env['CLUSTER'];

            if (cluster.isMaster) {
                for (var i = 0; i < cpus; i++) {
                    cluster.fork();
                }

                cluster.on('online', function (worker) {
                    LAZO.logger.warn('[server._cluster] Worker %d:%d is online.', worker.id, worker.process.pid);
                });

                cluster.on('disconnect', function (worker) {
                    LAZO.logger.warn('[server._cluster] Worker %d:%d was disconnected.', worker.id,
                        worker.process.pid);
                    cluster.fork();
                });
            } else {
                this._worker();
                LAZO.logger.warn('[server._cluster] Server started with %d workers, listening on port %d (SSL=%d)...', cpus, LAZO.PORT, sslPort);
            }

            return this;
        },

        _setServerRoute: function (servers, options) {
            var self = this;

            servers.forEach(function (server) {
                if (!server) {
                    return;
                }

                if (LAZO.ROBUST && typeof options.handler === 'function') {
                    options.handler = safeHandler(server, options.handler, self);
                }

                server.route(options);
            });
        }

    };

});
<commit_msg>fixed cls context for tunnel calls<commit_after>define([
    'handlers/app/main',
    'handlers/assets',
    'continuation-local-storage',
    'cluster',
    'handlers/ctlNavigate',
    'fs',
    'hapi',
    'path',
    'resolver/main',
    'handlers/safe',
    'handlers/stream',
    'handlers/tunnel'
], function (appHandler, assetsHandler, cls, cluster, ctlNavHandler, fs, hapi, path, resolver, safeHandler, streamHandler, tunnelHandler) {

    'use strict';

    var lazoNs = cls.createNamespace('lazojs');

    return {

        initialize: function (errHandlers, cb) {
            LAZO.logger.warn('[server.initialize] Initializing server...')

            this.errHandlers = errHandlers;
            this.cb = cb;
            this._cluster(); // cluster server if !this.DEV
        },

        _worker: function () {
            this._create() // create server instance
                ._views()
                ._extensions() // server extensions
                ._routes() // define app routes and add app handlers
                ._handlers() // add all other route handlers
                ._error() // init logger & error handling
                ._tail()
                ._start();
        },

        _create: function () {
            LAZO._server = this.server = new hapi.Server('0.0.0.0', LAZO.options.server.port, {
                debug: false,
                maxSockets: LAZO.options.server.maxSockets,
                payload: { maxBytes: 10485760 },
                state: { cookies: { failAction: 'log', strictHeader: false } }
            });

            if (LAZO.options.sslServer) {
                LAZO._sslServer = this.sslServer = new hapi.Server('0.0.0.0', LAZO.options.sslServer.port, {
                    debug: false,
                    maxSockets: LAZO.options.sslServer.maxSockets,
                    payload: { maxBytes: 10485760 },
                    state: { cookies: { failAction: 'log', strictHeader: false } },
                    tls: {
                        key: fs.readFileSync(path.resolve(path.normalize(LAZO.FILE_REPO_DIR + '/config/' + LAZO.options.sslServer.tls.key))),
                        cert: fs.readFileSync(path.resolve(path.normalize(LAZO.FILE_REPO_DIR + '/config/' + LAZO.options.sslServer.tls.cert)))
                    }
                });
            }

            return this;
        },

        _views: function () {
            var viewOptions = {
                engines: {
                    hbs: {
                        module: 'handlebars'
                    }
                },
                allowAbsolutePaths: true
            };
            this.server.views(viewOptions);
            this.sslServer && this.sslServer.views(viewOptions);

            return this;
        },

        _extensions: function () {
            var self = this;

            var preResponseHandler = function (request, next) {
                var response = request.response();

                // do not serve server code
                if (request.url.path.indexOf('/server/') !== -1 ||
                    request.url.path.lastIndexOf('/server') !== -1 ||
                    request.url.path.indexOf('/node_modules/') !== -1 ||
                    request.url.path.lastIndexOf('/node_modules') !== -1) {
                    return next(hapi.error.forbidden());
                    // if server render fails then send up HTML view, else return JSON error object
                } else if (response.isBoom) {
                    LAZO.logger.error('[server._extensions] Internal server error', request.url.href, response.response.code, response.message, response.trace);

                    if (LAZO.CLUSTER && !LAZO.ROBUST && response.response.code >= 500 && response.response.code <= 599) {
                        self._stop();
                    }

                    if (request.raw.req.headers['x-requested-with'] !== 'XMLHttpRequest') {
                        var errHandler = self.errHandlers[response.response.code];

                        if (errHandler) {
                            return next(request.generateView(errHandler.server, response.response.payload));
                        }
                    }
                }

                return next();
            };

            this.server.ext('onPreResponse', preResponseHandler);
            this.sslServer && this.sslServer.ext('onPreResponse', preResponseHandler);

            var onRequest = function (request, next) {
                lazoNs.run(function () {
                    lazoNs.set('request', request);
                    process.nextTick(function () {
                        next();
                    });
                });
            };

            this.server.ext('onRequest', onRequest);
            this.sslServer && this.sslServer.ext('onRequest', onRequest);

            return this;
        },

        _routes: function () {
            var self = this,
                routes,
                routeDefs = LAZO.routes,
                processRoute = function (route, svr) {
                    routes = resolver.transformRoute(route);

                    if (routes.routeNoTrailingSlash) {
                        self._addAppRouteHandler('GET', routes.routeNoTrailingSlash, route, svr);
                        self._addAppRouteHandler('POST', routes.routeNoTrailingSlash, route, svr);
                    }

                    self._addAppRouteHandler('GET', routes.route, route, svr);
                    self._addAppRouteHandler('POST', routes.route, route, svr);
                };

            // give server a reference to routes, used later when handling the routes
            this.server._routes = routeDefs;

            for (var route in routeDefs) {
                processRoute(route, this.server);
            }

            if (LAZO.options.sslServer && LAZO.options.sslServer._routes) {
                // give ssl server a reference to routes, used later when handling the routes
                this.sslServer._routes = LAZO.options.sslServer._routes;
                for (var route in LAZO.options.sslServer._routes) {
                    processRoute(route, this.sslServer);
                }
            }
            return this;
        },

        _addAppRouteHandler: function (method, path, route, svr) {
            var self = this,
                definition = { method: method, path: path };

            if (method === 'GET') {
                definition.handler = function (request) {
                    appHandler(request, route, svr);
                };
            } else {
                definition.config = {
                    handler: function (request) {
                        appHandler(request, route, svr);
                    },
                    payload: 'parse'
                };
            }

            this._setServerRoute([svr], definition);

            return this;
        },

        _handlers: function () {
            this._tunnelHandler()
                ._assetsHandler()
                ._staticFilesHandler()
                ._ctlNavigate();

            return this;
        },

        _tunnelHandler: function () {
            var tunnelOptions = {
                method: 'POST',
                path: '/tunnel',
                config: {
                    handler: tunnelHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], tunnelOptions);

            var postFcaOptions = {
                method: 'POST',
                path: '/fn/{compName}/{action}',
                config: {
                    handler: streamHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], postFcaOptions);

            var postFaOptions = {
                method: 'POST',
                path: '/fn/{action}',
                config: {
                    handler: streamHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], postFaOptions);

            var getFcaOptions = {
                method: 'GET',
                path: '/fn/{compName}/{action}',
                config: {
                    handler: streamHandler
                }
            };

            this._setServerRoute([this.server, this.sslServer], getFcaOptions);

            var getFaOptions = {
                method: 'GET',
                path: '/fn/{action}',
                config: {
                    handler: streamHandler
                }
            };

            this._setServerRoute([this.server, this.sslServer], getFaOptions);

            return this;
        },

        _assetsHandler: function () {
            var assetOptions = {
                method: 'GET',
                path: '/assets',
                handler: assetsHandler
            };

            this._setServerRoute([this.server, this.sslServer], assetOptions);

            return this;
        },

        _staticFilesHandler: function () {
            var pathsOptions = {
                method: 'GET',
                path: '/{path*}',
                handler: {
                    directory: {
                        path: [
                            LAZO.BASE_REPO_DIR,
                            LAZO.FILE_REPO_DIR,
                            LAZO.BASE_PATH,
                            LAZO.BASE_PATH + '/lib'
                        ],
                        listing: false,
                        index: true
                    }
                }
            };

            this._setServerRoute([this.server, this.sslServer], pathsOptions);

            var libOptions = {
                method: 'GET',
                path: '/lib/{path*}',
                handler: {
                    directory: { path: [LAZO.BASE_PATH + '/lib'], listing: true, index: true }
                }
            };

            this._setServerRoute([this.server, this.sslServer], libOptions);

            var baseOptions = {
                method: 'GET',
                path: '/base/{path*}',
                handler: {
                    directory: { path: [LAZO.BASE_PATH + '/base'], listing: true, index: true }
                }
            };

            this._setServerRoute([this.server, this.sslServer], baseOptions);

            return this;
        },

        _ctlNavigate: function () {
            var navOptions = {
                method: 'POST',
                path: '/navigate',
                config: {
                    handler: ctlNavHandler,
                    payload: 'parse'
                }
            };

            this._setServerRoute([this.server, this.sslServer], navOptions);

            return this;
        },

        _error: function () {
            var ev = this.server.on ? this.server : this.server.events;

            ev.on('internalError', function (request, error) {
                LAZO.logger.debug('[server._error] Internal server error', request, error);
            });

            return this;
        },

        _tail: function () {
            var ev = this.server.on ? this.server : this.server.events;

            ev.on('tail', function (request) {
                LAZO.logger.debug('[server._tail]', request._response._code, request.method, request.url.path, request.info);
            });

            return this;
        },

        _start: function () {
            var self = this;

            this.server.pack.require('crumb', [
                { ext: true }
            ], function (err) {
                if (!err) {
                    self.server.start();
                    if (!self.sslServer) {
                        self.cb();
                    }
                }
            });

            this.sslServer && this.sslServer.pack.require('crumb', [
                { ext: true }
            ], function (err) {
                if (!err) {
                    self.sslServer.start();
                    self.cb();
                }
                else {
                    LAZO.logger.error('[server._start] Error while starting SSL server...', err);
                }
            });

            return this;
        },

        _stop: function () {
            var self = this;
            try {
                if (cluster.isWorker) {
                    cluster.worker.disconnect();
                }

                this.server.stop(function () {
                    if (!self.sslServer) {
                        return process.exit(1);
                    }

                    self.sslServer.stop(function () {
                        process.exit(1);
                    });
                });

            } catch (err) {
                LAZO.logger.error('[server._stop] Error while stopping server and disconnecting worker.', err);
            }
        },

        _cluster: function () {
            var cpus,
                sslPort = LAZO.options.sslServer && LAZO.options.sslServer.port;

            if (!LAZO.CLUSTER) {
                this._worker();
                LAZO.logger.warn('[server._cluster] Server started with single process, listening on port %d (SSL=%d)...',
                    LAZO.PORT, sslPort);
                return this;
            }

            cpus = process.env['CLUSTER'];

            if (cluster.isMaster) {
                for (var i = 0; i < cpus; i++) {
                    cluster.fork();
                }

                cluster.on('online', function (worker) {
                    LAZO.logger.warn('[server._cluster] Worker %d:%d is online.', worker.id, worker.process.pid);
                });

                cluster.on('disconnect', function (worker) {
                    LAZO.logger.warn('[server._cluster] Worker %d:%d was disconnected.', worker.id,
                        worker.process.pid);
                    cluster.fork();
                });
            } else {
                this._worker();
                LAZO.logger.warn('[server._cluster] Server started with %d workers, listening on port %d (SSL=%d)...', cpus, LAZO.PORT, sslPort);
            }

            return this;
        },

        _setServerRoute: function (servers, options) {
            var self = this;

            servers.forEach(function (server) {
                if (!server) {
                    return;
                }

                if (LAZO.ROBUST && typeof options.handler === 'function') {
                    options.handler = safeHandler(server, options.handler, self);
                }

                server.route(options);
            });
        }

    };

});
<|endoftext|>


<commit_before>/* module make possible connectoin thru socket.io on a server */

(function() {
    'use strict';

    var main            = global.cloudcmd.main,
        SRVDIR          = main.SRVDIR,

        io              = main.require('socket.io'),
        update          = main.srvrequire('update'),
        exec            = main.child_process.exec,
        Util            = main.util,
        mainpackage     = main.mainpackage,
        CLOUDCMD        = mainpackage.name,

        ClientFuncs     = [],
        OnMessageFuncs  = [],
        INFO_LOG_LEVEL  = 2,
        WIN32           = main.WIN32,

        /* windows commands thet require
         * unicode charset on locales
         * different then English
         */
        Win32Commands   = ['ASSOC', 'AT', 'ATTRIB', 'BREAK', 'CACLS', 'CALL',
                            'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', 'CLS',
                            'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY',
                            'DATE', 'DEL', 'DIR', 'DISKCOMP', 'DISKCOPY', 'DOSKEY',
                            'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', 'FIND',
                            'FINDSTR', 'FOR', 'FORMAT', 'FTYPE', 'GOTO', 'GRAFTABL',
                            'HELP', 'IF', 'LABEL', 'MD', 'MKDIR', 'MODE', 'MORE',
                            'MOVE', 'PATH', 'PAUSE', 'POPD', 'PRINT', 'PROMPT',
                            'PUSHD', 'RD', 'RECOVER', 'REM', 'REN', 'RENAME',
                            'REPLACE', 'RMDIR', 'SET', 'SETLOCAL', 'SHIFT', 'SORT',
                            'START', 'SUBST', 'TIME', 'TITLE', 'TREE', 'TYPE',
                            'VER', 'VERIFY', 'VOL', 'XCOPY'];

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.listen = function(pServer) {
        var lRet, lListen, lConnNum, lMsg, lConn_func;

        if (io) {
            lListen     = io.listen(pServer),
            lConnNum    = 0;

            lListen.set('log level', INFO_LOG_LEVEL);

            /*
             * on Win7 application is crashing,
             * when options below is used.
             *
             * https://github.com/LearnBoost/socket.io/issues/1314
             *
             */
            if (!WIN32) {
                lListen.enable('browser client minification');
                lListen.enable('browser client gzip');
                lListen.enable('browser client etag');
            }

            lListen.set('transports', [
              'websocket',
              'htmlfile',
              'xhr-polling',
              'jsonp-polling'
            ]);

            lRet = lListen.sockets.on('connection', function (socket) {
                var lJSON;
                ++lConnNum;

                if(!OnMessageFuncs[lConnNum]) {
                    lMsg    = log(lConnNum, 'connected\n');
                    lJSON   = {
                        stdout : lMsg
                    };
                    lMsg    = Util.stringifyJSON(lJSON);

                    socket.send(lMsg);

                    OnMessageFuncs[lConnNum]    = onMessage(lConnNum, socket);
                    lConn_func                  = OnMessageFuncs[lConnNum];

                    socket.on('message', lConn_func);
                    socket.on('disconnect', Util.call(disconnect, lConnNum));
                } else {
                    lMsg = log(lConnNum, ' in use. Reconnecting...');
                    socket.send('{"stdout":"' + lMsg + '"}');
                    socket.disconnect();
                }

            });
        }

        return lRet;
    };

    function disconnect(pParams) {
        var lConnNum, lRet = Util.checkObj(pParams, ['params']);

        if(lRet) {
            lConnNum = pParams.params;
            OnMessageFuncs  [lConnNum]  =
            ClientFuncs     [lConnNum]  = null;

            log(lConnNum, 'disconnected');
        }

    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum, pSocket
     */
    function onMessage(pConnNum, pSocket) {
        return function(pCommand) {
            var lMsg, lJSON, lWinCommand, lExec_func, lDir,
                lHome, lError, lRet, lExecSymbols;

            Util.log('#' + pConnNum + ': ' + pCommand);

            if (Util.isContainStrAtBegin(pCommand, CLOUDCMD)) {
                pCommand = Util.removeStr(pCommand, CLOUDCMD);

                if( Util.isContainStrAtBegin(pCommand, ' ') ) {
                    pCommand = Util.removeStr(pCommand, ' ');

                    if( Util.isContainStrAtBegin(pCommand, 'update') && update )
                        update.get();

                    if( Util.strCmp(pCommand, 'exit') )
                        if(WIN32)
                            pCommand = 'taskkill -f /PID ' + process.pid;
                        else
                            pCommand = 'kill -9 ' + process.pid;
                }
                else {
                    lJSON = {
                        stdout  : CLOUDCMD + ' exit     \n' +
                                  CLOUDCMD + ' update   \n',
                        stderr  : null
                    };

                    lMsg = Util.stringifyJSON( lJSON );
                    pSocket.send(lMsg);

                    Util.log('received from client: ' + pCommand);
                    Util.log('sended to client: ' + lMsg);
                }
            } else if( Util.isContainStrAtBegin(pCommand, 'cd ') ) {
                lDir    = Util.removeStr(pCommand, 'cd ');
                lHome   = process.env.HOME;

                if ( Util.isContainStr(lDir, '~') )
                    lDir = Util.replaceStr(lDir, '~', lHome);

                lError = Util.tryCatchLog(function() {
                    process.chdir(lDir);
                });

                if (!lError)
                    lRet = true;
                else {
                    lJSON = {
                        stderr: Util.stringifyJSON( lError )
                    };

                    lMsg = Util.stringifyJSON( lJSON );

                    pSocket.send(lMsg);
                }
            }

            if (!lRet) {
                /* if we on windows and command is build in
                 * change code page to unicode becouse
                 * windows use unicode on non English versions
                 */
                if(WIN32) {
                    lWinCommand = pCommand.toUpperCase();

                    if( Win32Commands.indexOf(lWinCommand) >= 0 )
                        pCommand = 'chcp 65001 |' + pCommand;
                }

                if(!ClientFuncs[pConnNum])
                    ClientFuncs[pConnNum] = getExec(pSocket, pConnNum);

                lExec_func = ClientFuncs[pConnNum];

                lExecSymbols = ['&', '{', '}', '|', '\'', '"'];

                if (Util.isContainStr(pCommand, lExecSymbols))
                    exec(pCommand, lExec_func);
                else
                    getSpawn(pSocket, pConnNum, pCommand);
            }
        };
    }

    /**
     * function send result of command to client
     * @param pSocket
     */
    function getExec(pSocket, pConnNum) {
        return function(pError, pStdout, pStderr) {
            var lErrorStr, lExecStr, lExec,
                lError          = pError || pStderr;

            if (lError) {
                if (!Util.isString(lError))
                    lErrorStr   = lError.toString();

                lErrorStr = Util.addNewLine(lErrorStr);
            }

            lExec               = {
                stdout : pStdout,
                stderr : lErrorStr || lError
            };

            lExecStr       = JSON.stringify(lExec);

            log(pConnNum, pError, 'error');
            log(pConnNum, pStderr, 'stderror');

            pSocket.send(lExecStr);
        };
    }

    function getSpawn(pSocket, pConnNum, pCommand) {
        var send, cmd, spawn,
            args    = pCommand.split(' ');

        pCommand    = args.shift();

        spawn       = main.child_process.spawn;
        cmd         = spawn(pCommand, args);
        send        = function(data, isError) {
            var lExecStr,
                lExec               = {},
                msg                 = data.toString();

            if (isError)
                lExec.stderr    = msg;
            else
                lExec.stdout    = msg;

            lExecStr            = JSON.stringify(lExec);
            pSocket.send(lExecStr);
        };

        cmd.stdout.on('data', send);

        cmd.stderr.on('data', function(data) {
            send(data, true);
        });

        cmd.on('error', Util.retFalse);
    }

    function log(pConnNum, pStr, pType) {
        var lRet, lType = ' ';

        if (pStr) {

            if (pType)
                lType += pType + ':';

            lRet = 'client #' + pConnNum + lType + pStr;

            Util.log(lRet);
        }

        return lRet;
    }
})();
<commit_msg>feature(socket) add "#"<commit_after>/* module make possible connectoin thru socket.io on a server */

(function() {
    'use strict';

    var main            = global.cloudcmd.main,
        SRVDIR          = main.SRVDIR,

        io              = main.require('socket.io'),
        update          = main.srvrequire('update'),
        exec            = main.child_process.exec,
        Util            = main.util,
        mainpackage     = main.mainpackage,
        CLOUDCMD        = mainpackage.name,

        ClientFuncs     = [],
        OnMessageFuncs  = [],
        INFO_LOG_LEVEL  = 2,
        WIN32           = main.WIN32,

        /* windows commands thet require
         * unicode charset on locales
         * different then English
         */
        Win32Commands   = ['ASSOC', 'AT', 'ATTRIB', 'BREAK', 'CACLS', 'CALL',
                            'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', 'CLS',
                            'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY',
                            'DATE', 'DEL', 'DIR', 'DISKCOMP', 'DISKCOPY', 'DOSKEY',
                            'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', 'FIND',
                            'FINDSTR', 'FOR', 'FORMAT', 'FTYPE', 'GOTO', 'GRAFTABL',
                            'HELP', 'IF', 'LABEL', 'MD', 'MKDIR', 'MODE', 'MORE',
                            'MOVE', 'PATH', 'PAUSE', 'POPD', 'PRINT', 'PROMPT',
                            'PUSHD', 'RD', 'RECOVER', 'REM', 'REN', 'RENAME',
                            'REPLACE', 'RMDIR', 'SET', 'SETLOCAL', 'SHIFT', 'SORT',
                            'START', 'SUBST', 'TIME', 'TITLE', 'TREE', 'TYPE',
                            'VER', 'VERIFY', 'VOL', 'XCOPY'];

    /**
     * function listen on servers port
     * @pServer {Object} started server object
     */
    exports.listen = function(pServer) {
        var lRet, lListen, lConnNum, lMsg, lConn_func;

        if (io) {
            lListen     = io.listen(pServer),
            lConnNum    = 0;

            lListen.set('log level', INFO_LOG_LEVEL);

            /*
             * on Win7 application is crashing,
             * when options below is used.
             *
             * https://github.com/LearnBoost/socket.io/issues/1314
             *
             */
            if (!WIN32) {
                lListen.enable('browser client minification');
                lListen.enable('browser client gzip');
                lListen.enable('browser client etag');
            }

            lListen.set('transports', [
              'websocket',
              'htmlfile',
              'xhr-polling',
              'jsonp-polling'
            ]);

            lRet = lListen.sockets.on('connection', function (socket) {
                var lJSON;
                ++lConnNum;

                if(!OnMessageFuncs[lConnNum]) {
                    lMsg    = log(lConnNum, 'connected\n');
                    lJSON   = {
                        stdout : lMsg
                    };
                    lMsg    = Util.stringifyJSON(lJSON);

                    socket.send(lMsg);

                    OnMessageFuncs[lConnNum]    = onMessage(lConnNum, socket);
                    lConn_func                  = OnMessageFuncs[lConnNum];

                    socket.on('message', lConn_func);
                    socket.on('disconnect', Util.call(disconnect, lConnNum));
                } else {
                    lMsg = log(lConnNum, ' in use. Reconnecting...');
                    socket.send('{"stdout":"' + lMsg + '"}');
                    socket.disconnect();
                }

            });
        }

        return lRet;
    };

    function disconnect(pParams) {
        var lConnNum, lRet = Util.checkObj(pParams, ['params']);

        if(lRet) {
            lConnNum = pParams.params;
            OnMessageFuncs  [lConnNum]  =
            ClientFuncs     [lConnNum]  = null;

            log(lConnNum, 'disconnected');
        }

    }

    /**
     * function gets onMessage function
     * that execute needed command
     *
     * @param pConnNum, pSocket
     */
    function onMessage(pConnNum, pSocket) {
        return function(pCommand) {
            var lMsg, lJSON, lWinCommand, lExec_func, lDir,
                lHome, lError, lRet, lExecSymbols;

            Util.log('#' + pConnNum + ': ' + pCommand);

            if (Util.isContainStrAtBegin(pCommand, CLOUDCMD)) {
                pCommand = Util.removeStr(pCommand, CLOUDCMD);

                if( Util.isContainStrAtBegin(pCommand, ' ') ) {
                    pCommand = Util.removeStr(pCommand, ' ');

                    if( Util.isContainStrAtBegin(pCommand, 'update') && update )
                        update.get();

                    if( Util.strCmp(pCommand, 'exit') )
                        if(WIN32)
                            pCommand = 'taskkill -f /PID ' + process.pid;
                        else
                            pCommand = 'kill -9 ' + process.pid;
                }
                else {
                    lJSON = {
                        stdout  : CLOUDCMD + ' exit     \n' +
                                  CLOUDCMD + ' update   \n',
                        stderr  : null
                    };

                    lMsg = Util.stringifyJSON( lJSON );
                    pSocket.send(lMsg);

                    Util.log('received from client: ' + pCommand);
                    Util.log('sended to client: ' + lMsg);
                }
            } else if( Util.isContainStrAtBegin(pCommand, 'cd ') ) {
                lDir    = Util.removeStr(pCommand, 'cd ');
                lHome   = process.env.HOME;

                if ( Util.isContainStr(lDir, '~') )
                    lDir = Util.replaceStr(lDir, '~', lHome);

                lError = Util.tryCatchLog(function() {
                    process.chdir(lDir);
                });

                if (!lError)
                    lRet = true;
                else {
                    lJSON = {
                        stderr: Util.stringifyJSON( lError )
                    };

                    lMsg = Util.stringifyJSON( lJSON );

                    pSocket.send(lMsg);
                }
            }

            if (!lRet) {
                /* if we on windows and command is build in
                 * change code page to unicode becouse
                 * windows use unicode on non English versions
                 */
                if(WIN32) {
                    lWinCommand = pCommand.toUpperCase();

                    if( Win32Commands.indexOf(lWinCommand) >= 0 )
                        pCommand = 'chcp 65001 |' + pCommand;
                }

                if(!ClientFuncs[pConnNum])
                    ClientFuncs[pConnNum] = getExec(pSocket, pConnNum);

                lExec_func = ClientFuncs[pConnNum];

                lExecSymbols = ['#', '&', '{', '}', '|', '\'', '"'];

                if (Util.isContainStr(pCommand, lExecSymbols))
                    exec(pCommand, lExec_func);
                else
                    getSpawn(pSocket, pConnNum, pCommand);
            }
        };
    }

    /**
     * function send result of command to client
     * @param pSocket
     */
    function getExec(pSocket, pConnNum) {
        return function(pError, pStdout, pStderr) {
            var lErrorStr, lExecStr, lExec,
                lError          = pError || pStderr;

            if (lError) {
                if (!Util.isString(lError))
                    lErrorStr   = lError.toString();

                lErrorStr = Util.addNewLine(lErrorStr);
            }

            lExec               = {
                stdout : pStdout,
                stderr : lErrorStr || lError
            };

            lExecStr       = JSON.stringify(lExec);

            log(pConnNum, pError, 'error');
            log(pConnNum, pStderr, 'stderror');

            pSocket.send(lExecStr);
        };
    }

    function getSpawn(pSocket, pConnNum, pCommand) {
        var send, cmd, spawn,
            args    = pCommand.split(' ');

        pCommand    = args.shift();

        spawn       = main.child_process.spawn;
        cmd         = spawn(pCommand, args);
        send        = function(data, isError) {
            var lExecStr,
                lExec               = {},
                msg                 = data.toString();

            if (isError)
                lExec.stderr    = msg;
            else
                lExec.stdout    = msg;

            lExecStr            = JSON.stringify(lExec);
            pSocket.send(lExecStr);
        };

        cmd.stdout.on('data', send);

        cmd.stderr.on('data', function(data) {
            send(data, true);
        });

        cmd.on('error', Util.retFalse);
    }

    function log(pConnNum, pStr, pType) {
        var lRet, lType = ' ';

        if (pStr) {

            if (pType)
                lType += pType + ':';

            lRet = 'client #' + pConnNum + lType + pStr;

            Util.log(lRet);
        }

        return lRet;
    }
})();
<|endoftext|>


<commit_before>describe("Calculator", function(){
	var calculator;

	beforeEach(function(){
		calculator = new Calculator();
	});

	describe("add", function(){
		it("should be able to add 2 numbers", function(){
			var result = calculator.add(2, 3);

			expect(result).toEqual(5);
	});

		it("should throw and error if both arguments are not provided.", function(){
			var calculator = new Calculator();

			expect(function(){
				calculator.add(1)
			}).toThrow();
		});

		it("should be called with the right arguments.", function(){
			spyOn(calculator, "add").and.throwError("someError");

			var result = calculator.add(2, 5);

			expect(result).toEqual(7);

			expect(calculator.add).toHaveBeenCalled();

			expect(calculator.add).toHaveBeenCalledWith(2, 5);
		});
	});
});<commit_msg>Testing Errors<commit_after>describe("Calculator", function(){
	var calculator;

	beforeEach(function(){
		calculator = new Calculator();
	});

	describe("add", function(){
		it("should be able to add 2 numbers", function(){
			var result = calculator.add(2, 3);

			expect(result).toEqual(5);
	});

		it("should throw and error if both arguments are not provided.", function(){
			var calculator = new Calculator();

			expect(function(){
				calculator.add(1)
			}).toThrow();
		});

		it("should be called with the right arguments.", function(){
			spyOn(calculator, "add").and.throwError("someError");

			expect(function(){
				var result = calculator.add(2, 5);
			}).toThrowError("someError");
			// var result = calculator.add(2, 5);

			// expect(result).toEqual(7);

			// expect(calculator.add).toHaveBeenCalled();

			// expect(calculator.add).toHaveBeenCalledWith(2, 5);
		});
	});
});<|endoftext|>