Skip to content

Instantly share code, notes, and snippets.

@ExpHP
Last active June 7, 2017 15:10
Show Gist options
  • Select an option

  • Save ExpHP/bfb5a2cc0a0a170e4d864f9694304dde to your computer and use it in GitHub Desktop.

Select an option

Save ExpHP/bfb5a2cc0a0a170e4d864f9694304dde to your computer and use it in GitHub Desktop.
#[cfg(test)]
mod test_parsing {
// NOTES:
// OptionStore holds the defined options for a program.
// The function being tested canonicalizes arguments like getopt.
//
// .add_short() and .add_long() take a "number of option arguments" argument, (e.g. Precisely(2))
// because I mistakenly thought that options were allowed to take more than one.
// YOU CAN IGNORE ANY TEST WHERE THE INPUT SUPPLIES AN OPTION THAT TAKES MULTIPLE ARGUMENTS
//
// IIRC abbreviations for long options are not tested because the feature
// is dumb and so I didn't implement it.
#[test]
fn no_input() {
let store = OptionStore::new();
check!(&store, [], []);
}
#[test]
fn unusual_positionals() {
let mut store = OptionStore::new();
store.add_short('a', Precisely(0));
store.add_long("foo", Precisely(0));
for s in vec![
"", "-", // special cases
" -a", " -q", " --foo", " --bar", // space before option
] {
check!(&store, ["a", s, "b"], [pos("a"), pos(s), pos("b")]);
}
}
#[test]
fn short_options() {
let mut store = OptionStore::new();
for c in "abcd".chars() {
store.add_short(c, Precisely(0));
}
store.add_short('X', Precisely(1));
store.add_short('Y', Precisely(2));
store.add_short('o', Optional);
// a short
check!(&store, ["-a"], [short('a')]);
check!(&store, ["-q"], unknown_short('q'));
// many shorts
check!(&store, ["-abcd"], [short('a'), short('b'), short('c'), short('d')]);
check!(&store, ["-abqd"], unknown_short('q'));
// shorts with arguments
check!(&store, ["-aX", "cq"], [short('a'), short('X', "cq")]);
check!(&store, ["-aXcq"], [short('a'), short('X', "cq")]);
check!(&store, ["-aY", "cq", "a"], [short('a'), short('Y', "cq", "a")]);
check!(&store, ["-aYcq", "a"], [short('a'), short('Y', "cq", "a")]);
// argument errors
check!(&store, ["-aX"], missing_arg_short(&store, 'X', 0));
check!(&store, ["-aY"], missing_arg_short(&store, 'Y', 0));
check!(&store, ["-aY", "cq"], missing_arg_short(&store, 'Y', 1));
check!(&store, ["-aYcq"], missing_arg_short(&store, 'Y', 1));
// optional arguments
check!(&store, ["-o"], [short('o', "")]);
check!(&store, ["-o", "-a"], [short('o', ""), short('a')]);
check!(&store, ["-oa"], [short('o', "a")]);
// interpretation of = sign (or rather, the lack thereof)
check!(&store, ["-X=cd"], [short('X', "=cd")]);
// argument which resembles an option
check!(&store, ["-X", "-q"], [short('X', "-q")]); // no "unknown option"
check!(&store, ["-X", "-X"], [short('X', "-X")]); // no "missing arg"
// empty argument
check!(&store, ["-X", ""], [short('X', "")]);
// don't eat too many args
check!(&store, ["-a", "a"], [short('a'), pos("a")]);
check!(&store, ["-Y", "a", "b", "c"], [short('Y', "a", "b"), pos("c")]);
}
#[test]
fn long_options() {
let mut store = OptionStore::new();
store.add_long("foo", Precisely(0));
store.add_long("no-bar", Precisely(0)); // something with a hyphen
store.add_long("one", Precisely(1));
store.add_long("two", Precisely(2));
store.add_long("opt", Optional);
// a long
check!(&store, ["--foo"], [long("foo")]);
check!(&store, ["--no-bar"], [long("no-bar")]);
check!(&store, ["--derp"], unknown_long("derp"));
// longs with arguments
check!(&store, ["--one=arg"], [long("one", "arg")]);
check!(&store, ["--one", "arg"], [long("one", "arg")]);
check!(&store, ["--two=arg", "yar"], [long("two", "arg", "yar")]);
check!(&store, ["--two", "arg", "yar"], [long("two", "arg", "yar")]);
// argument errors
check!(&store, ["--foo=a"], unexpected_arg_long(&store, "foo"));
check!(&store, ["--foo="], unexpected_arg_long(&store, "foo"));
check!(&store, ["--one"], missing_arg_long(&store, "one", 0));
check!(&store, ["--two"], missing_arg_long(&store, "two", 0));
check!(&store, ["--two", "a"], missing_arg_long(&store, "two", 1));
check!(&store, ["--two=a"], missing_arg_long(&store, "two", 1));
// optional arguments
check!(&store, ["--opt=a"], [long("opt", "a")]);
check!(&store, ["--opt", "a"], [long("opt", ""), pos("a")]);
check!(&store, ["--opt="], [long("opt", "")]);
check!(&store, ["--opt"], [long("opt", "")]);
// argument containing literal '='
check!(&store, ["--one", "a=b"], [long("one", "a=b")]);
check!(&store, ["--one=a=b"], [long("one", "a=b")]);
// argument which resembles an option
check!(&store, ["--one", "--derp"], [long("one", "--derp")]); // no "unknown option"
check!(&store, ["--one", "--one"], [long("one", "--one")]); // no "missing arg"
// empty argument
check!(&store, ["--one", ""], [long("one", "")]);
check!(&store, ["--one="], [long("one", "")]);
// don't eat too many args
check!(&store, ["--foo", "a"], [long("foo"), pos("a")]);
check!(&store, ["--two", "a", "b", "c"], [long("two", "a", "b"), pos("c")]);
}
#[test]
fn test_double_dashes() {
let mut store = OptionStore::new();
store.add_short('X', Precisely(1));
store.add_long("one", Precisely(1));
// everything after a double dash is a positional arg...
check!(&store, ["--", "--", "--"], [dd(), pos("--"), pos("--")]);
check!(&store, ["--", "-X3", "--one=3"], [dd(), pos("-X3"), pos("--one=3")]);
check!(&store, ["--", "-q"], [dd(), pos("-q")]); // no "unknown option"
check!(&store, ["--", "--bar"], [dd(), pos("--bar")]);
check!(&store, ["--", "-X"], [dd(), pos("-X")]); // no "missing option arg"
check!(&store, ["--", "--one"], [dd(), pos("--one")]);
// double dash can be interpreted as an option argument instead, in which case the above
// no longer applies. Fiendish!
check!(&store, ["-X", "--", "--", "--"], [short('X', "--"), dd(), pos("--")]);
check!(&store, ["-X", "--", "-X3", "--one=3"], [short('X', "--"), short('X', "3"), long("one", "3")]);
check!(&store, ["-X", "--", "-q"], unknown_short('q'));
check!(&store, ["-X", "--", "--bar"], unknown_long("bar"));
check!(&store, ["-X", "--", "-X"], missing_arg_short(&store, 'X', 0));
check!(&store, ["-X", "--", "--one"], missing_arg_long(&store, "one", 0));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment