--- /dev/null
+/package.xml/1.1/Fri Feb 1 01:41:30 2008//
+D/lib////
+D/test////
--- /dev/null
+framework/Argv
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+D/Horde////
--- /dev/null
+framework/Argv/lib
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Raised if an ambiguous option is seen on the command line.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_AmbiguousOptionException extends Horde_Argv_BadOptionException
+{
+ public function __construct($opt_str, $possibilities)
+ {
+ // Have to skip the BadOptionException constructor or the string gets double-prefixed.
+ Horde_Argv_OptionException::__construct(sprintf(_("ambiguous option: %s (%s?)"), $opt_str, implode(', ', $possibilities)));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Raised if an invalid option is seen on the command line.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_BadOptionException extends Horde_Argv_OptionException
+{
+ public function __construct($opt_str)
+ {
+ parent::__construct(sprintf(_("no such option: %s"), $opt_str));
+ }
+
+}
--- /dev/null
+/AmbiguousOptionException.php/1.2/Wed Jun 18 19:00:45 2008//
+/BadOptionException.php/1.2/Wed Jun 18 19:00:45 2008//
+/Exception.php/1.2/Wed Jun 18 19:00:45 2008//
+/HelpFormatter.php/1.2/Wed Jun 18 19:00:45 2008//
+/IndentedHelpFormatter.php/1.3/Wed Jun 18 19:00:45 2008//
+/Option.php/1.3/Wed Jun 18 19:00:45 2008//
+/OptionConflictException.php/1.2/Wed Jun 18 19:00:45 2008//
+/OptionContainer.php/1.2/Wed Jun 18 19:00:45 2008//
+/OptionException.php/1.2/Wed Jun 18 19:00:45 2008//
+/OptionGroup.php/1.2/Wed Jun 18 19:00:45 2008//
+/OptionValueException.php/1.2/Wed Jun 18 19:00:45 2008//
+/Parser.php/1.3/Wed Jun 18 19:00:45 2008//
+/TitledHelpFormatter.php/1.2/Wed Jun 18 19:00:45 2008//
+/Values.php/1.2/Wed Jun 18 19:00:45 2008//
+D
--- /dev/null
+framework/Argv/lib/Horde/Argv
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+<?php
+/**
+ * Horde command-line argument parser
+ *
+ * This package is ported from Python's Optik (http://optik.sourceforge.net/).
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_Exception extends Exception
+{}
--- /dev/null
+<?php
+/**
+ * Provides HelpFormatter, used by Horde_Argv_Parser to generate formatted
+ * help text.
+ *
+ * This package is ported from Python's Optik (http://optik.sourceforge.net/).
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Abstract base class for formatting option help. Horde_Argv_Parser
+ * instances should use one of the HelpFormatter subclasses for
+ * formatting help; by default IndentedHelpFormatter is used.
+ *
+ Instance attributes:
+ parser : Horde_Argv_Parser
+ the controlling Horde_Argv_Parser instance
+ indent_increment : int
+ the number of columns to indent per nesting level
+ max_help_position : int
+ the maximum starting column for option help text
+ help_position : int
+ the calculated starting column for option help text;
+ initially the same as the maximum
+ width : int
+ total number of columns for output (pass None to constructor for
+ this value to be taken from the $COLUMNS environment variable)
+ level : int
+ current indentation level
+ current_indent : int
+ current indentation level (in columns)
+ help_width : int
+ number of columns available for option help text (calculated)
+ default_tag : str
+ text to replace with each option's default value, "%default"
+ by default. Set to false value to disable default value expansion.
+ option_strings : { Option : str }
+ maps Option instances to the snippet of help text explaining
+ the syntax of that option, e.g. "-h, --help" or
+ "-fFILE, --file=FILE"
+ _short_opt_fmt : str
+ format string controlling how short options with values are
+ printed in help text. Must be either "%s%s" ("-fFILE") or
+ "%s %s" ("-f FILE"), because those are the two syntaxes that
+ Optik supports.
+ _long_opt_fmt : str
+ similar but for long options; must be either "%s %s" ("--file FILE")
+ or "%s=%s" ("--file=FILE").
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+abstract class Horde_Argv_HelpFormatter
+{
+ const NO_DEFAULT_VALUE = 'none';
+
+ public $parser = null;
+
+ public function __construct($indent_increment, $max_help_position, $width = null, $short_first = false)
+ {
+ $this->indent_increment = $indent_increment;
+ $this->help_position = $this->max_help_position = $max_help_position;
+ if (is_null($width)) {
+ if (!empty($_ENV['COLUMNS'])) {
+ $width = $_ENV['COLUMNS'];
+ } else {
+ $width = 80;
+ }
+ $width -= 2;
+ }
+ $this->width = $width;
+ $this->current_indent = 0;
+ $this->level = 0;
+ $this->help_width = null; // computed later
+ $this->short_first = $short_first;
+ $this->default_tag = "%default";
+ $this->option_strings = array();
+ $this->_short_opt_fmt = "%s %s";
+ $this->_long_opt_fmt = "%s=%s";
+ }
+
+ public function setParser($parser)
+ {
+ $this->parser = $parser;
+ }
+
+ public function setShortOptDelimiter($delim)
+ {
+ if (!in_array($delim, array('', ' '))) {
+ throw new InvalidArgumentException('invalid metavar delimiter for short options: ' . $delim);
+ }
+ $this->_short_opt_fmt = "%s$delim%s";
+ }
+
+ public function setLongOptDelimiter($delim)
+ {
+ if (!in_array($delim, array('=', ' '))) {
+ throw new InvalidArgumentException('invalid metavar delimiter for long options: ' . $delim);
+ }
+ $this->_long_opt_fmt = "%s$delim%s";
+ }
+
+ public function indent()
+ {
+ $this->current_indent += $this->indent_increment;
+ $this->level += 1;
+ }
+
+ public function dedent()
+ {
+ $this->current_indent -= $this->indent_increment;
+ assert($this->current_indent >= 0); // Indent decreased below 0
+ $this->level -= 1;
+ }
+
+ public abstract function formatUsage($usage);
+
+ public abstract function formatHeading($heading);
+
+ /**
+ * Format a paragraph of free-form text for inclusion in the
+ * help output at the current indentation level.
+ */
+ protected function _formatText($text)
+ {
+ $text_width = $this->width - $this->current_indent;
+ $indent = str_repeat(' ', $this->current_indent);
+ return wordwrap($indent . $text, $text_width, "\n" . $indent);
+ }
+
+ public function formatDescription($description)
+ {
+ if ($description) {
+ return $this->_formatText($description) . "\n";
+ } else {
+ return '';
+ }
+ }
+
+ public function formatEpilog($epilog)
+ {
+ if ($epilog) {
+ return "\n" . $this->_formatText($epilog) . "\n";
+ } else {
+ return '';
+ }
+ }
+
+ public function expandDefault($option)
+ {
+ if (is_null($this->parser) || !$this->default_tag) {
+ return $option->help;
+ }
+
+ $default_value = isset($this->parser->defaults[$option->dest]) ? $this->parser->defaults[$option->dest] : null;
+ if ($default_value == Horde_Argv_Option::$NO_DEFAULT || !$default_value) {
+ $default_value = self::NO_DEFAULT_VALUE;
+ }
+
+ return str_replace($this->default_tag, (string)$default_value, $option->help);
+ }
+
+ /**
+ * The help for each option consists of two parts:
+ * * the opt strings and metavars
+ * eg. ("-x", or "-fFILENAME, --file=FILENAME")
+ * * the user-supplied help string
+ * eg. ("turn on expert mode", "read data from FILENAME")
+ *
+ * If possible, we write both of these on the same line:
+ * -x turn on expert mode
+ *
+ * But if the opt string list is too long, we put the help
+ * string on a second line, indented to the same column it would
+ * start in if it fit on the first line.
+ * -fFILENAME, --file=FILENAME
+ * read data from FILENAME
+ */
+ public function formatOption($option)
+ {
+ $result = array();
+ $opts = isset($this->option_strings[(string)$option]) ? $this->option_strings[(string)$option] : null;
+ $opt_width = $this->help_position - $this->current_indent - 2;
+ if (strlen($opts) > $opt_width) {
+ $opts = sprintf('%' . $this->current_indent . "s%s\n", "", $opts);
+ $indent_first = $this->help_position;
+ } else {
+ // start help on same line as opts
+ $opts = sprintf("%" . $this->current_indent . "s%-" . $opt_width . "s ", "", $opts);
+ $indent_first = 0;
+ }
+ $result[] = $opts;
+ if ($option->help) {
+ $help_text = $this->expandDefault($option);
+ $help_lines = explode("\n", wordwrap($help_text, $this->help_width));
+ $result[] = sprintf("%" . $indent_first . "s%s\n", '', $help_lines[0]);
+ for ($i = 1, $i_max = count($help_lines); $i < $i_max; $i++) {
+ $result[] = sprintf("%" . $this->help_position . "s%s\n", "", $help_lines[$i]);
+ }
+ } elseif (substr($opts, -1) != "\n") {
+ $result[] = "\n";
+ }
+ return implode('', $result);
+ }
+
+ public function storeOptionStrings($parser)
+ {
+ $this->indent();
+ $max_len = 0;
+ foreach ($parser->optionList as $opt) {
+ $strings = $this->formatOptionStrings($opt);
+ $this->option_strings[(string)$opt] = $strings;
+ $max_len = max($max_len, strlen($strings) + $this->current_indent);
+ }
+ $this->indent();
+ foreach ($parser->optionGroups as $group) {
+ foreach ($group->optionList as $opt) {
+ $strings = $this->formatOptionStrings($opt);
+ $this->option_strings[(string)$opt] = $strings;
+ $max_len = max($max_len, strlen($strings) + $this->current_indent);
+ }
+ }
+ $this->dedent();
+ $this->dedent();
+ $this->help_position = min($max_len + 2, $this->max_help_position);
+ $this->help_width = $this->width - $this->help_position;
+ }
+
+ /**
+ * Return a comma-separated list of option strings & metavariables.
+ */
+ public function formatOptionStrings($option)
+ {
+ if ($option->takesValue()) {
+ $metavar = $option->metavar ? $option->metavar : strtoupper($option->dest);
+ $short_opts = array();
+ foreach ($option->shortOpts as $sopt) {
+ $short_opts[] = sprintf($this->_short_opt_fmt, $sopt, $metavar);
+ }
+ $long_opts = array();
+ foreach ($option->longOpts as $lopt) {
+ $long_opts[] = sprintf($this->_long_opt_fmt, $lopt, $metavar);
+ }
+ } else {
+ $short_opts = $option->shortOpts;
+ $long_opts = $option->longOpts;
+ }
+
+ if ($this->short_first) {
+ $opts = array_merge($short_opts, $long_opts);
+ } else {
+ $opts = array_merge($long_opts, $short_opts);
+ }
+
+ return implode(', ', $opts);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Format help with indented section bodies.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_IndentedHelpFormatter extends Horde_Argv_HelpFormatter
+{
+ public function __construct(
+ $indent_increment = 2,
+ $max_help_position = 24,
+ $width = null,
+ $short_first = true)
+ {
+ parent::__construct($indent_increment, $max_help_position, $width, $short_first);
+ }
+
+ public function formatUsage($usage)
+ {
+ return sprintf(_("Usage:") . " %s\n", $usage);
+ }
+
+ public function formatHeading($heading)
+ {
+ return sprintf('%' . $this->current_indent . "s%s:\n", '', $heading);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Defines the Option class and some standard value-checking functions.
+ *
+ * Instance attributes:
+ * shortOpts : [string]
+ * longOpts : [string]
+ *
+ * action : string
+ * type : string
+ * dest : string
+ * default : any
+ * nargs : int
+ * const : any
+ * choices : [string]
+ * callback : function
+ * callbackArgs : (any*)
+ * help : string
+ * metavar : string
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_Option
+{
+ const SUPPRESS_HELP = "SUPPRESS HELP";
+ const SUPPRESS_USAGE = "SUPPRESS USAGE";
+
+ /**
+ * Not supplying a default is different from a default of None,
+ * so we need an explicit "not supplied" value.
+ */
+ public static $NO_DEFAULT = array("NO", "DEFAULT");
+
+ public static function parseNumber($value)
+ {
+ if (!strlen($value)) {
+ return false;
+ }
+
+ // Values to check against or compute with.
+ $first = substr($value, 0, 1);
+ $prefix = substr($value, 0, 2);
+ $suffix = substr($value, 2);
+
+ // Hex
+ if ($prefix == '0x' || $prefix == '0X') {
+ if (strspn($suffix, '0123456789abcdefABCDEF') != strlen($suffix)) {
+ return false;
+ }
+ return hexdec($value);
+ }
+
+ // Binary
+ if ($prefix == '0b' || $prefix == '0B') {
+ if (strspn($suffix, '01') != strlen($suffix)) {
+ return false;
+ }
+ return bindec($value);
+ }
+
+ // Octal
+ if ($first == '0') {
+ $suffix = substr($value, 1);
+ if (strspn($suffix, '01234567') != strlen($suffix)) {
+ return false;
+ }
+ return octdec($suffix);
+ }
+
+ // Base 10
+ if (!is_numeric($value)) {
+ return false;
+ }
+ return intval($value);
+ }
+
+ public function checkBuiltin($opt, $value)
+ {
+ switch ($this->type) {
+ case 'int':
+ case 'long':
+ $number = self::parseNumber($value);
+ if ($number === false) {
+ $message = $this->type == 'int'
+ ? _("option %s: invalid integer value: '%s'")
+ : _("option %s: invalid long integer value: '%s'");
+ throw new Horde_Argv_OptionValueException(
+ sprintf($message, $opt, $value));
+ }
+ return $number;
+
+ case 'float':
+ if (!is_numeric($value)) {
+ throw new Horde_Argv_OptionValueException(
+ sprintf(_("option %s: invalid floating-point value: '%s'"),
+ $opt, $value));
+ }
+ return floatval($value);
+ }
+ }
+
+ public function checkChoice($opt, $value)
+ {
+ if (in_array($value, $this->choices)) {
+ return $value;
+ } else {
+ $choices = array();
+ foreach ($this->choices as $choice) {
+ $choices[] = (string)$choice;
+ }
+ $choices = "'" . implode("', '", $choices) . "'";
+ throw new Horde_Argv_OptionValueException(sprintf(
+ _("option %s: invalid choice: '%s' (choose from %s)"),
+ $opt, $value, $choices));
+ }
+ }
+
+
+ # The list of instance attributes that may be set through
+ # keyword args to the constructor.
+ public $ATTRS = array('action',
+ 'type',
+ 'dest',
+ 'default',
+ 'nargs',
+ 'const',
+ 'choices',
+ 'callback',
+ 'callbackArgs',
+ 'help',
+ 'metavar',
+ );
+
+ # The set of actions allowed by option parsers. Explicitly listed
+ # here so the constructor can validate its arguments.
+ public $ACTIONS = array("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "append_const",
+ "count",
+ "callback",
+ "help",
+ "version",
+ );
+
+ /**
+ * The set of actions that involve storing a value somewhere;
+ * also listed just for constructor argument validation. (If
+ * the action is one of these, there must be a destination.)
+ */
+ public $STORE_ACTIONS = array("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "append_const",
+ "count",
+ );
+
+ # The set of actions for which it makes sense to supply a value
+ # type, ie. which may consume an argument from the command line.
+ public $TYPED_ACTIONS = array("store",
+ "append",
+ "callback",
+ );
+
+ /**
+ * The set of actions which *require* a value type, ie. that
+ * always consume an argument from the command line.
+ */
+ public $ALWAYS_TYPED_ACTIONS = array("store",
+ "append",
+ );
+
+ # The set of actions which take a 'const' attribute.
+ public $CONST_ACTIONS = array("store_const",
+ "append_const",
+ );
+
+ # The set of known types for option parsers. Again, listed here for
+ # constructor argument validation.
+ public $TYPES = array("string", "int", "long", "float", "complex", "choice");
+
+ # Dictionary of argument checking functions, which convert and
+ # validate option arguments according to the option type.
+ #
+ # Signature of checking functions is:
+ # check(option : Option, opt : string, value : string) -> any
+ # where
+ # option is the Option instance calling the checker
+ # opt is the actual option seen on the command-line
+ # (eg. "-a", "--file")
+ # value is the option argument seen on the command-line
+ #
+ # The return value should be in the appropriate Python type
+ # for option.type -- eg. an integer if option.type == "int".
+ #
+ # If no checker is defined for a type, arguments will be
+ # unchecked and remain strings.
+ public $TYPE_CHECKER = array("int" => 'checkBuiltin',
+ "long" => 'checkBuiltin',
+ "float" => 'checkBuiltin',
+ "complex"=> 'checkBuiltin',
+ "choice" => 'checkChoice',
+ );
+
+ # CHECK_METHODS is a list of unbound method objects; they are called
+ # by the constructor, in order, after all attributes are
+ # initialized. The list is created and filled in later, after all
+ # the methods are actually defined. (I just put it here because I
+ # like to define and document all class attributes in the same
+ # place.) Subclasses that add another _check_*() method should
+ # define their own CHECK_METHODS list that adds their check method
+ # to those from this class.
+ public $CHECK_METHODS = array('_checkAction',
+ '_checkType',
+ '_checkChoice',
+ '_checkDest',
+ '_checkConst',
+ '_checkNargs',
+ '_checkCallback',
+ );
+
+ // -- Constructor/initialization methods ----------------------------
+
+ public $shortOpts = array();
+ public $longOpts = array();
+ public $dest;
+ public $default;
+
+ public function __construct()
+ {
+ // The last argument to this function is an $attrs hash, if it
+ // is present and an array. All other arguments are $opts.
+ $opts = func_get_args();
+ $num = func_num_args();
+ if ($num == 0 || $num == 1 || !is_array($opts[$num - 1])) {
+ $attrs = array();
+ } else {
+ $attrs = array_pop($opts);
+ }
+
+ // Set shortOpts, longOpts attrs from 'opts' tuple.
+ // Have to be set now, in case no option strings are supplied.
+ $this->shortOpts = array();
+ $this->longOpts = array();
+ $opts = $this->_checkOptStrings($opts);
+ $this->_setOptStrings($opts);
+
+ // Set all other attrs (action, type, etc.) from 'attrs' dict
+ $this->_setAttrs($attrs);
+
+ // Check all the attributes we just set. There are lots of
+ // complicated interdependencies, but luckily they can be farmed
+ // out to the _check*() methods listed in CHECK_METHODS -- which
+ // could be handy for subclasses! The one thing these all share
+ // is that they raise OptionError if they discover a problem.
+ foreach ($this->CHECK_METHODS as $checker) {
+ call_user_func(array($this, $checker));
+ }
+ }
+
+ protected function _checkOptStrings($opts)
+ {
+ // Filter out None because early versions of Optik had exactly
+ // one short option and one long option, either of which
+ // could be None.
+ $opts = array_filter($opts);
+ if (!$opts) {
+ throw new InvalidArgumentException('at least one option string must be supplied');
+ }
+ return $opts;
+ }
+
+ protected function _setOptStrings($opts)
+ {
+ foreach ($opts as &$opt) {
+ $opt = (string)$opt;
+
+ if (strlen($opt) < 2) {
+ throw new Horde_Argv_OptionException(sprintf("invalid option string '%s': must be at least two characters long", $opt), $this);
+ } elseif (strlen($opt) == 2) {
+ if (!($opt[0] == "-" && $opt[1] != "-")) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "invalid short option string '%s': " .
+ "must be of the form -x, (x any non-dash char)", $opt), $this);
+ }
+ $this->shortOpts[] = $opt;
+ } else {
+ if (!(substr($opt, 0, 2) == '--' && $opt[2] != '-')) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "invalid long option string '%s': " .
+ "must start with --, followed by non-dash", $opt), $this);
+ }
+ $this->longOpts[] = $opt;
+ }
+ }
+ }
+
+ protected function _setAttrs($attrs)
+ {
+ foreach ($this->ATTRS as $attr) {
+ if (array_key_exists($attr, $attrs)) {
+ $this->$attr = $attrs[$attr];
+ unset($attrs[$attr]);
+ } else {
+ if ($attr == 'default') {
+ $this->$attr = self::$NO_DEFAULT;
+ } else {
+ $this->$attr = null;
+ }
+ }
+ }
+
+ if ($attrs) {
+ $attrs = array_keys($attrs);
+ sort($attrs);
+ throw new Horde_Argv_OptionException(sprintf(
+ "invalid keyword arguments: %s", implode(", ", $attrs)), $this);
+ }
+ }
+
+
+ // -- Constructor validation methods --------------------------------
+
+ public function _checkAction()
+ {
+ if (is_null($this->action)) {
+ $this->action = "store";
+ } elseif (!in_array($this->action, $this->ACTIONS)) {
+ throw new Horde_Argv_OptionException(sprintf("invalid action: '%s'", $this->action), $this);
+ }
+ }
+
+ public function _checkType()
+ {
+ if (is_null($this->type)) {
+ if (in_array($this->action, $this->ALWAYS_TYPED_ACTIONS)) {
+ if (!is_null($this->choices)) {
+ // The "choices" attribute implies "choice" type.
+ $this->type = "choice";
+ } else {
+ // No type given? "string" is the most sensible default.
+ $this->type = "string";
+ }
+ }
+ } else {
+ if ($this->type == "str") {
+ $this->type = "string";
+ }
+
+ if (!in_array($this->type, $this->TYPES)) {
+ throw new Horde_Argv_OptionException(sprintf("invalid option type: '%s'", $this->type), $this);
+ }
+
+ if (!in_array($this->action, $this->TYPED_ACTIONS)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "must not supply a type for action '%s'", $this->action), $this);
+ }
+ }
+ }
+
+ public function _checkChoice()
+ {
+ if ($this->type == "choice") {
+ if (is_null($this->choices)) {
+ throw new Horde_Argv_OptionException(
+ "must supply a list of choices for type 'choice'", $this);
+ } elseif (!(is_array($this->choices) || $this->choices instanceof Iterator)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "choices must be a list of strings ('%s' supplied)",
+ gettype($this->choices)), $this);
+ }
+ } elseif (!is_null($this->choices)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "must not supply choices for type '%s'", $this->type), $this);
+ }
+ }
+
+ public function _checkDest()
+ {
+ // No destination given, and we need one for this action. The
+ // $this->type check is for callbacks that take a value.
+ $takes_value = (in_array($this->action, $this->STORE_ACTIONS) ||
+ !is_null($this->type));
+ if (is_null($this->dest) && $takes_value) {
+ // Glean a destination from the first long option string,
+ // or from the first short option string if no long options.
+ if ($this->longOpts) {
+ // eg. "--foo-bar" -> "foo_bar"
+ $this->dest = str_replace('-', '_', substr($this->longOpts[0], 2));
+ } else {
+ $this->dest = $this->shortOpts[0][1];
+ }
+ }
+ }
+
+ public function _checkConst()
+ {
+ if (!in_array($this->action, $this->CONST_ACTIONS) && !is_null($this->const)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "'const' must not be supplied for action '%s'", $this->action),
+ $this);
+ }
+ }
+
+ public function _checkNargs()
+ {
+ if (in_array($this->action, $this->TYPED_ACTIONS)) {
+ if (is_null($this->nargs)) {
+ $this->nargs = 1;
+ }
+ } elseif (!is_null($this->nargs)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "'nargs' must not be supplied for action '%s'", $this->action),
+ $this);
+ }
+ }
+
+ public function _checkCallback()
+ {
+ if ($this->action == "callback") {
+ if (!is_callable($this->callback)) {
+ $callback_name = is_array($this->callback) ?
+ is_object($this->callback[0]) ? get_class($this->callback[0] . '#' . $this->callback[1]) : implode('#', $this->callback) :
+ $this->callback;
+ throw new Horde_Argv_OptionException(sprintf(
+ "callback not callable: '%s'", $callback_name), $this);
+ }
+ if (!is_null($this->callbackArgs) && !is_array($this->callbackArgs)) {
+ throw new Horde_Argv_OptionException(sprintf(
+ "callbackArgs, if supplied, must be an array: not '%s'",
+ $this->callbackArgs), $this);
+ }
+ } else {
+ if (!is_null($this->callback)) {
+ $callback_name = is_array($this->callback) ?
+ is_object($this->callback[0]) ? get_class($this->callback[0] . '#' . $this->callback[1]) : implode('#', $this->callback) :
+ $this->callback;
+ throw new Horde_Argv_OptionException(sprintf(
+ "callback supplied ('%s') for non-callback option",
+ $callback_name), $this);
+ }
+ if (!is_null($this->callbackArgs)) {
+ throw new Horde_Argv_OptionException(
+ "callbackArgs supplied for non-callback option", $this);
+ }
+ }
+ }
+
+
+ // -- Miscellaneous methods -----------------------------------------
+
+ public function __toString()
+ {
+ return implode('/', array_merge($this->shortOpts, $this->longOpts));
+ }
+
+ public function takesValue()
+ {
+ return !is_null($this->type);
+ }
+
+ public function getOptString()
+ {
+ if ($this->longOpts)
+ return $this->longOpts[0];
+ else
+ return $this->shortOpts[0];
+ }
+
+
+ // -- Processing methods --------------------------------------------
+
+ public function checkValue($opt, $value)
+ {
+ if (!isset($this->TYPE_CHECKER[$this->type])) {
+ return $value;
+ }
+ $checker = $this->TYPE_CHECKER[$this->type];
+ return call_user_func(array($this, $checker), $opt, $value);
+ }
+
+ public function convertValue($opt, $value)
+ {
+ if (!is_null($value)) {
+ if ($this->nargs == 1) {
+ return $this->checkValue($opt, $value);
+ } else {
+ $return = array();
+ foreach ($value as $v) {
+ $return[] = $this->checkValue($opt, $v);
+ }
+ return $return;
+ }
+ }
+ }
+
+ public function process($opt, $value, $values, $parser)
+ {
+ // First, convert the value(s) to the right type. Howl if any
+ // value(s) are bogus.
+ $value = $this->convertValue($opt, $value);
+
+ // And then take whatever action is expected of us.
+ // This is a separate method to make life easier for
+ // subclasses to add new actions.
+ return $this->takeAction(
+ $this->action, $this->dest, $opt, $value, $values, $parser);
+ }
+
+ public function takeAction($action, $dest, $opt, $value, $values, $parser)
+ {
+ if ($action == 'store')
+ $values->$dest = $value;
+ elseif ($action == 'store_const')
+ $values->$dest = $this->const;
+ elseif ($action == 'store_true')
+ $values->$dest = true;
+ elseif ($action == 'store_false')
+ $values->$dest = false;
+ elseif ($action == 'append') {
+ $values->{$dest}[] = $value;
+ } elseif ($action == 'append_const') {
+ $values->{$dest}[] = $this->const;
+ } elseif ($action == 'count') {
+ $values->ensureValue($dest, 0);
+ $values->$dest++;
+ } elseif ($action == 'callback') {
+ call_user_func($this->callback, $this, $opt, $value, $parser, $this->callbackArgs);
+ } elseif ($action == 'help') {
+ $parser->printHelp();
+ $parser->parserExit();
+ } elseif ($action == 'version') {
+ $parser->printVersion();
+ $parser->parserExit();
+ } else {
+ throw new RuntimeException('unknown action ' . $this->action);
+ }
+
+ return 1;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Raised if conflicting options are added to a Horde_Argv_Parser.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_OptionConflictException extends Horde_Argv_OptionException
+{}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Abstract base class.
+ *
+ * Class attributes:
+ * standardOptionList : [Option]
+ * list of standard options that will be accepted by all instances
+ * of this parser class (intended to be overridden by subclasses).
+ *
+ * Instance attributes:
+ * optionList : [Option]
+ * the list of Option objects contained by this OptionContainer
+ * shortOpt : { string : Option }
+ * dictionary mapping short option strings, eg. "-f" or "-X",
+ * to the Option instances that implement them. If an Option
+ * has multiple short option strings, it will appears in this
+ * dictionary multiple times. [1]
+ * longOpt : { string : Option }
+ * dictionary mapping long option strings, eg. "--file" or
+ * "--exclude", to the Option instances that implement them.
+ * Again, a given Option can occur multiple times in this
+ * dictionary. [1]
+ * defaults : { string : any }
+ * dictionary mapping option destination names to default
+ * values for each destination [1]
+ *
+ * [1] These mappings are common to (shared by) all components of the
+ * controlling Horde_Argv_Parser, where they are initially created.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_OptionContainer
+{
+ public $description = '';
+ public $optionList = array();
+ public $optionClass = 'Horde_Argv_Option';
+ public $defaults = array();
+ public $shortOpt = array();
+ public $longOpt = array();
+ public $conflictHandler;
+
+ /**
+ * Initialize the option list and related data structures.
+ * This method must be provided by subclasses, and it must
+ * initialize at least the following instance attributes:
+ * optionList, shortOpt, longOpt, defaults.
+ */
+ public function __construct($optionClass, $conflictHandler, $description)
+ {
+ $this->_createOptionList();
+
+ $this->optionClass = $optionClass;
+ $this->setConflictHandler($conflictHandler);
+ $this->setDescription($description);
+ }
+
+ /**
+ * For use by Horde_Argv_Parser constructor -- create the master
+ * option mappings used by this Horde_Argv_Parser and all
+ * OptionGroups that it owns.
+ */
+ protected function _createOptionMappings()
+ {
+ $this->shortOpt = array(); // single letter -> Option instance
+ $this->longOpt = array(); // long option -> Option instance
+ $this->defaults = array(); // maps option dest -> default value
+ }
+
+ /**
+ * For use by OptionGroup constructor -- use shared option
+ * mappings from the Horde_Argv_Parser that owns this OptionGroup.
+ */
+ protected function _shareOptionMappings($parser)
+ {
+ $this->shortOpt =& $parser->shortOpt;
+ $this->longOpt =& $parser->longOpt;
+ $this->defaults = $parser->defaults;
+ }
+
+ public function setConflictHandler($handler)
+ {
+ if (!in_array($handler, array('error', 'resolve'))) {
+ throw new InvalidArgumentException('invalid conflictHandler ' . var_export($handler, true));
+ }
+ $this->conflictHandler = $handler;
+ }
+
+ public function setDescription($description)
+ {
+ $this->description = $description;
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ // -- Option-adding methods -----------------------------------------
+
+ protected function _checkConflict($option)
+ {
+ $conflictOpts = array();
+ foreach ($option->shortOpts as $opt) {
+ if (isset($this->shortOpt[$opt])) {
+ $conflictOpts[$opt] = $this->shortOpt[$opt];
+ }
+ }
+ foreach ($option->longOpts as $opt) {
+ if (isset($this->longOpt[$opt])) {
+ $conflictOpts[$opt] = $this->longOpt[$opt];
+ }
+ }
+
+ if ($conflictOpts) {
+ $handler = $this->conflictHandler;
+ if ($handler == 'error') {
+ throw new Horde_Argv_OptionConflictException(sprintf(
+ 'conflicting option string(s): %s',
+ implode(', ', array_keys($conflictOpts))), $option);
+ } elseif ($handler == 'resolve') {
+ foreach ($conflictOpts as $opt => $c_option) {
+ if (strncmp($opt, '--', 2) === 0) {
+ $key = array_search($opt, $c_option->longOpts);
+ if ($key !== false) {
+ unset($c_option->longOpts[$key]);
+ }
+ unset($this->longOpt[$opt]);
+ } else {
+ $key = array_search($opt, $c_option->shortOpts);
+ if ($key !== false) {
+ unset($c_option->shortOpts[$key]);
+ }
+ unset($this->shortOpt[$opt]);
+ }
+
+ if (! ($c_option->shortOpts || $c_option->longOpts)) {
+ $key = array_search($c_option, $c_option->container->optionList);
+ unset($c_option->container->optionList[$key]);
+ }
+ }
+ }
+ }
+ }
+
+ public function addOption()
+ {
+ $opts = func_get_args();
+
+ if (count($opts) && is_string($opts[0])) {
+ $optionFactory = new ReflectionClass($this->optionClass);
+ $option = $optionFactory->newInstanceArgs($opts);
+ } elseif (count($opts) == 1) {
+ $option = $opts[0];
+ if (!$option instanceof Horde_Argv_Option)
+ throw new InvalidArgumentException('not an Option instance: ' . var_export($option, true));
+ } else {
+ throw new InvalidArgumentException('invalid arguments');
+ }
+
+ $this->_checkConflict($option);
+
+ $this->optionList[] = $option;
+ $option->container = $this;
+ foreach ($option->shortOpts as $opt) {
+ $this->shortOpt[$opt] = $option;
+ }
+ foreach ($option->longOpts as $opt) {
+ $this->longOpt[$opt] = $option;
+ }
+
+ if (!is_null($option->dest)) {
+ // option has a dest, we need a default
+ if ($option->default !== Horde_Argv_Option::$NO_DEFAULT) {
+ $this->defaults[$option->dest] = $option->default;
+ } elseif (!isset($this->defaults[$option->dest])) {
+ $this->defaults[$option->dest] = null;
+ }
+ }
+
+ return $option;
+ }
+
+ public function addOptions($optionList)
+ {
+ foreach ($optionList as $option) {
+ $this->addOption($option);
+ }
+ }
+
+ // -- Option query/removal methods ----------------------------------
+
+ public function getOption($opt_str)
+ {
+ if (isset($this->shortOpt[$opt_str])) {
+ return $this->shortOpt[$opt_str];
+ } elseif (isset($this->longOpt[$opt_str])) {
+ return $this->longOpt[$opt_str];
+ } else {
+ return null;
+ }
+ }
+
+ public function hasOption($opt_str)
+ {
+ return isset($this->shortOpt[$opt_str])
+ || isset($this->longOpt[$opt_str]);
+ }
+
+ public function removeOption($opt_str)
+ {
+ $option = $this->getOption($opt_str);
+ if (is_null($option))
+ throw new InvalidArgumentException("no such option '$opt_str'");
+
+ foreach ($option->shortOpts as $opt) {
+ unset($this->shortOpt[$opt]);
+ }
+ foreach ($option->longOpts as $opt) {
+ unset($this->longOpt[$opt]);
+ }
+ $key = array_search($option, $option->container->optionList);
+ unset($option->container->optionList[$key]);
+ }
+
+
+ // -- Help-formatting methods ---------------------------------------
+
+ public function formatOptionHelp($formatter = null)
+ {
+ if (!$this->optionList)
+ return '';
+ $result = array();
+ foreach ($this->optionList as $option) {
+ if ($option->help != Horde_Argv_Option::SUPPRESS_HELP)
+ $result[] = $formatter->formatOption($option);
+ }
+ return implode('', $result);
+ }
+
+ public function formatDescription($formatter = null)
+ {
+ return $formatter->formatDescription($this->getDescription());
+ }
+
+ public function formatHelp($formatter = null)
+ {
+ $result = array();
+ if ($this->description)
+ $result[] = $this->formatDescription($formatter);
+ if ($this->optionList)
+ $result[] = $this->formatOptionHelp($formatter);
+ return implode("\n", $result);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Raised if an Option instance is created with invalid or
+ * inconsistent arguments.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_OptionException extends Horde_Argv_Exception
+{
+ public function __construct($msg, $option = null)
+ {
+ $this->optionId = (string)$option;
+ if ($this->optionId) {
+ parent::__construct(sprintf(_("option %s: %s"), $this->optionId, $msg));
+ } else {
+ parent::__construct($msg);
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_OptionGroup extends Horde_Argv_OptionContainer
+{
+ protected $_title;
+
+ public function __construct($parser, $title, $description = null)
+ {
+ $this->parser = $parser;
+ parent::__construct($parser->optionClass, $parser->conflictHandler, $description);
+ $this->_title = $title;
+ }
+
+ protected function _createOptionList()
+ {
+ $this->optionList = array();
+ $this->_shareOptionMappings($this->parser);
+ }
+
+ public function setTitle($title)
+ {
+ $this->_title = $title;
+ }
+
+ public function __destruct()
+ {
+ unset($this->optionList);
+ }
+
+ // -- Help-formatting methods ---------------------------------------
+
+ public function formatHelp($formatter = null)
+ {
+ if (is_null($formatter))
+ return '';
+
+ $result = $formatter->formatHeading($this->_title);
+ $formatter->indent();
+ $result .= parent::formatHelp($formatter);
+ $formatter->dedent();
+ return $result;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Raised if an invalid option value is encountered on the command
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_OptionValueException extends Horde_Argv_OptionException
+{}
--- /dev/null
+<?php
+/**
+ * Horde command-line argument parsing package.
+ *
+ * This package is ported from Python's Optik (http://optik.sourceforge.net/).
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Class attributes:
+ * standardOptionList : [Option]
+ * list of standard options that will be accepted by all instances
+ * of this parser class (intended to be overridden by subclasses).
+ *
+ * Instance attributes:
+ * usage : string
+ * a usage string for your program. Before it is displayed
+ * to the user, "%prog" will be expanded to the name of
+ * your program ($this->prog or os.path.basename(sys.argv[0])).
+ * prog : string
+ * the name of the current program (to override
+ * os.path.basename(sys.argv[0])).
+ * epilog : string
+ * paragraph of help text to print after option help
+ *
+ * optionGroups : [OptionGroup]
+ * list of option groups in this parser (option groups are
+ * irrelevant for parsing the command-line, but very useful
+ * for generating help)
+ *
+ * allow_interspersed_args : bool = true
+ * if true, positional arguments may be interspersed with options.
+ * Assuming -a and -b each take a single argument, the command-line
+ * -ablah foo bar -bboo baz
+ * will be interpreted the same as
+ * -ablah -bboo -- foo bar baz
+ * If this flag were false, that command line would be interpreted as
+ * -ablah -- foo bar -bboo baz
+ * -- ie. we stop processing options as soon as we see the first
+ * non-option argument. (This is the tradition followed by
+ * Python's getopt module, Perl's Getopt::Std, and other argument-
+ * parsing libraries, but it is generally annoying to users.)
+ *
+ * rargs : [string]
+ * the argument list currently being parsed. Only set when
+ * parseArgs() is active, and continually trimmed down as
+ * we consume arguments. Mainly there for the benefit of
+ * callback options.
+ * largs : [string]
+ * the list of leftover arguments that we have skipped while
+ * parsing options. If allow_interspersed_args is false, this
+ * list is always empty.
+ * values : Values
+ * the set of option values currently being accumulated. Only
+ * set when parseArgs() is active. Also mainly for callbacks.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_Parser extends Horde_Argv_OptionContainer
+{
+ public $standardOptionList = array();
+
+ protected $_usage;
+ public $optionGroups = array();
+
+ public function __construct($args = array())
+ {
+ $args = array_merge(array(
+ 'usage' => null,
+ 'optionList' => null,
+ 'optionClass' => 'Horde_Argv_Option',
+ 'version' => null,
+ 'conflictHandler' => "error",
+ 'description' => null,
+ 'formatter' => null,
+ 'addHelpOption' => true,
+ 'prog' => null,
+ 'epilog' => null),
+ $args);
+
+ parent::__construct($args['optionClass'], $args['conflictHandler'], $args['description']);
+ $this->setUsage($args['usage']);
+ $this->prog = $args['prog'];
+ $this->version = $args['version'];
+ $this->allow_interspersed_args = true;
+ if (is_null($args['formatter']))
+ $args['formatter'] = new Horde_Argv_IndentedHelpFormatter();
+ $this->formatter = $args['formatter'];
+ $this->formatter->setParser($this);
+ $this->epilog = $args['epilog'];
+
+ // Populate the option list; initial sources are the
+ // standardOptionList class attribute, the 'optionList'
+ // argument, and (if applicable) the _addVersionOption() and
+ // _addHelpOption() methods.
+ $this->_populateOptionList($args['optionList'],
+ $args['addHelpOption']);
+
+ $this->_initParsingState();
+ }
+
+ /**
+ * Declare that you are done with this Horde_Argv_Parser. This cleans up
+ * reference cycles so the Horde_Argv_Parser (and all objects referenced by
+ * it) can be garbage-collected promptly. After calling destroy(), the
+ * Horde_Argv_Parser is unusable.
+ */
+ public function __destruct()
+ {
+ foreach ($this->optionGroups as &$group) {
+ unset($group);
+ }
+
+ unset($this->optionList);
+ unset($this->optionGroups);
+ unset($this->formatter);
+ }
+
+ // -- Private methods -----------------------------------------------
+ // (used by our or OptionContainer's constructor)
+
+ protected function _createOptionList()
+ {
+ $this->optionList = array();
+ $this->optionGroups = array();
+ $this->_createOptionMappings();
+ }
+
+ protected function _addHelpOption()
+ {
+ $this->addOption('-h', '--help', array('action' => 'help',
+ 'help' => _("show this help message and exit")));
+ }
+
+ protected function _addVersionOption()
+ {
+ $this->addOption('--version', array('action' => 'version',
+ 'help' => _("show program's version number and exit")));
+ }
+
+ protected function _populateOptionList($optionList, $add_help = true)
+ {
+ if ($this->standardOptionList)
+ $this->addOptions($this->standardOptionList);
+ if ($optionList)
+ $this->addOptions($optionList);
+ if ($this->version)
+ $this->_addVersionOption();
+ if ($add_help)
+ $this->_addHelpOption();
+ }
+
+ protected function _initParsingState()
+ {
+ // These are set in parseArgs() for the convenience of callbacks.
+ $this->rargs = null;
+ $this->largs = null;
+ $this->values = null;
+ }
+
+ // -- Simple modifier methods ---------------------------------------
+
+ public function setUsage($usage)
+ {
+ if (is_null($usage))
+ $this->_usage = '%prog ' . _("[options]");
+ elseif ($usage == Horde_Argv_Option::SUPPRESS_USAGE)
+ $this->_usage = null;
+ else
+ $this->_usage = $usage;
+ }
+
+ public function enableInterspersedArgs()
+ {
+ $this->allow_interspersed_args = true;
+ }
+
+ public function disableInterspersedArgs()
+ {
+ $this->allow_interspersed_args = false;
+ }
+
+ public function setDefault($dest, $value)
+ {
+ $this->defaults[$dest] = $value;
+ }
+
+ public function setDefaults($defaults)
+ {
+ $this->defaults = array_merge($this->defaults, $defaults);
+ }
+
+ protected function _getAllOptions()
+ {
+ $options = $this->optionList;
+ foreach ($this->optionGroups as $group) {
+ $options = array_merge($options, $group->optionList);
+ }
+ return $options;
+ }
+
+ public function getDefaultValues()
+ {
+ $defaults = $this->defaults;
+ foreach ($this->_getAllOptions() as $option) {
+ $default = isset($defaults[$option->dest]) ? $defaults[$option->dest] : null;
+ if (is_string($default)) {
+ $opt_str = $option->getOptString();
+ $defaults[$option->dest] = $option->checkValue($opt_str, $default);
+ }
+ }
+
+ return new Horde_Argv_Values($defaults);
+ }
+
+
+ // -- OptionGroup methods -------------------------------------------
+
+ public function addOptionGroup()
+ {
+ // XXX lots of overlap with OptionContainer::addOption()
+ $args = func_get_args();
+
+ if (count($args) && is_string($args[0])) {
+ $groupFactory = new ReflectionClass('Horde_Argv_OptionGroup');
+ array_unshift($args, $this);
+ $group = $groupFactory->newInstanceArgs($args);
+ } elseif (count($args) == 1) {
+ $group = $args[0];
+ if (!$group instanceof Horde_Argv_OptionGroup)
+ throw new InvalidArgumentException("not an OptionGroup instance: " . var_export($group, true));
+ if ($group->parser !== $this)
+ throw new InvalidArgumentException("invalid OptionGroup (wrong parser)");
+ } else {
+ throw new InvalidArgumentException('invalid arguments');
+ }
+
+ $this->optionGroups[] = $group;
+ return $group;
+ }
+
+ public function getOptionGroup($opt_str)
+ {
+ if (isset($this->shortOpt[$opt_str])) {
+ $option = $this->shortOpt[$opt_str];
+ } elseif (isset($this->longOpt[$opt_str])) {
+ $option = $this->longOpt[$opt_str];
+ } else {
+ return null;
+ }
+
+ if ($option->container !== $this) {
+ return $option->container;
+ }
+
+ return null;
+ }
+
+ // -- Option-parsing methods ----------------------------------------
+
+ protected function _getArgs($args = null)
+ {
+ if (is_null($args)) {
+ $args = $_SERVER['argv'];
+ array_shift($args);
+ return $args;
+ } else {
+ return $args;
+ }
+ }
+
+ /**
+ * Parse the command-line options found in 'args' (default:
+ * sys.argv[1:]). Any errors result in a call to 'parserError()', which
+ * by default prints the usage message to stderr and calls
+ * exit() with an error message. On success returns a pair
+ * (values, args) where 'values' is an Values instance (with all
+ * your option values) and 'args' is the list of arguments left
+ * over after parsing options.
+ */
+ public function parseArgs($args = null, $values = null)
+ {
+ $rargs = $this->_getArgs($args);
+ $largs = array();
+ if (is_null($values))
+ $values = $this->getDefaultValues();
+
+ // Store the halves of the argument list as attributes for the
+ // convenience of callbacks:
+ // rargs
+ // the rest of the command-line (the "r" stands for
+ // "remaining" or "right-hand")
+ // largs
+ // the leftover arguments -- ie. what's left after removing
+ // options and their arguments (the "l" stands for "leftover"
+ // or "left-hand")
+ $this->rargs =& $rargs;
+ $this->largs =& $largs;
+ $this->values = $values;
+
+ try {
+ $this->_processArgs($largs, $rargs, $values);
+ } catch (Horde_Argv_BadOptionException $e) {
+ $this->parserError($e->getMessage());
+ } catch (Horde_Argv_OptionValueException $e) {
+ $this->parserError($e->getMessage());
+ }
+
+ $args = array_merge($largs, $rargs);
+ return $this->checkValues($values, $args);
+ }
+
+ /**
+ * Check that the supplied option values and leftover arguments are
+ * valid. Returns the option values and leftover arguments
+ * (possibly adjusted, possibly completely new -- whatever you
+ * like). Default implementation just returns the passed-in
+ * values; subclasses may override as desired.
+ */
+ public function checkValues($values, $args)
+ {
+ return array($values, $args);
+ }
+
+ /**
+ * _process_args(largs : [string],
+ * rargs : [string],
+ * values : Values)
+ *
+ * Process command-line arguments and populate 'values', consuming
+ * options and arguments from 'rargs'. If 'allow_interspersed_args' is
+ * false, stop at the first non-option argument. If true, accumulate any
+ * interspersed non-option arguments in 'largs'.
+ */
+ protected function _processArgs(&$largs, &$rargs, &$values)
+ {
+ while ($rargs) {
+ $arg = $rargs[0];
+ // We handle bare "--" explicitly, and bare "-" is handled by the
+ // standard arg handler since the short arg case ensures that the
+ // len of the opt string is greater than 1.
+ if ($arg == '--') {
+ array_shift($rargs);
+ return;
+ } elseif (substr($arg, 0, 2) == '--') {
+ // process a single long option (possibly with value(s))
+ $this->_processLongOpt($rargs, $values);
+ } elseif (substr($arg, 0, 1) == '-' && strlen($arg) > 1) {
+ // process a cluster of short options (possibly with
+ // value(s) for the last one only)
+ $this->_processShortOpts($rargs, $values);
+ } elseif ($this->allow_interspersed_args) {
+ $largs[] = $arg;
+ array_shift($rargs);
+ } else {
+ // stop now, leave this arg in rargs
+ return;
+ }
+ }
+
+ // Say this is the original argument list:
+ // [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
+ // ^
+ // (we are about to process arg(i)).
+ //
+ // Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
+ // [arg0, ..., arg(i-1)] (any options and their arguments will have
+ // been removed from largs).
+ //
+ // The while loop will usually consume 1 or more arguments per pass.
+ // If it consumes 1 (eg. arg is an option that takes no arguments),
+ // then after _process_arg() is done the situation is:
+ //
+ // largs = subset of [arg0, ..., arg(i)]
+ // rargs = [arg(i+1), ..., arg(N-1)]
+ //
+ // If allow_interspersed_args is false, largs will always be
+ // *empty* -- still a subset of [arg0, ..., arg(i-1)], but
+ // not a very interesting subset!
+ }
+
+ /**
+ * opt : string) -> string
+ *
+ * Determine which long option string 'opt' matches, ie. which one
+ * it is an unambiguous abbrevation for. Raises BadOptionError if
+ * 'opt' doesn't unambiguously match any long option string.
+ */
+ protected function _matchLongOpt($opt)
+ {
+ return self::matchAbbrev($opt, $this->longOpt);
+ }
+
+ /**
+ * (s : string, wordmap : {string : Option}) -> string
+ *
+ * Return the string key in 'wordmap' for which 's' is an unambiguous
+ * abbreviation. If 's' is found to be ambiguous or doesn't match any of
+ * 'words', raise BadOptionError.
+ */
+ public static function matchAbbrev($s, $wordmap)
+ {
+ // Is there an exact match?
+ if (array_key_exists($s, $wordmap)) {
+ return $s;
+ }
+
+ // Isolate all words with s as a prefix.
+ $possibilities = array();
+ foreach (array_keys($wordmap) as $word) {
+ if (strncmp($word, $s, strlen($s)) === 0) {
+ $possibilities[] = $word;
+ }
+ }
+
+ // No exact match, so there had better be just one possibility.
+ if (count($possibilities) == 1) {
+ return $possibilities[0];
+ } elseif (!$possibilities) {
+ throw new Horde_Argv_BadOptionException($s);
+ } else {
+ // More than one possible completion: ambiguous prefix.
+ sort($possibilities);
+ throw new Horde_Argv_AmbiguousOptionException($s, $possibilities);
+ }
+ }
+
+ protected function _processLongOpt(&$rargs, &$values)
+ {
+ $arg = array_shift($rargs);
+
+ // Value explicitly attached to arg? Pretend it's the next
+ // argument.
+ if (strpos($arg, '=') !== false) {
+ list($opt, $next_arg) = explode('=', $arg, 2);
+ array_unshift($rargs, $next_arg);
+ $had_explicit_value = true;
+ } else {
+ $opt = $arg;
+ $had_explicit_value = false;
+ }
+
+ $opt = $this->_matchLongOpt($opt);
+ $option = $this->longOpt[$opt];
+ if ($option->takesValue()) {
+ $nargs = $option->nargs;
+ if (count($rargs) < $nargs) {
+ if ($nargs == 1)
+ $this->parserError(sprintf(_("%s option requires an argument"), $opt));
+ else
+ $this->parserError(sprintf(_("%s option requires %d arguments"),
+ $opt, $nargs));
+ } elseif ($nargs == 1) {
+ $value = array_shift($rargs);
+ } else {
+ $value = array_splice($rargs, 0, $nargs);
+ }
+
+ } elseif ($had_explicit_value) {
+ $this->parserError(sprintf(_("%s option does not take a value"), $opt));
+
+ } else {
+ $value = null;
+ }
+
+ $option->process($opt, $value, $values, $this);
+ }
+
+ protected function _processShortOpts(&$rargs, &$values)
+ {
+ $arg = array_shift($rargs);
+ $stop = false;
+ $i = 1;
+ for ($c = 1, $c_max = strlen($arg); $c < $c_max; $c++) {
+ $ch = $arg[$c];
+ $opt = '-' . $ch;
+ $option = isset($this->shortOpt[$opt]) ? $this->shortOpt[$opt] : null;
+ $i++; // we have consumed a character
+
+ if (!$option)
+ throw new Horde_Argv_BadOptionException($opt);
+
+ if ($option->takesValue()) {
+ // Any characters left in arg? Pretend they're the
+ // next arg, and stop consuming characters of arg.
+ if ($i < strlen($arg)) {
+ array_unshift($rargs, substr($arg, $i));
+ $stop = true;
+ }
+
+ $nargs = $option->nargs;
+ if (count($rargs) < $nargs) {
+ if ($nargs == 1)
+ $this->parserError(sprintf(_("%s option requires an argument"), $opt));
+ else
+ $this->parserError(sprintf(_("%s option requires %d arguments"), $opt, $nargs));
+
+ } elseif ($nargs == 1) {
+ $value = array_shift($rargs);
+ } else {
+ $value = array_splice($rargs, 0, $nargs);
+ }
+
+ } else {
+ // option doesn't take a value
+ $value = null;
+ }
+
+ $option->process($opt, $value, $values, $this);
+
+ if ($stop)
+ break;
+ }
+ }
+
+ // -- Feedback methods ----------------------------------------------
+
+ public function getProgName()
+ {
+ if (is_null($this->prog))
+ return basename($_SERVER['argv'][0]);
+ else
+ return $this->prog;
+ }
+
+ public function expandProgName($s)
+ {
+ return str_replace("%prog", $this->getProgName(), $s);
+ }
+
+ public function getDescription()
+ {
+ return $this->expandProgName($this->description);
+ }
+
+ public function parserExit($status = 0, $msg = null)
+ {
+ if ($msg)
+ fwrite(STDERR, $msg);
+ exit($status);
+ }
+
+ /**
+ * Print a usage message incorporating $msg to stderr and exit.
+ * If you override this in a subclass, it should not return -- it
+ * should either exit or raise an exception.
+ *
+ * @param string $msg
+ */
+ public function parserError($msg)
+ {
+ $this->printUsage(STDERR);
+ $this->parserExit(2, sprintf("%s: error: %s\n", $this->getProgName(), $msg));
+ }
+
+ public function getUsage($formatter = null)
+ {
+ if (is_null($formatter))
+ $formatter = $this->formatter;
+ if ($this->_usage)
+ return $formatter->formatUsage($this->expandProgName($this->_usage));
+ else
+ return '';
+ }
+
+ /**
+ * (file : file = stdout)
+ *
+ * Print the usage message for the current program ($this->_usage) to
+ * 'file' (default stdout). Any occurence of the string "%prog" in
+ * $this->_usage is replaced with the name of the current program
+ * (basename of sys.argv[0]). Does nothing if $this->_usage is empty
+ * or not defined.
+ */
+ public function printUsage($file = null)
+ {
+ if (!$this->_usage)
+ return;
+
+ if (is_null($file))
+ echo $this->getUsage();
+ else
+ fwrite($file, $this->getUsage());
+ }
+
+ public function getVersion()
+ {
+ if ($this->version)
+ return $this->expandProgName($this->version);
+ else
+ return '';
+ }
+
+ /**
+ * file : file = stdout
+ *
+ * Print the version message for this program ($this->version) to
+ * 'file' (default stdout). As with printUsage(), any occurence
+ * of "%prog" in $this->version is replaced by the current program's
+ * name. Does nothing if $this->version is empty or undefined.
+ */
+ public function printVersion($file = null)
+ {
+ if (!$this->version)
+ return;
+
+ if (is_null($file))
+ echo $this->getVersion() . "\n";
+ else
+ fwrite($file, $this->getVersion() . "\n");
+ }
+
+ public function formatOptionHelp($formatter = null)
+ {
+ if (is_null($formatter))
+ $formatter = $this->formatter;
+ $formatter->storeOptionStrings($this);
+ $result = array();
+ $result[] = $formatter->formatHeading(_("Options"));
+ $formatter->indent();
+ if ($this->optionList) {
+ $result[] = parent::formatOptionHelp($formatter);
+ $result[] = "\n";
+ }
+ foreach ($this->optionGroups as $group) {
+ $result[] = $group->formatHelp($formatter);
+ $result[] = "\n";
+ }
+ $formatter->dedent();
+ // Drop the last "\n", or the header if no options or option groups:
+ array_pop($result);
+ return implode('', $result);
+ }
+
+ public function formatEpilog($formatter)
+ {
+ return $formatter->formatEpilog($this->epilog);
+ }
+
+ public function formatHelp($formatter = null)
+ {
+ if (is_null($formatter))
+ $formatter = $this->formatter;
+ $result = array();
+ if ($this->_usage)
+ $result[] = $this->getUsage($formatter) . "\n";
+ if ($this->description)
+ $result[] = $this->formatDescription($formatter) . "\n";
+ $result[] = $this->formatOptionHelp($formatter);
+ $result[] = $this->formatEpilog($formatter);
+ return implode('', $result);
+ }
+
+ /**
+ * file : file = stdout
+ *
+ * Print an extended help message, listing all options and any
+ * help text provided with them, to 'file' (default stdout).
+ */
+ public function printHelp($file = null)
+ {
+ if (is_null($file))
+ echo $this->formatHelp();
+ else
+ fwrite($file, $this->formatHelp());
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Format help with underlined section headers.
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_TitledHelpFormatter extends Horde_Argv_HelpFormatter
+{
+ public function __construct(
+ $indent_increment = 0,
+ $max_help_position = 24,
+ $width = null,
+ $short_first = false)
+ {
+ parent::__construct($indent_increment, $max_help_position, $width, $short_first);
+ }
+
+ public function formatUsage($usage)
+ {
+ return sprintf("%s %s\n", $this->formatHeading(_("Usage")), $usage);
+ }
+
+ public function formatHeading($heading)
+ {
+ $prefix = array('=', '-');
+ return sprintf("%s\n%s\n", $heading, str_repeat($prefix[$this->level], strlen($heading)));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ */
+
+/**
+ * Result hash for Horde_Argv_Parser
+ *
+ * @category Horde
+ * @package Horde_Argv
+ */
+class Horde_Argv_Values implements IteratorAggregate, ArrayAccess, Countable
+{
+ public function __construct($defaults = array())
+ {
+ foreach ($defaults as $attr => $val) {
+ $this->$attr = $val;
+ }
+ }
+
+ public function __toString()
+ {
+ $str = array();
+ foreach ($this as $attr => $val) {
+ $str[] = $attr . ': ' . (string)$val;
+ }
+ return implode(', ', $str);
+ }
+
+ public function offsetExists($attr)
+ {
+ return !is_null($this->$attr);
+ }
+
+ public function offsetGet($attr)
+ {
+ return $this->$attr;
+ }
+
+ public function offsetSet($attr, $val)
+ {
+ $this->$attr = $val;
+ }
+
+ public function offsetUnset($attr)
+ {
+ unset($this->$attr);
+ }
+
+ public function getIterator()
+ {
+ return new ArrayIterator(get_object_vars($this));
+ }
+
+ public function count()
+ {
+ return count(get_object_vars($this));
+ }
+
+ public function ensureValue($attr, $value)
+ {
+ if (is_null($this->$attr)) {
+ $this->$attr = $value;
+ }
+ return $this->$attr;
+ }
+
+}
--- /dev/null
+D/Argv////
--- /dev/null
+framework/Argv/lib/Horde
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Argv</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde command-line argument parsing package</summary>
+ <description>This package provides classes for parsing command line
+ arguments with various actions, providing help, grouping options, and
+ more.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Mike Naberezny</name>
+ <user>mnaberez</user>
+ <email>mike@maintainable.com</email>
+ <active>yes</active>
+ </lead>
+ <date>2008-01-31</date>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>
+ * Initial release, ported from Optik (http://optik.sourceforge.net/)
+ </notes>
+ <contents>
+ <dir name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <dir name="Argv">
+ <file name="AmbiguousOptionException.php" role="php" />
+ <file name="BadOptionException.php" role="php" />
+ <file name="Exception.php" role="php" />
+ <file name="HelpFormatter.php" role="php" />
+ <file name="IndentedHelpFormatter.php" role="php" />
+ <file name="Option.php" role="php" />
+ <file name="OptionConflictException.php" role="php" />
+ <file name="OptionContainer.php" role="php" />
+ <file name="OptionException.php" role="php" />
+ <file name="OptionGroup.php" role="php" />
+ <file name="OptionValueException.php" role="php" />
+ <file name="Parser.php" role="php" />
+ <file name="TitledHelpFormatter.php" role="php" />
+ <file name="Values.php" role="php" />
+ </dir> <!-- /lib/Horde/Argv -->
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.1.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.5.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="lib/Horde/Argv/AmbiguousOptionException.php" as="Horde/Argv/AmbiguousOptionException.php" />
+ <install name="lib/Horde/Argv/BadOptionException.php" as="Horde/Argv/BadOptionException.php" />
+ <install name="lib/Horde/Argv/Exception.php" as="Horde/Argv/Exception.php" />
+ <install name="lib/Horde/Argv/HelpFormatter.php" as="Horde/Argv/HelpFormatter.php" />
+ <install name="lib/Horde/Argv/IndentedHelpFormatter.php" as="Horde/Argv/IndentedHelpFormatter.php" />
+ <install name="lib/Horde/Argv/Option.php" as="Horde/Argv/Option.php" />
+ <install name="lib/Horde/Argv/OptionConflictException.php" as="Horde/Argv/OptionConflictException.php" />
+ <install name="lib/Horde/Argv/OptionContainer.php" as="Horde/Argv/OptionContainer.php" />
+ <install name="lib/Horde/Argv/OptionException.php" as="Horde/Argv/OptionException.php" />
+ <install name="lib/Horde/Argv/OptionGroup.php" as="Horde/Argv/OptionGroup.php" />
+ <install name="lib/Horde/Argv/OptionValueException.php" as="Horde/Argv/OptionValueException.php" />
+ <install name="lib/Horde/Argv/Parser.php" as="Horde/Argv/Parser.php" />
+ <install name="lib/Horde/Argv/TitledHelpFormatter.php" as="Horde/Argv/TitledHelpFormatter.php" />
+ <install name="lib/Horde/Argv/Values.php" as="Horde/Argv/Values.php" />
+ </filelist>
+ </phprelease>
+</package>
--- /dev/null
+D/Horde////
--- /dev/null
+framework/Argv/test
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+<?php
+/**
+ * Horde_Argv test suite
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'Horde_Argv_AllTests::main');
+}
+
+require_once 'PHPUnit/Framework/TestSuite.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+/**
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+class Horde_Argv_AllTests {
+
+ public static function main()
+ {
+ PHPUnit_TextUI_TestRunner::run(self::suite());
+ }
+
+ public static function suite()
+ {
+ // Catch strict standards
+ error_reporting(E_ALL | E_STRICT);
+
+ // Set up autoload
+ set_include_path(dirname(dirname(dirname(dirname(__FILE__)))) . DIRECTORY_SEPARATOR . 'lib' . PATH_SEPARATOR . get_include_path());
+ if (!spl_autoload_functions()) {
+ spl_autoload_register(create_function('$class', '$filename = str_replace(array(\'::\', \'_\'), \'/\', $class); include "$filename.php";'));
+ }
+
+ // Test base classes and helper objects
+ require_once dirname(__FILE__) . '/TestBase.php';
+ require_once dirname(__FILE__) . '/ConflictTestBase.php';
+ require_once dirname(__FILE__) . '/InterceptedException.php';
+ require_once dirname(__FILE__) . '/InterceptingParser.php';
+
+ $suite = new PHPUnit_Framework_TestSuite('Horde Framework - Horde_Argv');
+
+ $basedir = dirname(__FILE__);
+ $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+ if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+ $pathname = $file->getPathname();
+ require $pathname;
+
+ $class = str_replace(DIRECTORY_SEPARATOR, '_',
+ preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+ $suite->addTestSuite('Horde_Argv_' . $class);
+ }
+ }
+
+ return $suite;
+ }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Horde_Argv_AllTests::main') {
+ Horde_Argv_AllTests::main();
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_BoolTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-v', '--verbose',
+ array('action' => 'store_true', 'dest' => 'verbose', 'default' => '')),
+ $this->makeOption('-q', '--quiet',
+ array('action' => 'store_false', 'dest' => 'verbose'))
+ );
+
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function testBoolDefault()
+ {
+ $this->assertParseOk(array(),
+ array('verbose' => ''),
+ array());
+ }
+
+ public function testBoolFalse()
+ {
+ list($options, $args) = $this->assertParseOk(array('-q'),
+ array('verbose' => false),
+ array());
+
+ $this->assertSame(false, $options->verbose);
+ }
+
+ public function testBoolTrue()
+ {
+ list($options, $args) = $this->assertParseOk(array('-v'),
+ array('verbose' => true),
+ array());
+ $this->assertSame(true, $options->verbose);
+ }
+
+ public function testBoolFlickerOnAndOff()
+ {
+ $this->assertParseOk(array('-qvq', '-q', '-v'),
+ array('verbose' => true),
+ array());
+ }
+
+}
--- /dev/null
+/AllTests.php/1.3/Wed Jun 18 19:00:45 2008//
+/BoolTest.php/1.2/Wed Jun 18 19:00:45 2008//
+/CallbackCheckAbbrevTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CallbackExtraArgsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CallbackManyArgsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CallbackMeddleArgsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CallbackTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CallbackVarArgsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ChoiceTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ConflictOverrideTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ConflictResolveTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ConflictTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ConflictTestBase.php/1.2/Wed Jun 18 19:00:46 2008//
+/ConflictingDefaultsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/CountTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/DefaultValuesTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ExpandDefaultsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ExtendAddActionsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ExtendAddTypesTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/HelpTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/InterceptedException.php/1.2/Wed Jun 18 19:00:46 2008//
+/InterceptingParser.php/1.2/Wed Jun 18 19:00:46 2008//
+/MatchAbbrevTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/MultipleArgsAppendTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/MultipleArgsTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/OptionChecksTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/OptionGroupTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/OptionValuesTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ParseNumTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ParserTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/ProgNameTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/StandardTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/TestBase.php/1.2/Wed Jun 18 19:00:46 2008//
+/TypeAliasesTest.php/1.2/Wed Jun 18 19:00:46 2008//
+/VersionTest.php/1.2/Wed Jun 18 19:00:46 2008//
+D
--- /dev/null
+framework/Argv/test/Horde/Argv
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackCheckAbbrevTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser();
+ $this->parser->addOption('--foo-bar', array('action' => 'callback',
+ 'callback' => array($this, 'checkAbbrev')));
+ }
+
+ public function checkAbbrev($option, $opt, $value, $parser)
+ {
+ $this->assertEquals($opt, '--foo-bar');
+ }
+
+ public function testAbbrevCallbackExpansion()
+ {
+ $this->assertParseOk(array('--foo'), array(), array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackExtraArgsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-p', '--point', array('action' => 'callback',
+ 'callback' => array($this, 'processTuple'),
+ 'callbackArgs' => array(3, 'int'), 'type' => 'string',
+ 'dest' => 'points', 'default' => array())),
+ );
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function processTuple($option, $opt, $value, $parser, $args)
+ {
+ list($len, $type) = $args;
+
+ $this->assertEquals(3, $len);
+ $this->assertEquals('int', $type);
+
+ if ($opt == '-p') {
+ $this->assertEquals('1,2,3', $value);
+ } else if ($option == '--point') {
+ $this->assertEquals('4,5,6', $value);
+ }
+
+ $values = explode(',', $value);
+ foreach ($values as &$value) {
+ settype($value, $type);
+ }
+
+ $parser->values->{$option->dest}[] = $values;
+ }
+
+ public function testCallbackExtraArgs()
+ {
+ $this->assertParseOk(array("-p1,2,3", "--point", "4,5,6"),
+ array('points' => array(array(1,2,3), array(4,5,6))),
+ array());
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackManyArgsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-a', '--apple', array('action' => 'callback', 'nargs' => 2,
+ 'callback' => array($this, 'processMany'), 'type' => 'string')),
+ $this->makeOption('-b', '--bob', array('action' => 'callback', 'nargs' => 3,
+ 'callback' => array($this, 'processMany'), 'type' => 'int'))
+ );
+
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function processMany($option, $opt, $value, $parser_)
+ {
+ if ($opt == '-a') {
+ $this->assertEquals(array('foo', 'bar'), $value);
+ } else if ($opt == '--apple') {
+ $this->assertEquals(array('ding', 'dong'), $value);
+ } else if ($opt == '-b') {
+ $this->assertEquals(array(1, 2, 3), $value);
+ } else if ($option == '--bob') {
+ $this->assertEquals(array(-666, 42, 0), $value);
+ }
+ }
+
+ public function testManyArgs()
+ {
+ $this->assertParseOk(array("-a", "foo", "bar", "--apple", "ding", "dong",
+ "-b", "1", "2", "3", "--bob", "-666", "42",
+ "0"),
+ array('apple' => null, 'bob' => null),
+ array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackMeddleArgsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array();
+ for ($i = -1; $i > -6; $i--) {
+ $options[] = $this->makeOption((string)$i, array('action' => 'callback',
+ 'callback' => array($this, 'process_n'),
+ 'dest' => 'things'));
+ }
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ /**
+ * Callback that meddles in rargs, largs
+ */
+ public function process_n($option, $opt, $value, $parser)
+ {
+ // option is -3, -5, etc.
+ $nargs = (int)substr($opt, 1);
+ $rargs =& $parser->rargs;
+ if (count($rargs) < $nargs) {
+ $this->fail(sprintf("Expected %d arguments for %s option.", $nargs, $opt));
+ }
+
+ $parser->values->{$option->dest}[] = array_splice($rargs, 0, $nargs);
+ $parser->largs[] = $nargs;
+ }
+
+ public function testCallbackMeddleArgs()
+ {
+ $this->assertParseOK(array("-1", "foo", "-3", "bar", "baz", "qux"),
+ array('things' => array(array('foo'), array('bar', 'baz', 'qux'))),
+ array(1, 3));
+ }
+
+ public function testCallbackMeddleArgsSeparator()
+ {
+ $this->assertParseOK(array("-2", "foo", "--"),
+ array('things' => array(array('foo', '--'))),
+ array(2));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ new Horde_Argv_Option('-x', null,
+ array('action' => 'callback', 'callback' => array($this, 'processOpt'))),
+ new Horde_Argv_Option('-f', '--file',
+ array('action' => 'callback',
+ 'callback' => array($this, 'processOpt'),
+ 'type' => 'string',
+ 'dest' => 'filename')),
+ );
+
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function processOpt($option, $opt, $value, $parser_)
+ {
+ if ($opt == '-x') {
+ $this->assertEquals(array('-x'), $option->shortOpts);
+ $this->assertEquals(array(), $option->longOpts);
+ $this->assertType(get_class($this->parser), $parser_);
+ $this->assertNull($value);
+ $this->assertEquals(array('filename' => null), iterator_to_array($parser_->values));
+
+ $parser_->values->x = 42;
+ } else if ($opt == '--file') {
+ $this->assertEquals(array('-f'), $option->shortOpts);
+ $this->assertEquals(array('--file'), $option->longOpts);
+ $this->assertType(gettype($this->parser), $parser_);
+ $this->assertEquals('foo', $value);
+ $this->assertEquals(array('filename' => null, 'x' => 42), iterator_to_array($parser_->values));
+
+ $parser_->values->{$option->dest} = $value;
+ } else {
+ $this->fail(sprintf('Unknown option %r in processOpt.', $opt));
+ }
+ }
+
+ public function testCallback()
+ {
+ $this->assertParseOk(array('-x', '--file=foo'),
+ array('filename' => 'foo', 'x' => 42),
+ array());
+ }
+
+ public function testCallbackHelp()
+ {
+ // This test was prompted by SF bug #960515 -- the point is
+ // not to inspect the help text, just to make sure that
+ // formatHelp() doesn't crash.
+ $parser = new Horde_Argv_Parser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $parser->removeOption('-h');
+ $parser->addOption('-t', '--test',
+ array('action' => 'callback', 'callback' => array($this, 'returnNull'),
+ 'type' => 'string', 'help' => 'foo'));
+
+ $expectedHelp = "Options:\n -t TEST, --test=TEST foo\n";
+ $this->assertHelp($parser, $expectedHelp);
+ }
+
+ public function returnNull()
+ {}
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CallbackVarArgsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-a', array('type' => 'int', 'nargs' => 2, 'dest' => 'a')),
+ $this->makeOption('-b', array('action' => 'store_true', 'dest' => 'b')),
+ $this->makeOption('-c', '--callback', array('action' => 'callback', 'callback' => array($this, 'variableArgs'), 'dest' => 'c')),
+ );
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE,
+ 'optionList' => $options));
+ }
+
+ public function variableArgs($option, $opt, $value, $parser)
+ {
+ $this->assertNull($value);
+ $done = 0;
+ $value = array();
+ $rargs =& $parser->rargs;
+ while ($rargs) {
+ $arg = $rargs[0];
+ if ((substr($arg, 0, 2) == '--' && strlen($arg) > 2) ||
+ (substr($arg, 0, 1) == '-' && strlen($arg) > 1 && substr($arg, 1, 1) != '-')) {
+ break;
+ } else {
+ $value[] = $arg;
+ array_shift($rargs);
+ }
+ }
+ $parser->values->{$option->dest} = $value;
+ }
+
+ public function testVariableArgs()
+ {
+ $this->assertParseOK(array('-a3', '-5', '--callback', 'foo', 'bar'),
+ array('a' => array(3, -5), 'b' => null, 'c' => array('foo', 'bar')),
+ array());
+ }
+
+ public function testConsumeSeparatorStopAtOption()
+ {
+ $this->assertParseOK(array('-c', '37', '--', 'xxx', '-b', 'hello'),
+ array('a' => null, 'b' => true, 'c' => array('37', '--', 'xxx')),
+ array('hello'));
+ }
+
+ public function testPositionalArgAndVariableArgs()
+ {
+ $this->assertParseOK(array('hello', '-c', 'foo', '-', 'bar'),
+ array('a' => null, 'b' => null, 'c' => array('foo', '-', 'bar')),
+ array('hello'));
+ }
+
+ public function testStopAtOption()
+ {
+ $this->assertParseOK(array('-c', 'foo', '-b'),
+ array('a' => null, 'b' => true, 'c' => array('foo')),
+ array());
+ }
+
+ public function testStopAtInvalidOption()
+ {
+ $this->assertParseFail(array('-c', '3', '-5', '-a'), 'no such option: -5');
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ChoiceTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->parser->addOption('-c', array('action' => 'store', 'type' => 'choice',
+ 'dest' => 'choice', 'choices' => array('one', 'two', 'three')));
+ }
+
+ public function testValidChoice()
+ {
+ $this->assertParseOk(array('-c', 'one', 'xyz'),
+ array('choice' => 'one'),
+ array('xyz'));
+ }
+
+ public function testInvalidChoice()
+ {
+ $this->assertParseFail(array('-c', 'four', 'abc'),
+ "option -c: invalid choice: 'four' " .
+ "(choose from 'one', 'two', 'three')");
+ }
+
+ public function testAddChoiceOption()
+ {
+ $this->parser->addOption('-d', '--default', array('choices' => array('four', 'five', 'six')));
+ $opt = $this->parser->getOption('-d');
+ $this->assertEquals('choice', $opt->type);
+ $this->assertEquals('store', $opt->action);
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ConflictOverrideTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->parser->setConflictHandler('resolve');
+ $this->parser->addOption('-n', '--dry-run',
+ array('action' => 'store_true', 'dest' => 'dry_run',
+ 'help' => "don't do anything"));
+ $this->parser->addOption('--dry-run', '-n',
+ array('action' => 'store_const', 'const' => 42, 'dest' => 'dry_run',
+ 'help' => 'dry run mode'));
+ }
+
+ public function testConflictOverrideOpts()
+ {
+ $opt = $this->parser->getOption('--dry-run');
+
+ $this->assertEquals(array('-n'), $opt->shortOpts);
+ $this->assertEquals(array('--dry-run'), $opt->longOpts);
+ }
+
+ public function testConflictOverrideHelp()
+ {
+ $output = "Options:\n"
+ . " -h, --help show this help message and exit\n"
+ . " -n, --dry-run dry run mode\n";
+ $this->assertOutput(array('-h'), $output);
+ }
+
+ public function testConflictOverrideArgs()
+ {
+ $this->assertParseOk(array('-n'),
+ array('dry_run' => 42),
+ array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ConflictResolveTest extends Horde_Argv_ConflictTestBase
+{
+ public function setUp()
+ {
+ parent::setUp();
+ $this->parser->setConflictHandler('resolve');
+ $this->parser->addOption('-v', '--version', array('action' => 'callback',
+ 'callback' => array($this, 'showVersion'),
+ 'help' => 'show version'));
+ }
+
+ public function testConflictResolve()
+ {
+ $vOpt = $this->parser->getOption('-v');
+ $verboseOpt = $this->parser->getOption('--verbose');
+ $versionOpt = $this->parser->getOption('--version');
+
+ $this->assertSame($vOpt, $versionOpt);
+ $this->assertNotSame($vOpt, $verboseOpt);
+
+ $this->assertEquals(array('--version'), $vOpt->longOpts);
+ $this->assertEquals(array('-v'), $versionOpt->shortOpts);
+ $this->assertEquals(array('--version'), $versionOpt->longOpts);
+ $this->assertEquals(array(), $verboseOpt->shortOpts);
+ $this->assertEquals(array('--verbose'), $verboseOpt->longOpts);
+ }
+
+ public function testConflictResolveHelp()
+ {
+ $output = "Options:\n"
+ . " --verbose increment verbosity\n"
+ . " -h, --help show this help message and exit\n"
+ . " -v, --version show version\n";
+
+ $this->assertOutput(array('-h'), $output);
+ }
+
+ public function testConflictResolveShortOpt()
+ {
+ $this->assertParseOk(array('-v'),
+ array('verbose' => null, 'showVersion' => 1),
+ array());
+ }
+
+ public function testConflictResolveLongOpt()
+ {
+ $this->assertParseOk(array('--verbose'),
+ array('verbose' => 1),
+ array());
+ }
+
+ public function testConflictResolveLongOpts()
+ {
+ $this->assertParseOk(array('--verbose', '--version'),
+ array('verbose' => 1, 'showVersion' => 1),
+ array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ConflictTest extends Horde_Argv_ConflictTestBase
+{
+ public function assertConflictError($func)
+ {
+ try {
+ call_user_func($func, '-v', '--version', array(
+ 'action' => 'callback',
+ 'callback' => array($this, 'showVersion'),
+ 'help' => 'show version'));
+ $this->fail();
+ } catch (Horde_Argv_OptionConflictException $e) {
+ $this->assertEquals("option -v/--version: conflicting option string(s): -v",
+ $e->getMessage());
+ $this->assertEquals('-v/--version', $e->optionId);
+ }
+ }
+
+ public function testConflictError()
+ {
+ $this->assertConflictError(array($this->parser, 'addOption'));
+ }
+
+ public function testConflictErrorGroup()
+ {
+ $group = new Horde_Argv_OptionGroup($this->parser, 'Group 1');
+ $this->assertConflictError(array($group, 'addOption'));
+ }
+
+ public function testNoSuchConflictHandler()
+ {
+ $this->assertRaises(array($this->parser, 'setConflictHandler'), array('foo'), 'InvalidArgumentException', "invalid conflictHandler 'foo'");
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ConflictTestBase extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(new Horde_Argv_Option('-v', '--verbose', array(
+ 'action' => 'count',
+ 'dest' => 'verbose',
+ 'help' => 'increment verbosity'))
+ );
+
+ $this->parser = new Horde_Argv_InterceptingParser(
+ array('usage' => Horde_Argv_Option::SUPPRESS_USAGE, 'optionList' => $options)
+ );
+ }
+
+ public function showVersion($option, $opt, $value, $parser)
+ {
+ $this->parser->values->showVersion = 1;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+/**
+ * Conflicting default values: the last one should win.
+ */
+class Horde_Argv_ConflictingDefaultsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-v', array('action' => 'store_true', 'dest' => 'verbose', 'default' => 1))
+ );
+
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function testConflictDefault()
+ {
+ $this->parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose',
+ 'default' => 0));
+
+ $this->assertParseOk(array(), array('verbose' => 0), array());
+ }
+
+ public function testConflictDefaultNone()
+ {
+ $this->parser->addOption('-q', array('action' => 'store_false', 'dest' => 'verbose',
+ 'default' => null));
+
+ $this->assertParseOk(array(), array('verbose' => null), array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_CountTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->vOpt = $this->makeOption('-v', array('action' => 'count', 'dest' => 'verbose'));
+ $this->parser->addOption($this->vOpt);
+ $this->parser->addOption('--verbose', array('type' => 'int', 'dest' => 'verbose'));
+ $this->parser->addOption('-q', '--quiet',
+ array('action' => 'store_const', 'dest' => 'verbose', 'const' => 0));
+ }
+
+ public function testEmpty()
+ {
+ $this->assertParseOk(array(), array('verbose' => null), array());
+ }
+
+ public function testCountOne()
+ {
+ $this->assertParseOk(array('-v'), array('verbose' => 1), array());
+ }
+
+ public function testCountThree()
+ {
+ $this->assertParseOk(array('-vvv'), array('verbose' => 3), array());
+ }
+
+ public function testCountThreeApart()
+ {
+ $this->assertParseOk(array('-v', '-v', '-v'), array('verbose' => 3), array());
+ }
+
+ public function testCountOverrideAmount()
+ {
+ $this->assertParseOk(array('-vvv', '--verbose=2'), array('verbose' => 2), array());
+ }
+
+ public function testCountOverrideQuiet()
+ {
+ $this->assertParseOk(array('-vvv', '--verbose=2', '-q'), array('verbose' => 0), array());
+ }
+
+ public function testCountOverriding()
+ {
+ $this->assertParseOk(array('-vvv', '--verbose=2', '-q', '-v'),
+ array('verbose' => 1), array());
+ }
+
+ public function testCountInterspersedArgs()
+ {
+ $this->assertParseOk(array('--quiet', '3', '-v'),
+ array('verbose' => 1),
+ array('3'));
+ }
+
+ public function testCountNoInterspersedArgs()
+ {
+ $this->parser->disableInterspersedArgs();
+ $this->assertParseOk(array('--quiet', '3', '-v'),
+ array('verbose' => 0),
+ array('3', '-v'));
+ }
+
+ public function testCountNoSuchOption()
+ {
+ $this->assertParseFail(array('-q3', '-v'), 'no such option: -3');
+ }
+
+ public function testCountOptionNoValue()
+ {
+ $this->assertParseFail(array('--quiet=3', 'v'),
+ '--quiet option does not take a value');
+ }
+
+ public function testCountWithDefault()
+ {
+ $this->parser->setDefault('verbose', 0);
+ $this->assertParseOk(array(), array('verbose' => 0), array());
+ }
+
+ public function testCountOverridingDefault()
+ {
+ $this->parser->setDefault('verbose', 0);
+ $this->assertParseOk(array('-vvv', '--verbose=2', '-q', '-v'),
+ array('verbose' => 1), array());
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_DefaultValuesTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser();
+ $this->parser->addOption('-v', '--verbose', array('default' => true));
+ $this->parser->addOption('-q', '--quiet', array('dest' => 'verbose'));
+ $this->parser->addOption('-n', array('type' => 'int', 'default' => 37));
+ $this->parser->addOption('-m', array('type' => 'int'));
+ $this->parser->addOption('-s', array('default' => 'foo'));
+ $this->parser->addOption('-t');
+ $this->parser->addOption('-u', array('default' => null));
+
+ $this->expected = array('verbose' => true,
+ 'n' => 37,
+ 'm' => null,
+ 's' => 'foo',
+ 't' => null,
+ 'u' => null);
+ }
+
+ public function testBasicDefault()
+ {
+ $this->assertEquals($this->expected, iterator_to_array($this->parser->getDefaultValues()));
+ }
+
+ public function testMixedDefaultsPost()
+ {
+ $this->parser->setDefaults(array('n' => 42, 'm' => -100));
+ $this->expected = array_merge($this->expected, array('n' => 42, 'm' => -100));
+ $this->assertEquals($this->expected, iterator_to_array($this->parser->getDefaultValues()));
+ }
+
+ public function testMixedDefaultsPre()
+ {
+ $this->parser->setDefaults(array('x' => 'barf', 'y' => 'blah'));
+ $this->parser->addOption('-x', array('default' => 'frob'));
+ $this->parser->addOption('-y');
+
+ $this->expected = array_merge($this->expected, array('x' => 'frob', 'y' => 'blah'));
+ $this->assertEquals($this->expected, iterator_to_array($this->parser->getDefaultValues()));
+
+ $this->parser->removeOption('-y');
+ $this->parser->addOption('-y', array('default' => null));
+ $this->expected = array_merge($this->expected, array('y' => null));
+ $this->assertEquals($this->expected, iterator_to_array($this->parser->getDefaultValues()));
+ }
+
+ public function testProcessDefault()
+ {
+ $this->parser->optionClass = 'Horde_Argv_DurationOption';
+ $this->parser->addOption('-d', array('type' => 'duration', 'default' => 300));
+ $this->parser->addOption('-e', array('type' => 'duration', 'default' => '6m'));
+ $this->parser->setDefaults(array('n' => '42'));
+
+ $this->expected = array_merge($this->expected, array('d' => 300, 'e' => 360, 'n' => '42'));
+ $this->assertEquals($this->expected, iterator_to_array($this->parser->getDefaultValues()));
+ }
+}
+
+class Horde_Argv_DurationOption extends Horde_Argv_Option
+{
+ public $TYPES = array('string', 'int', 'long', 'float', 'complex', 'choice', 'duration');
+
+ public $TYPE_CHECKER = array('int' => 'checkBuiltin',
+ 'long' => 'checkBuiltin',
+ 'float' => 'checkBuiltin',
+ 'complex'=> 'checkBuiltin',
+ 'choice' => 'checkChoice',
+ 'duration' => 'checkDuration',
+ );
+
+ public function checkDuration($opt, $value)
+ {
+ // Custom type for testing processing of default values.
+ $time_units = array('s' => 1, 'm' => 60, 'h' => 60 * 60, 'd' => 60 * 60 * 24);
+
+ $last = substr($value, -1);
+ if (is_numeric($last)) {
+ return (int)$value;
+ } elseif (isset($time_units[$last])) {
+ return (int)substr($value, 0, -1) * $time_units[$last];
+ } else {
+ throw new Horde_Argv_OptionValueException(sprintf(
+ 'option %s: invalid duration: %s', $opt, $value));
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ExpandDefaultsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser(array('prog' => 'test'));
+ $this->help_prefix = 'Usage: test [options]
+
+Options:
+ -h, --help show this help message and exit';
+
+ $this->file_help = "read from FILE [default: %default]";
+ $this->expected_help_file = $this->help_prefix . "\n" .
+ " -f FILE, --file=FILE read from FILE [default: foo.txt]\n";
+ $this->expected_help_none = $this->help_prefix . "\n" .
+ " -f FILE, --file=FILE read from FILE [default: none]\n";
+ }
+
+ public function testOptionDefault()
+ {
+ $this->parser->addOption("-f", "--file", array('default' => 'foo.txt', 'help' => $this->file_help));
+ $this->assertHelp($this->parser, $this->expected_help_file);
+ }
+
+ public function testParserDefault1()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('help' => $this->file_help));
+ $this->parser->setDefault('file', "foo.txt");
+ $this->assertHelp($this->parser, $this->expected_help_file);
+ }
+
+ public function testParserDefault2()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('help' => $this->file_help));
+ $this->parser->setDefaults(array('file' => 'foo.txt'));
+ $this->assertHelp($this->parser, $this->expected_help_file);
+ }
+
+ public function testNoDefault()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('help' => $this->file_help));
+ $this->assertHelp($this->parser, $this->expected_help_none);
+ }
+
+ public function testDefaultNone1()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('default' => null,
+ 'help' => $this->file_help));
+ $this->assertHelp($this->parser, $this->expected_help_none);
+ }
+
+ public function testDefaultNone2()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('help' => $this->file_help));
+ $this->parser->setDefaults(array('file' => null));
+ $this->assertHelp($this->parser, $this->expected_help_none);
+ }
+
+ public function testFloatDefault()
+ {
+ $this->parser->addOption(
+ "-p", "--prob",
+ array('help' => "blow up with probability PROB [default: %default]"));
+ $this->parser->setDefaults(array('prob' => 0.43));
+ $expected_help = $this->help_prefix . "\n" .
+ " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n";
+ $this->assertHelp($this->parser, $expected_help);
+ }
+
+ public function testAltExpand()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('default' => "foo.txt",
+ 'help' => "read from FILE [default: *DEFAULT*]"));
+ $this->parser->formatter->default_tag = "*DEFAULT*";
+ $this->assertHelp($this->parser, $this->expected_help_file);
+ }
+
+ public function testNoExpand()
+ {
+ $this->parser->addOption("-f", "--file",
+ array('default' => "foo.txt",
+ 'help' => "read from %default file"));
+ $this->parser->formatter->default_tag = null;
+ $expected_help = $this->help_prefix . "\n" .
+ " -f FILE, --file=FILE read from %default file\n";
+ $this->assertHelp($this->parser, $expected_help);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ExtendAddActionsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(new Horde_Argv_ExtendAddActionsTest_MyOption("-a", "--apple", array(
+ 'action' => "extend", 'type' => "string", 'dest' => "apple")));
+ $this->parser = new Horde_Argv_Parser(array('optionList' => $options));
+ }
+
+ public function testExtendAddAction()
+ {
+ $this->assertParseOK(array("-afoo,bar", "--apple=blah"),
+ array('apple' => array("foo", "bar", "blah")),
+ array());
+ }
+
+ public function testExtendAddActionNormal()
+ {
+ $this->assertParseOK(array("-a", "foo", "-abar", "--apple=x,y"),
+ array('apple' => array("foo", "bar", "x", "y")),
+ array());
+ }
+
+}
+
+class Horde_Argv_ExtendAddActionsTest_MyOption extends Horde_Argv_Option
+{
+ public $ACTIONS = array("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "append_const",
+ "count",
+ "callback",
+ "help",
+ "version",
+ "extend",
+ );
+
+ public $STORE_ACTIONS = array("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "append_const",
+ "count",
+ "extend",
+ );
+
+ public $TYPED_ACTIONS = array("store",
+ "append",
+ "callback",
+ "extend",
+ );
+
+ public function takeAction($action, $dest, $opt, $value, $values, $parser)
+ {
+ if ($action == "extend") {
+ $lvalue = explode(',', $value);
+ $values->$dest = array_merge($values->ensureValue($dest, array()), $lvalue);
+ } else {
+ parent::takeAction($action, $dest, $opt, $parser, $value, $values);
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ExtendAddTypesTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE,
+ 'optionClass' => 'Horde_Argv_ExtendAddTypesTest_MyOption'));
+ $this->parser->addOption("-a", null, array('type' => "string", 'dest' => "a"));
+ $this->parser->addOption("-f", "--file", array('type' => "file", 'dest' => "file"));
+
+ /* @todo make more system independent */
+ $this->testPath = tempnam('/tmp', 'horde_argv');
+ }
+
+ public function tearDown()
+ {
+ if (!is_link($this->testPath) && is_dir($this->testPath)) {
+ rmdir($this->testPath);
+ } elseif (is_file($this->testPath)) {
+ unlink($this->testPath);
+ }
+ }
+
+ public function testFiletypeOk()
+ {
+ touch($this->testPath);
+ $this->assertParseOK(array("--file", $this->testPath, "-afoo"),
+ array('file' => $this->testPath, 'a' => 'foo'),
+ array());
+ }
+
+ public function testFiletypeNoexist()
+ {
+ unlink($this->testPath);
+ $this->assertParseFail(array("--file", $this->testPath, "-afoo"),
+ sprintf("%s: file does not exist", $this->testPath));
+ }
+
+ public function testFiletypeNotfile()
+ {
+ unlink($this->testPath);
+ mkdir($this->testPath);
+ $this->assertParseFail(array("--file", $this->testPath, "-afoo"),
+ sprintf("%s: not a regular file", $this->testPath));
+ }
+
+}
+
+class Horde_Argv_ExtendAddTypesTest_MyOption extends Horde_Argv_Option
+{
+ public $TYPES = array('string', 'int', 'long', 'float', 'complex', 'choice', 'file');
+
+ public $TYPE_CHECKER = array("int" => 'checkBuiltin',
+ "long" => 'checkBuiltin',
+ "float" => 'checkBuiltin',
+ "complex"=> 'checkBuiltin',
+ "choice" => 'checkChoice',
+ 'file' => 'checkFile',
+ );
+
+ public function checkFile($opt, $value)
+ {
+ if (!file_exists($value)) {
+ throw new Horde_Argv_OptionValueException(sprintf("%s: file does not exist", $value));
+ } elseif (!is_file($value)) {
+ throw new Horde_Argv_OptionValueException(sprintf("%s: not a regular file", $value));
+ }
+ return $value;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_HelpTest extends Horde_Argv_TestBase
+{
+
+ public static $expected_help_basic = 'Usage: bar.php [options]
+
+Options:
+ -a APPLE throw APPLEs at basket
+ -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
+ evil spirits that cause trouble and mayhem)
+ --foo=FOO store FOO in the foo list for later fooing
+ -h, --help show this help message and exit
+';
+
+ public static $expected_help_long_opts_first = 'Usage: bar.php [options]
+
+Options:
+ -a APPLE throw APPLEs at basket
+ --boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
+ evil spirits that cause trouble and mayhem)
+ --foo=FOO store FOO in the foo list for later fooing
+ --help, -h show this help message and exit
+';
+
+ public static $expected_help_title_formatter = 'Usage
+=====
+ bar.php [options]
+
+Options
+=======
+-a APPLE throw APPLEs at basket
+--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
+ evil spirits that cause trouble and mayhem)
+--foo=FOO store FOO in the foo list for later fooing
+--help, -h show this help message and exit
+';
+
+ public static $expected_help_short_lines = 'Usage: bar.php [options]
+
+Options:
+ -a APPLE throw APPLEs at basket
+ -b NUM, --boo=NUM shout "boo!" NUM times (in order to
+ frighten away all the evil spirits
+ that cause trouble and mayhem)
+ --foo=FOO store FOO in the foo list for later
+ fooing
+ -h, --help show this help message and exit
+';
+
+ public function setUp()
+ {
+ $this->parser = $this->makeParser(80);
+ $this->origColumns = isset($_ENV['COLUMNS']) ? $_ENV['COLUMNS'] : null;
+ }
+
+ public function tearDown()
+ {
+ if (is_null($this->origColumns)) {
+ unset($_ENV['COLUMNS']);
+ } else {
+ $_ENV['COLUMNS'] = $this->origColumns;
+ }
+ }
+
+ public function makeParser($columns)
+ {
+ $options = array(
+ $this->makeOption("-a", array('type' => "string", 'dest' => 'a',
+ 'metavar' => "APPLE", 'help' => "throw APPLEs at basket")),
+
+ $this->makeOption("-b", "--boo", array('type' => "int", 'dest' => 'boo',
+ 'metavar' => "NUM",
+ 'help' => "shout \"boo!\" NUM times (in order to frighten away " .
+ "all the evil spirits that cause trouble and mayhem)")),
+
+ $this->makeOption("--foo", array('action' => 'append', 'type' => 'string', 'dest' => 'foo',
+ 'help' => "store FOO in the foo list for later fooing")),
+ );
+
+ $_ENV['COLUMNS'] = $columns;
+
+ return new Horde_Argv_InterceptingParser(array('optionList' => $options));
+ }
+
+ public function assertHelpEquals($expectedOutput)
+ {
+ // @todo
+ // if type(expected_output) is types.UnicodeType:
+ // encoding = self.parser._get_encoding(sys.stdout)
+ // expected_output = expected_output.encode(encoding, "replace")
+
+ $origArgv = $_SERVER['argv'];
+ $_SERVER['argv'][0] = 'foo/bar.php';
+ $this->assertOutput(array('-h'), $expectedOutput);
+
+ $_SERVER['argv'] = $origArgv;
+ }
+
+ public function testHelp()
+ {
+ $this->assertHelpEquals(self::$expected_help_basic);
+ }
+
+ public function tesHelpOldUsage()
+ {
+ $this->parser->setUsage("Usage: %prog [options]");
+ $this->assertHelpEquals(self::$expected_help_basic);
+ }
+
+ public function testHelpLongOptsFirst()
+ {
+ $this->parser->formatter->short_first = false;
+ $this->assertHelpEquals(self::$expected_help_long_opts_first);
+ }
+
+ public function testHelpTitleFormatter()
+ {
+ $this->parser->formatter = new Horde_Argv_TitledHelpFormatter();
+ $this->assertHelpEquals(self::$expected_help_title_formatter);
+ }
+
+ public function testWrapColumns()
+ {
+ // Ensure that wrapping respects $COLUMNS environment variable.
+ // Need to reconstruct the parser, since that's the only time
+ // we look at $COLUMNS.
+ $this->parser = $this->makeParser(60);
+ $this->assertHelpEquals(self::$expected_help_short_lines);
+ }
+
+ public function testHelpDescriptionGroups()
+ {
+ $this->parser->setDescription(
+ "This is the program description for %prog. %prog has " .
+ "an option group as well as single options.");
+
+ $group = new Horde_Argv_OptionGroup(
+ $this->parser, "Dangerous Options",
+ "Caution: use of these options is at your own risk. " .
+ "It is believed that some of them bite.");
+ $group->addOption("-g", array('action' => "store_true", 'help' => "Group option."));
+ $this->parser->addOptionGroup($group);
+
+ $expect = 'Usage: bar.php [options]
+
+This is the program description for bar.php. bar.php has an option group as
+well as single options.
+
+Options:
+ -a APPLE throw APPLEs at basket
+ -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
+ evil spirits that cause trouble and mayhem)
+ --foo=FOO store FOO in the foo list for later fooing
+ -h, --help show this help message and exit
+
+ Dangerous Options:
+ Caution: use of these options is at your own risk. It is believed
+ that some of them bite.
+
+ -g Group option.
+';
+
+ $this->assertHelpEquals($expect);
+
+ $this->parser->epilog = "Please report bugs to /dev/null.";
+ $this->assertHelpEquals($expect . "\nPlease report bugs to /dev/null.\n");
+ }
+
+ /* @todo
+ def test_help_unicode(self):
+ self.parser = Horde_Argv_InterceptingParser(usage=Horde_Argv_Option::SUPPRESS_USAGE)
+ self.parser.addOption("-a", action="store_true", help=u"ol\u00E9!")
+ expect = u"""\
+Options:
+ -h, --help show this help message and exit
+ -a ol\u00E9!
+"""
+ self.assertHelpEquals(expect)
+
+ def test_help_unicode_description(self):
+ self.parser = Horde_Argv_InterceptingParser(usage=Horde_Argv_Option::SUPPRESS_USAGE,
+ description=u"ol\u00E9!")
+ expect = u"""\
+ol\u00E9!
+
+Options:
+ -h, --help show this help message and exit
+"""
+ self.assertHelpEquals(expect)
+
+ */
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_InterceptedException extends Exception
+{
+ public function __construct($error_message = null, $exit_status = null, $exit_message = null)
+ {
+ $this->error_message = $error_message;
+ $this->exit_status = $exit_status;
+ $this->exit_message = $exit_message;
+ }
+
+ public function __toString()
+ {
+ if ($this->error_message)
+ return $this->error_message;
+ if ($this->exit_message)
+ return $this->exit_message;
+ return "intercepted error";
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_InterceptingParser extends Horde_Argv_Parser
+{
+ public function parserExit($status = 0, $msg = null)
+ {
+ throw new Horde_Argv_InterceptedException(null, $status, $msg);
+ }
+
+ public function parserError($msg)
+ {
+ throw new Horde_Argv_InterceptedException($msg);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_MatchAbbrevTest extends Horde_Argv_TestBase
+{
+ public function testMatchAbbrev()
+ {
+ $this->assertEquals(Horde_Argv_Parser::matchAbbrev("--f",
+ array("--foz" => null,
+ "--foo" => null,
+ "--fie" => null,
+ "--f" => null)),
+ '--f');
+ }
+
+ public function testMatchAbbrevError()
+ {
+ $s = '--f';
+ $wordmap = array("--foz" => null, "--foo" => null, "--fie" => null);
+
+ try {
+ Horde_Argv_Parser::matchAbbrev($s, $wordmap);
+ $this->fail();
+ } catch (Horde_Argv_BadOptionException $e) {
+ $this->assertEquals("ambiguous option: --f (--fie, --foo, --foz?)",
+ $e->getMessage());
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_MultipleArgsAppendTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->parser->addOption("-p", "--point", array(
+ 'action' => "store", 'nargs' => 3, 'type' => 'float', 'dest' => 'point'));
+ $this->parser->addOption("-f", "--foo", array(
+ 'action' => "append", 'nargs' => 2, 'type' => "int", 'dest' => "foo"));
+ $this->parser->addOption("-z", "--zero", array(
+ 'action' => "append_const", 'dest' => "foo", 'const' => array(0, 0)));
+ }
+
+ public function testNargsAppend()
+ {
+ $this->assertParseOK(array("-f", "4", "-3", "blah", "--foo", "1", "666"),
+ array('point' => null, 'foo' => array(array(4, -3), array(1, 666))),
+ array('blah'));
+ }
+
+ public function testNargsAppendRequiredValues()
+ {
+ $this->assertParseFail(array("-f4,3"),
+ "-f option requires 2 arguments");
+ }
+
+ public function testNargsAppendSimple()
+ {
+ $this->assertParseOK(array("--foo=3", "4"),
+ array('point' => null, 'foo' => array(array(3, 4))),
+ array());
+ }
+
+ public function testNargsAppendConst()
+ {
+ $this->assertParseOK(array("--zero", "--foo", "3", "4", "-z"),
+ array('point' => null, 'foo' => array(array(0, 0), array(3, 4), array(0, 0))),
+ array());
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_MultipleArgsTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->parser->addOption("-p", "--point",
+ array('action' => "store", 'nargs' => 3, 'type' => "float", 'dest' => "point"));
+ }
+
+ public function testNargsWithPositionalArgs()
+ {
+ $this->assertParseOK(array("foo", "-p", "1", "2.5", "-4.3", "xyz"),
+ array('point' => array(1.0, 2.5, -4.3)),
+ array('foo', 'xyz'));
+ }
+
+ public function testNargsLongOpt()
+ {
+ $this->assertParseOK(array("--point", "-1", "2.5", "-0", "xyz"),
+ array('point' => array(-1.0, 2.5, -0.0)),
+ array("xyz"));
+ }
+
+ public function testNargsInvalidFloatValue()
+ {
+ $this->assertParseFail(array("-p", "1.0", "2x", "3.5"),
+ "option -p: invalid floating-point value: '2x'");
+ }
+
+ public function testNargsRequiredValues()
+ {
+ $this->assertParseFail(array("--point", "1.0", "3.5"),
+ "--point option requires 3 arguments");
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_OptionChecksTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ }
+
+ public function assertOptionError($expected_message, $args)
+ {
+ $this->assertRaises(array($this, 'makeOption'), $args, 'Horde_Argv_OptionException', $expected_message);
+ }
+
+ public function testOptStringEmpty()
+ {
+ try {
+ new Horde_Argv_Option();
+ } catch (Exception $e) {
+ $this->assertType('InvalidArgumentException', $e);
+ $this->assertEquals("at least one option string must be supplied", $e->getMessage());
+ return true;
+ }
+
+ $this->fail("InvalidArgumentException for no option strings not thrown");
+ }
+
+ public function testOptStringTooShort()
+ {
+ $this->assertOptionError(
+ "invalid option string 'b': must be at least two characters long",
+ array("b"));
+ }
+
+ public function testOptStringShortInvalid()
+ {
+ $this->assertOptionError(
+ "invalid short option string '--': must be " .
+ "of the form -x, (x any non-dash char)",
+ array("--"));
+ }
+
+ public function testOptStringLongInvalid()
+ {
+ $this->assertOptionError(
+ "invalid long option string '---': " .
+ "must start with --, followed by non-dash",
+ array("---"));
+ }
+
+ public function testAttrInvalid()
+ {
+ $this->assertOptionError(
+ "option -b: invalid keyword arguments: bar, foo",
+ array("-b", array('foo' => null, 'bar' => null)));
+ }
+
+ public function testActionInvalid()
+ {
+ $this->assertOptionError(
+ "option -b: invalid action: 'foo'",
+ array("-b", array('action' => 'foo')));
+ }
+
+ public function testTypeInvalid()
+ {
+ $this->assertOptionError(
+ "option -b: invalid option type: 'foo'",
+ array("-b", array('type' => 'foo')));
+ $this->assertOptionError(
+ "option -b: invalid option type: 'Array'",
+ array("-b", array('type' => array())));
+ }
+
+ public function testNoTypeForAction()
+ {
+ $this->assertOptionError(
+ "option -b: must not supply a type for action 'count'",
+ array("-b", array('action' => 'count', 'type' => 'int')));
+ }
+
+ public function testNoChoicesList()
+ {
+ $this->assertOptionError(
+ "option -b/--bad: must supply a list of " .
+ "choices for type 'choice'",
+ array("-b", "--bad", array('type' => "choice")));
+ }
+
+ public function testBadChoicesList()
+ {
+ $typename = gettype('');
+ $this->assertOptionError(
+ sprintf("option -b/--bad: choices must be a list of " .
+ "strings ('%s' supplied)", $typename),
+ array("-b", "--bad", array('type' => 'choice', 'choices' => 'bad choices')));
+ }
+
+ public function testNoChoicesForType()
+ {
+ $this->assertOptionError(
+ "option -b: must not supply choices for type 'int'",
+ array("-b", array('type' => 'int', 'choices' => "bad")));
+ }
+
+ public function testNoConstForAction()
+ {
+ $this->assertOptionError(
+ "option -b: 'const' must not be supplied for action 'store'",
+ array("-b", array('action' => 'store', 'const' => 1)));
+ }
+
+ public function testNoNargsForAction()
+ {
+ $this->assertOptionError(
+ "option -b: 'nargs' must not be supplied for action 'count'",
+ array("-b", array('action' => 'count', 'nargs' => 2)));
+ }
+
+ public function testCallbackNotCallable()
+ {
+ $this->assertOptionError(
+ "option -b: callback not callable: 'foo'",
+ array("-b", array('action' => 'callback', 'callback' => 'foo')));
+ }
+
+ public function dummy()
+ {
+ }
+
+ public function testCallbackArgsNoArray()
+ {
+ $this->assertOptionError(
+ "option -b: callbackArgs, if supplied, " .
+ "must be an array: not 'foo'",
+ array("-b", array('action' => 'callback',
+ 'callback' => array($this, 'dummy'),
+ 'callbackArgs' => 'foo')));
+ }
+
+ public function testNoCallbackForAction()
+ {
+ $this->assertOptionError(
+ "option -b: callback supplied ('foo') for non-callback option",
+ array("-b", array('action' => 'store',
+ 'callback' => 'foo')));
+ }
+
+ public function testNoCallbackArgsForAction()
+ {
+ $this->assertOptionError(
+ "option -b: callbackArgs supplied for non-callback option",
+ array("-b", array('action' => 'store',
+ 'callbackArgs' => 'foo')));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_OptionGroupTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ }
+
+ public function testOptionGroupCreateInstance()
+ {
+ $group = new Horde_Argv_OptionGroup($this->parser, "Spam");
+ $this->parser->addOptionGroup($group);
+ $group->addOption("--spam", array('action' => "store_true",
+ 'help' => "spam spam spam spam"));
+ $this->assertParseOK(array("--spam"), array('spam' => true), array());
+ }
+
+ public function testAddGroupNoGroup()
+ {
+ $this->assertTypeError(array($this->parser, 'addOptionGroup'),
+ "not an OptionGroup instance: NULL", array(null));
+ }
+
+ public function testAddGroupInvalidArguments()
+ {
+ $this->assertTypeError(array($this->parser, 'addOptionGroup'),
+ "invalid arguments", null);
+ }
+
+ public function testAddGroupWrongParser()
+ {
+ $group = new Horde_Argv_OptionGroup($this->parser, "Spam");
+ $group->parser = new Horde_Argv_Parser();
+ $this->assertRaises(array($this->parser, 'addOptionGroup'), array($group),
+ 'InvalidArgumentException', "invalid OptionGroup (wrong parser)");
+ }
+
+ public function testGroupManipulate()
+ {
+ $group = $this->parser->addOptionGroup("Group 2",
+ array('description' => "Some more options"));
+ $group->setTitle("Bacon");
+ $group->addOption("--bacon", array('type' => "int"));
+ $this->assertSame($group, $this->parser->getOptionGroup("--bacon"));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_OptionValuesTest extends Horde_Argv_TestBase
+{
+ public function testBasics()
+ {
+ $values = new Horde_Argv_Values();
+ $this->assertEquals(iterator_to_array($values), array());
+ $this->assertNotEquals($values, array('foo' => 'bar'));
+ $this->assertNotEquals($values, '');
+
+ $dict = array('foo' => 'bar', 'baz' => 42);
+ $values = new Horde_Argv_Values($dict);
+ $this->assertEquals($dict, iterator_to_array($values));
+ $this->assertNotEquals($values, array('foo' => 'bar'));
+ $this->assertNotEquals($values, array());
+ $this->assertNotEquals($values, "");
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ParseNumTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser();
+ $this->parser->addOption('-n', array('type' => 'int'));
+ $this->parser->addOption('-l', array('type' => 'long'));
+ }
+
+ public function testParseNumFail()
+ {
+ $this->assertFalse(Horde_Argv_Option::parseNumber(''));
+ $this->assertFalse(Horde_Argv_Option::parseNumber("0xOoops"));
+ }
+
+ public function testParseNumOk()
+ {
+ $this->assertSame(0,
+ Horde_Argv_Option::parseNumber('0'));
+ $this->assertSame(16,
+ Horde_Argv_Option::parseNumber('0x10'));
+ $this->assertSame(10,
+ Horde_Argv_Option::parseNumber('0XA'));
+ $this->assertSame(8,
+ Horde_Argv_Option::parseNumber('010'));
+ $this->assertSame(3,
+ Horde_Argv_Option::parseNumber('0b11'));
+ $this->assertSame(0,
+ Horde_Argv_Option::parseNumber('0b'));
+ }
+
+ public function testNumericOptions()
+ {
+ $this->assertParseOk(array("-n", "42", "-l", "0x20"),
+ array("n" => 42, "l" => 0x20), array());
+
+ $this->assertParseOk(array("-n", "0b0101", "-l010"),
+ array("n" => 5, "l" => 8), array());
+
+ $this->assertParseFail(array("-n008"),
+ "option -n: invalid integer value: '008'");
+
+ $this->assertParseFail(array("-l0b0123"),
+ "option -l: invalid long integer value: '0b0123'");
+
+ $this->assertParseFail(array("-l", "0x12x"),
+ "option -l: invalid long integer value: '0x12x'");
+ }
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ParserTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser();
+ $this->parser->addOption('-v', '--verbose', '-n', '--noisy',
+ array('action' => 'store_true', 'dest' => 'verbose'));
+ $this->parser->addOption('-q', '--quiet', '--silent',
+ array('action' => 'store_false', 'dest' => 'verbose'));
+ }
+
+ public function testAddOptionNoOption()
+ {
+ $this->assertTypeError(array($this->parser, 'addOption'),
+ "not an Option instance: NULL", array(null));
+ }
+
+ public function testAddOptionInvalidArguments()
+ {
+ $this->assertTypeError(array($this->parser, 'addOption'),
+ "invalid arguments", null);
+ }
+
+ public function testGetOption()
+ {
+ $opt1 = $this->parser->getOption("-v");
+ $this->assertType('Horde_Argv_Option', $opt1);
+ $this->assertEquals($opt1->shortOpts, array("-v", "-n"));
+ $this->assertEquals($opt1->longOpts, array("--verbose", "--noisy"));
+ $this->assertEquals($opt1->action, "store_true");
+ $this->assertEquals($opt1->dest, "verbose");
+ }
+
+ public function testGetOptionEquals()
+ {
+ $opt1 = $this->parser->getOption("-v");
+ $opt2 = $this->parser->getOption("--verbose");
+ $opt3 = $this->parser->getOption("-n");
+ $opt4 = $this->parser->getOption("--noisy");
+ $this->assertEquals($opt1, $opt2);
+ $this->assertEquals($opt1, $opt3);
+ $this->assertEquals($opt1, $opt4);
+ }
+
+ public function testHasOption()
+ {
+ $this->assertTrue($this->parser->hasOption("-v"));
+ $this->assertTrue($this->parser->hasOption("--verbose"));
+ }
+
+ public function assertRemoved()
+ {
+ $this->assertNull($this->parser->getOption("-v"));
+ $this->assertNull($this->parser->getOption("--verbose"));
+ $this->assertNull($this->parser->getOption("-n"));
+ $this->assertNull($this->parser->getOption("--noisy"));
+
+ $this->assertFalse($this->parser->hasOption("-v"));
+ $this->assertFalse($this->parser->hasOption("--verbose"));
+ $this->assertFalse($this->parser->hasOption("-n"));
+ $this->assertFalse($this->parser->hasOption("--noisy"));
+
+ $this->assertTrue($this->parser->hasOption("-q"));
+ $this->assertTrue($this->parser->hasOption("--silent"));
+ }
+
+ public function testRemoveShortOpt()
+ {
+ $this->parser->removeOption('-n');
+ $this->assertRemoved();
+ }
+
+ public function testRemoveLongOpt()
+ {
+ $this->parser->removeOption('--verbose');
+ $this->assertRemoved();
+ }
+
+ public function testRemoveNonexistent()
+ {
+ $this->assertRaises(array($this->parser, 'removeOption'), array('foo'), 'InvalidArgumentException', "no such option 'foo'");
+ }
+
+ /**
+ def test_refleak(self):
+ # If a Horde_Argv_Parser is carrying around a reference to a large
+ # object, various cycles can prevent it from being GC'd in
+ # a timely fashion. destroy() breaks the cycles to ensure stuff
+ # can be cleaned up.
+ big_thing = [42]
+ refcount = sys.getrefcount(big_thing)
+ parser = Horde_Argv_Parser()
+ parser.addOption("-a", "--aaarggh")
+ parser.big_thing = big_thing
+
+ parser.destroy()
+ del parser
+ $this->assertEquals(refcount, sys.getrefcount(big_thing))
+ */
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_ProgNameTest extends Horde_Argv_TestBase
+{
+ public function assertUsage($parser, $expectedUsage)
+ {
+ $this->assertEquals($parser->getUsage(), $expectedUsage);
+ }
+
+ public function assertVersion($parser, $expectedVersion)
+ {
+ $this->assertEquals($parser->getVersion(), $expectedVersion);
+ }
+
+ public function testDefaultProgName()
+ {
+ // Make sure that program name is taken from $_SERVER['argv'][0] by default.
+ $saveArgv = $_SERVER['argv'];
+ try {
+ $_SERVER['argv'][0] = 'foo/bar/baz.php';
+ $parser = new Horde_Argv_Parser(array('usage' => "%prog ...", 'version' => "%prog 1.2"));
+ $expectedUsage = "Usage: baz.php ...\n";
+ } catch (Exception $e) {
+ $_SERVER['argv'] = $saveArgv;
+ throw($e);
+ }
+
+ $this->assertUsage($parser, $expectedUsage);
+ $this->assertVersion($parser, "baz.php 1.2");
+ $this->assertHelp($parser,
+ $expectedUsage . "\n" .
+ "Options:\n" .
+ " --version show program's version number and exit\n" .
+ " -h, --help show this help message and exit\n");
+ }
+
+ public function testCustomProgName()
+ {
+ $parser = new Horde_Argv_Parser(array('prog' => 'thingy',
+ 'version' => "%prog 0.1",
+ 'usage' => "%prog arg arg"));
+ $parser->removeOption('-h');
+ $parser->removeOption('--version');
+ $expectedUsage = "Usage: thingy arg arg\n";
+ $this->assertUsage($parser, $expectedUsage);
+ $this->assertVersion($parser, "thingy 0.1");
+ $this->assertHelp($parser, $expectedUsage . "\n");
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_StandardTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $options = array(
+ $this->makeOption('-a', array('type' => 'string')),
+ $this->makeOption('-b', '--boo', array('type' => 'int', 'dest' => 'boo')),
+ $this->makeOption('--foo', array('action' => 'append'))
+ );
+
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE,
+ 'optionList' => $options));
+ }
+
+ public function testRequiredValue()
+ {
+ $this->assertParseFail(array('-a'),
+ '-a option requires an argument');
+ }
+
+ public function testInvalidInteger()
+ {
+ $this->assertParseFail(array('-b', '5x'),
+ "option -b: invalid integer value: '5x'");
+ }
+
+ public function testNoSuchOption()
+ {
+ $this->assertParseFail(array('--boo13'),
+ "no such option: --boo13");
+ }
+
+ public function testLongInvalidInteger()
+ {
+ $this->assertParseFail(array("--boo=x5"),
+ "option --boo: invalid integer value: 'x5'");
+ }
+
+ public function testEmpty()
+ {
+ $this->assertParseOk(array(),
+ array('a' => null, 'boo' => null, 'foo' => null), array());
+ }
+
+ public function testShortOptEmptyLongOptAppend()
+ {
+ $this->assertParseOk(array("-a", "", "--foo=blah", "--foo="),
+ array('a' => "", 'boo' => null, 'foo' => array("blah", "")),
+ array());
+ }
+
+ public function testLongOptionAppend()
+ {
+ $this->assertParseOk(array("--foo", "bar", "--foo", "", "--foo=x"),
+ array('a' => null,
+ 'boo' => null,
+ 'foo' => array('bar', '', 'x')),
+ array());
+ }
+
+ public function testOptionArgumentJoined()
+ {
+ $this->assertParseOk(array("-abc"),
+ array('a' => "bc", 'boo' => null, 'foo' => null),
+ array());
+ }
+
+ public function testOptionArgumentSplit()
+ {
+ $this->assertParseOk(array("-a", "34"),
+ array('a' => "34", 'boo' => null, 'foo' => null),
+ array());
+ }
+
+ public function testOptionArgumentJoinedInteger()
+ {
+ $this->assertParseOk(array("-b34"),
+ array('a' => null, 'boo' => 34, 'foo' => null),
+ array());
+ }
+
+ public function testOptionArgumentSplitNegativeInteger()
+ {
+ $this->assertParseOk(array("-b", "-5"),
+ array('a' => null, 'boo' => -5, 'foo' => null),
+ array());
+ }
+
+ public function testLongOptionArgumentJoined()
+ {
+ $this->assertParseOk(array("--boo=13"),
+ array('a' => null, 'boo' => 13, 'foo' => null),
+ array());
+ }
+
+ public function testLongOptionArgumentSplit()
+ {
+ $this->assertParseOk(array("--boo", "111"),
+ array('a' => null, 'boo' => 111, 'foo' => null),
+ array());
+ }
+
+ public function testLongOptionShortOption()
+ {
+ $this->assertParseOk(array("--foo=bar", "-axyz"),
+ array('a' => 'xyz', 'boo' => null, 'foo' => array("bar")),
+ array());
+ }
+
+ public function testAbbrevLongOption()
+ {
+ $this->assertParseOk(array("--f=bar", "-axyz"),
+ array('a' => 'xyz', 'boo' => null, 'foo' => array("bar")),
+ array());
+ }
+
+ public function testDefaults()
+ {
+ list($options, $args) = $this->parser->parseArgs(array());
+ $defaults = $this->parser->getDefaultValues();
+
+ $this->assertEquals($defaults, $options);
+ }
+
+ public function testAmbiguousOption()
+ {
+ $this->parser->addOption("--foz", array('action' => 'store',
+ 'type' => 'string', 'dest' => 'foo'));
+ $this->assertParseFail(array('--f=bar'),
+ "ambiguous option: --f (--foo, --foz?)");
+ }
+
+ public function testShortAndLongOptionSplit()
+ {
+ $this->assertParseOk(array("-a", "xyz", "--foo", "bar"),
+ array('a' => 'xyz', 'boo' => null, 'foo' => array("bar")),
+ array());
+ }
+
+ public function testShortOptionSplitLongOptionAppend()
+ {
+ $this->assertParseOk(array("--foo=bar", "-b", "123", "--foo", "baz"),
+ array('a' => null, 'boo' => 123, 'foo' => array("bar", "baz")),
+ array());
+ }
+
+ public function testShortOptionSplitOnePositionalArg()
+ {
+ $this->assertParseOk(array("-a", "foo", "bar"),
+ array('a' => "foo", 'boo' => null, 'foo' => null),
+ array("bar"));
+ }
+
+ public function testShortOptionConsumesSeparator()
+ {
+ $this->assertParseOk(array("-a", "--", "foo", "bar"),
+ array('a' => "--", 'boo' => null, 'foo' => null),
+ array("foo", "bar"));
+
+ $this->assertParseOk(array("-a", "--", "--foo", "bar"),
+ array('a' => "--", 'boo' => null, 'foo' => array("bar")),
+ array());
+ }
+
+ public function testShortOptionJoinedAndSeparator()
+ {
+ $this->assertParseOk(array("-ab", "--", "--foo", "bar"),
+ array('a' => "b", 'boo' => null, 'foo' => null),
+ array("--foo", "bar"));
+ }
+
+ public function testHyphenBecomesPositionalArg()
+ {
+ $this->assertParseOk(array("-ab", "-", "--foo", "bar"),
+ array('a' => "b", 'boo' => null, 'foo' => array("bar")),
+ array("-"));
+ }
+
+ public function testNoAppendVersusAppend()
+ {
+ $this->assertParseOk(array("-b3", "-b", "5", "--foo=bar", "--foo", "baz"),
+ array('a' => null, 'boo' => 5, 'foo' => array("bar", "baz")),
+ array());
+ }
+
+ public function testOptionConsumesOptionLikeString()
+ {
+ $this->assertParseOk(array("-a", "-b3"),
+ array('a' => "-b3", 'boo' => null, 'foo' => null),
+ array());
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_TestBase extends PHPUnit_Framework_TestCase
+{
+ public function makeOption()
+ {
+ $args = func_get_args();
+ $reflector = new ReflectionClass('Horde_Argv_Option');
+ return $reflector->newInstanceArgs($args);
+ }
+
+ /**
+ * Assert the options are what we expected when parsing arguments.
+ *
+ * Otherwise, fail with a nicely formatted message.
+ *
+ * Keyword arguments:
+ * args -- A list of arguments to parse with Horde_Argv_Parser.
+ * expected_opts -- The options expected.
+ * expected_positional_args -- The positional arguments expected.
+ *
+ * Returns the options and positional args for further testing.
+ */
+ public function assertParseOK($args, $expected_opts, $expected_positional_args)
+ {
+ list($options, $positional_args) = $this->parser->parseArgs($args);
+ $optdict = iterator_to_array($options);
+
+ $this->assertEquals($expected_opts, $optdict,
+ 'Expected options don\'t match. Args were ' . print_r($args, true));
+
+ $this->assertEquals($positional_args, $expected_positional_args,
+ 'Positional arguments don\'t match. Args were ' . print_r($args, true));
+
+ return array($options, $positional_args);
+ }
+
+ /**
+ * Assert that the expected exception is raised when calling a
+ * function, and that the right error message is included with
+ * that exception.
+ *
+ * Arguments:
+ * func -- the function to call
+ * args -- positional arguments to `func`
+ * expected_exception -- exception that should be raised
+ * expected_message -- expected exception message (or pattern
+ * if a compiled regex object)
+ *
+ * Returns the exception raised for further testing.
+ */
+ public function assertRaises($func, $args = array(),
+ $expected_exception, $expected_message) {
+ $caught = false;
+ try {
+ if (is_array($args)) {
+ call_user_func_array($func, $args);
+ } else {
+ call_user_func($func);
+ }
+ } catch (Exception $e) {
+ if (get_class($e) == $expected_exception) {
+ $caught = true;
+ $this->assertEquals($expected_message, $e->getMessage(), 'Expected exception message not matched');
+ }
+ }
+
+ if (!$caught) {
+ $this->fail("Expected exception $expected_exception not thrown");
+ }
+ }
+
+ // -- Assertions used in more than one class --------------------
+
+ /**
+ * Assert the parser fails with the expected message. Caller
+ * must ensure that $this->parser is an InterceptingParser.
+ */
+ public function assertParseFail($cmdline_args, $expected_output)
+ {
+ try {
+ $this->parser->parseArgs($cmdline_args);
+ } catch (Horde_Argv_InterceptedException $e) {
+ $this->assertEquals($expected_output, (string)$e);
+ return true;
+ } catch (Exception $e) {
+ $this->fail("unexpected Exception: " . $e->getMessage());
+ }
+
+ $this->fail("expected parse failure");
+ }
+
+ /**
+ * Assert the parser prints the expected output on stdout.
+ */
+ public function assertOutput(
+ $cmdline_args,
+ $expected_output,
+ $expected_status = 0,
+ $expected_error = null)
+ {
+ ob_start();
+ try {
+ $this->parser->parseArgs($cmdline_args);
+ } catch (Horde_Argv_InterceptedException $e) {
+ $output = ob_get_clean();
+
+ $this->assertEquals($expected_output, $output, 'Expected parser output to match');
+ $this->assertEquals($expected_status, $e->exit_status);
+ $this->assertEquals($expected_error, $e->exit_message);
+ return;
+ }
+
+ ob_end_clean();
+
+ $this->fail("expected parser->parserExit()");
+ }
+
+ /**
+ * Assert that TypeError is raised when executing func.
+ */
+ public function assertTypeError($func, $expected_message, $args)
+ {
+ $this->assertRaises($func, $args, 'InvalidArgumentException', $expected_message);
+ }
+
+ public function assertHelp($parser, $expected_help)
+ {
+ $actual_help = $parser->formatHelp();
+ $this->assertEquals($expected_help, $actual_help);
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_TypeAliasesTest extends Horde_Argv_TestBase
+{
+ public function setUp()
+ {
+ $this->parser = new Horde_Argv_Parser();
+ }
+
+ public function testStrAliasesString()
+ {
+ $this->parser->addOption("-s", array('type' => "str"));
+ $this->assertEquals($this->parser->getOption("-s")->type, "string");
+ }
+
+ public function testNewTypeObject()
+ {
+ $this->parser->addOption("-s", array('type' => 'str'));
+ $this->assertEquals($this->parser->getOption("-s")->type, "string");
+ $this->parser->addOption("-x", array('type' => 'int'));
+ $this->assertEquals($this->parser->getOption("-x")->type, "int");
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Mike Naberezny <mike@maintainable.com>
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package Horde_Argv
+ * @subpackage UnitTests
+ */
+
+class Horde_Argv_VersionTest extends Horde_Argv_TestBase
+{
+ public function testVersion()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array(
+ 'usage' => Horde_Argv_Option::SUPPRESS_USAGE,
+ 'version' => "%prog 0.1"));
+ $saveArgv = $_SERVER['argv'];
+ try {
+ $_SERVER['argv'][0] = dirname(__FILE__) . '/foo/bar';
+ $this->assertOutput(array("--version"), "bar 0.1\n");
+ } catch (Exception $e) {
+ $_SERVER['argv'] = $saveArgv;
+ throw $e;
+ }
+
+ $_SERVER['argv'] = $saveArgv;
+ }
+
+ public function testNoVersion()
+ {
+ $this->parser = new Horde_Argv_InterceptingParser(array('usage' => Horde_Argv_Option::SUPPRESS_USAGE));
+ $this->assertParseFail(array("--version"), "no such option: --version");
+ }
+}
--- /dev/null
+D/Argv////
--- /dev/null
+framework/Argv/test/Horde
--- /dev/null
+chuck@cvs.horde.org:/repository
--- /dev/null
+
+Bug:
+Submitted by:
+Merge after:
+CVS: ----------------------------------------------------------------------
+CVS: Bug: Fill this in if a listed bug is affected by the change.
+CVS: Submitted by: Fill this in if someone else sent in the change.
+CVS: Merge after: N [day[s]|week[s]|month[s]] (days assumed by default)