mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00

This uses `toml_edit` to edit the config file in-place. For the moment, it only supports top-level arguments, but can be extended to do other things later.
784 lines
22 KiB
Rust
784 lines
22 KiB
Rust
use super::args::*;
|
|
use super::{ArgList, ConfigOperation, DescriptionMod, Filter, Modification};
|
|
use crate::usage;
|
|
use nom::{branch::alt, combinator::*, sequence::*, IResult};
|
|
use taskchampion::Status;
|
|
|
|
// IMPLEMENTATION NOTE:
|
|
//
|
|
// For each variant of Subcommand, there is a private, empty type of the same name with a `parse`
|
|
// method and a `get_usage` method. The parse methods may handle several subcommands, but always
|
|
// produce the variant of the same name as the type.
|
|
//
|
|
// This organization helps to gather the parsing and usage information into
|
|
// comprehensible chunks of code, to ensure that everything is documented.
|
|
|
|
/// A subcommand is the specific operation that the CLI should execute.
|
|
#[derive(Debug, PartialEq)]
|
|
pub(crate) enum Subcommand {
|
|
/// Display the tool version
|
|
Version,
|
|
|
|
/// Display the help output
|
|
Help {
|
|
/// Give the summary help (fitting on a few lines)
|
|
summary: bool,
|
|
},
|
|
|
|
/// Manipulate configuration
|
|
Config {
|
|
config_operation: ConfigOperation,
|
|
},
|
|
|
|
/// Add a new task
|
|
Add {
|
|
modification: Modification,
|
|
},
|
|
|
|
/// Modify existing tasks
|
|
Modify {
|
|
filter: Filter,
|
|
modification: Modification,
|
|
},
|
|
|
|
/// Lists (reports)
|
|
Report {
|
|
/// The name of the report to show
|
|
report_name: String,
|
|
|
|
/// Additional filter terms beyond those in the report
|
|
filter: Filter,
|
|
},
|
|
|
|
/// Per-task information (typically one task)
|
|
Info {
|
|
filter: Filter,
|
|
debug: bool,
|
|
},
|
|
|
|
/// Basic operations without args
|
|
Gc,
|
|
Sync,
|
|
}
|
|
|
|
impl Subcommand {
|
|
pub(super) fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
all_consuming(alt((
|
|
Version::parse,
|
|
Help::parse,
|
|
Config::parse,
|
|
Add::parse,
|
|
Modify::parse,
|
|
Info::parse,
|
|
Gc::parse,
|
|
Sync::parse,
|
|
// This must come last since it accepts arbitrary report names
|
|
Report::parse,
|
|
)))(input)
|
|
}
|
|
|
|
pub(super) fn get_usage(u: &mut usage::Usage) {
|
|
Version::get_usage(u);
|
|
Help::get_usage(u);
|
|
Config::get_usage(u);
|
|
Add::get_usage(u);
|
|
Modify::get_usage(u);
|
|
Info::get_usage(u);
|
|
Gc::get_usage(u);
|
|
Sync::get_usage(u);
|
|
Report::get_usage(u);
|
|
}
|
|
}
|
|
|
|
struct Version;
|
|
|
|
impl Version {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(_: &str) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Version)
|
|
}
|
|
map_res(
|
|
alt((
|
|
arg_matching(literal("version")),
|
|
arg_matching(literal("--version")),
|
|
)),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "version",
|
|
syntax: "version",
|
|
summary: "Show the TaskChampion version",
|
|
description: "Show the version of the TaskChampion binary",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Help;
|
|
|
|
impl Help {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(input: &str) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Help {
|
|
summary: input == "-h",
|
|
})
|
|
}
|
|
map_res(
|
|
alt((
|
|
arg_matching(literal("help")),
|
|
arg_matching(literal("--help")),
|
|
arg_matching(literal("-h")),
|
|
)),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(_u: &mut usage::Usage) {}
|
|
}
|
|
|
|
struct Config;
|
|
|
|
impl Config {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(input: (&str, ConfigOperation)) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Config {
|
|
config_operation: input.1,
|
|
})
|
|
}
|
|
map_res(
|
|
tuple((arg_matching(literal("config")), ConfigOperation::parse)),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
ConfigOperation::get_usage(u);
|
|
}
|
|
}
|
|
|
|
struct Add;
|
|
|
|
impl Add {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(input: (&str, Modification)) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Add {
|
|
modification: input.1,
|
|
})
|
|
}
|
|
map_res(
|
|
pair(arg_matching(literal("add")), Modification::parse),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "add",
|
|
syntax: "add [modification]",
|
|
summary: "Add a new task",
|
|
description: "
|
|
Add a new, pending task to the list of tasks. The modification must include a
|
|
description.",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Modify;
|
|
|
|
impl Modify {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(input: (Filter, &str, Modification)) -> Result<Subcommand, ()> {
|
|
let filter = input.0;
|
|
let mut modification = input.2;
|
|
|
|
match input.1 {
|
|
"prepend" => {
|
|
if let DescriptionMod::Set(s) = modification.description {
|
|
modification.description = DescriptionMod::Prepend(s)
|
|
}
|
|
}
|
|
"append" => {
|
|
if let DescriptionMod::Set(s) = modification.description {
|
|
modification.description = DescriptionMod::Append(s)
|
|
}
|
|
}
|
|
"start" => modification.active = Some(true),
|
|
"stop" => modification.active = Some(false),
|
|
"done" => modification.status = Some(Status::Completed),
|
|
_ => {}
|
|
}
|
|
|
|
Ok(Subcommand::Modify {
|
|
filter,
|
|
modification,
|
|
})
|
|
}
|
|
map_res(
|
|
tuple((
|
|
Filter::parse,
|
|
alt((
|
|
arg_matching(literal("modify")),
|
|
arg_matching(literal("prepend")),
|
|
arg_matching(literal("append")),
|
|
arg_matching(literal("start")),
|
|
arg_matching(literal("stop")),
|
|
arg_matching(literal("done")),
|
|
)),
|
|
Modification::parse,
|
|
)),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "modify",
|
|
syntax: "[filter] modify [modification]",
|
|
summary: "Modify tasks",
|
|
description: "
|
|
Modify all tasks matching the filter.",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "prepend",
|
|
syntax: "[filter] prepend [modification]",
|
|
summary: "Prepend task description",
|
|
description: "
|
|
Modify all tasks matching the filter by inserting the given description before each
|
|
task's description.",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "append",
|
|
syntax: "[filter] append [modification]",
|
|
summary: "Append task description",
|
|
description: "
|
|
Modify all tasks matching the filter by adding the given description to the end
|
|
of each task's description.",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "start",
|
|
syntax: "[filter] start [modification]",
|
|
summary: "Start tasks",
|
|
description: "
|
|
Start all tasks matching the filter, additionally applying any given modifications."
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "stop",
|
|
syntax: "[filter] stop [modification]",
|
|
summary: "Stop tasks",
|
|
description: "
|
|
Stop all tasks matching the filter, additionally applying any given modifications.",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "done",
|
|
syntax: "[filter] done [modification]",
|
|
summary: "Mark tasks as completed",
|
|
description: "
|
|
Mark all tasks matching the filter as completed, additionally applying any given
|
|
modifications.",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Report;
|
|
|
|
impl Report {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(filter: Filter, report_name: &str) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Report {
|
|
filter,
|
|
report_name: report_name.to_owned(),
|
|
})
|
|
}
|
|
// allow the filter expression before or after the report name
|
|
alt((
|
|
map_res(pair(arg_matching(report_name), Filter::parse), |input| {
|
|
to_subcommand(input.1, input.0)
|
|
}),
|
|
map_res(pair(Filter::parse, arg_matching(report_name)), |input| {
|
|
to_subcommand(input.0, input.1)
|
|
}),
|
|
// default to a "next" report
|
|
map_res(Filter::parse, |input| to_subcommand(input, "next")),
|
|
))(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "report",
|
|
syntax: "[filter] [report-name] *or* [report-name] [filter]",
|
|
summary: "Show a report",
|
|
description: "
|
|
Show the named report, including only tasks matching the filter",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "next",
|
|
syntax: "[filter]",
|
|
summary: "Show the 'next' report",
|
|
description: "
|
|
Show the report named 'next', including only tasks matching the filter",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Info;
|
|
|
|
impl Info {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(input: (Filter, &str)) -> Result<Subcommand, ()> {
|
|
let debug = input.1 == "debug";
|
|
Ok(Subcommand::Info {
|
|
filter: input.0,
|
|
debug,
|
|
})
|
|
}
|
|
map_res(
|
|
pair(
|
|
Filter::parse,
|
|
alt((
|
|
arg_matching(literal("info")),
|
|
arg_matching(literal("debug")),
|
|
)),
|
|
),
|
|
to_subcommand,
|
|
)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "info",
|
|
syntax: "[filter] info",
|
|
summary: "Show tasks",
|
|
description: " Show information about all tasks matching the fiter.",
|
|
});
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "debug",
|
|
syntax: "[filter] debug",
|
|
summary: "Show task debug details",
|
|
description: " Show all key/value properties of the tasks matching the fiter.",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Gc;
|
|
|
|
impl Gc {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(_: &str) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Gc)
|
|
}
|
|
map_res(arg_matching(literal("gc")), to_subcommand)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "gc",
|
|
syntax: "gc",
|
|
summary: "Perform 'garbage collection'",
|
|
description: "
|
|
Perform 'garbage collection'. This refreshes the list of pending tasks
|
|
and their short id's.",
|
|
});
|
|
}
|
|
}
|
|
|
|
struct Sync;
|
|
|
|
impl Sync {
|
|
fn parse(input: ArgList) -> IResult<ArgList, Subcommand> {
|
|
fn to_subcommand(_: &str) -> Result<Subcommand, ()> {
|
|
Ok(Subcommand::Sync)
|
|
}
|
|
map_res(arg_matching(literal("sync")), to_subcommand)(input)
|
|
}
|
|
|
|
fn get_usage(u: &mut usage::Usage) {
|
|
u.subcommands.push(usage::Subcommand {
|
|
name: "sync",
|
|
syntax: "sync",
|
|
summary: "Synchronize this replica",
|
|
description: "
|
|
Synchronize this replica locally or against a remote server, as configured.
|
|
|
|
Synchronization is a critical part of maintaining the task database, and should
|
|
be done regularly, even if only locally. It is typically run in a crontask.",
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use crate::argparse::Condition;
|
|
|
|
const EMPTY: Vec<&str> = vec![];
|
|
|
|
#[test]
|
|
fn test_version() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["version"]).unwrap(),
|
|
(&EMPTY[..], Subcommand::Version)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_dd_version() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["--version"]).unwrap(),
|
|
(&EMPTY[..], Subcommand::Version)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_d_h() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["-h"]).unwrap(),
|
|
(&EMPTY[..], Subcommand::Help { summary: true })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_help() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["help"]).unwrap(),
|
|
(&EMPTY[..], Subcommand::Help { summary: false })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_dd_help() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["--help"]).unwrap(),
|
|
(&EMPTY[..], Subcommand::Help { summary: false })
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_config_set() {
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["config", "set", "x", "y"]).unwrap(),
|
|
(
|
|
&EMPTY[..],
|
|
Subcommand::Config {
|
|
config_operation: ConfigOperation::Set("x".to_owned(), "y".to_owned())
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_add_description() {
|
|
let subcommand = Subcommand::Add {
|
|
modification: Modification {
|
|
description: DescriptionMod::Set(s!("foo")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["add", "foo"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_add_description_multi() {
|
|
let subcommand = Subcommand::Add {
|
|
modification: Modification {
|
|
description: DescriptionMod::Set(s!("foo bar")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["add", "foo", "bar"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_modify_description_multi() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
description: DescriptionMod::Set(s!("foo bar")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "modify", "foo", "bar"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_append() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
description: DescriptionMod::Append(s!("foo bar")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "append", "foo", "bar"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_prepend() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
description: DescriptionMod::Prepend(s!("foo bar")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "prepend", "foo", "bar"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_done() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
status: Some(Status::Completed),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "done"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_done_modify() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
description: DescriptionMod::Set(s!("now-finished")),
|
|
status: Some(Status::Completed),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "done", "now-finished"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_start() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
active: Some(true),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "start"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_start_modify() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
active: Some(true),
|
|
description: DescriptionMod::Set(s!("mod")),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "start", "mod"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_stop() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
active: Some(false),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "stop"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_stop_modify() {
|
|
let subcommand = Subcommand::Modify {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(123)])],
|
|
},
|
|
modification: Modification {
|
|
description: DescriptionMod::Set(s!("mod")),
|
|
active: Some(false),
|
|
..Default::default()
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["123", "stop", "mod"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_report() {
|
|
let subcommand = Subcommand::Report {
|
|
filter: Default::default(),
|
|
report_name: "myreport".to_owned(),
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["myreport"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_report_filter_before() {
|
|
let subcommand = Subcommand::Report {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![
|
|
TaskId::WorkingSetId(12),
|
|
TaskId::WorkingSetId(13),
|
|
])],
|
|
},
|
|
report_name: "foo".to_owned(),
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["12,13", "foo"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_report_filter_after() {
|
|
let subcommand = Subcommand::Report {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![
|
|
TaskId::WorkingSetId(12),
|
|
TaskId::WorkingSetId(13),
|
|
])],
|
|
},
|
|
report_name: "foo".to_owned(),
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["foo", "12,13"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_report_filter_next() {
|
|
let subcommand = Subcommand::Report {
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![
|
|
TaskId::WorkingSetId(12),
|
|
TaskId::WorkingSetId(13),
|
|
])],
|
|
},
|
|
report_name: "next".to_owned(),
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["12,13"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_report_next() {
|
|
let subcommand = Subcommand::Report {
|
|
filter: Filter {
|
|
..Default::default()
|
|
},
|
|
report_name: "next".to_owned(),
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv![]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_info_filter() {
|
|
let subcommand = Subcommand::Info {
|
|
debug: false,
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![
|
|
TaskId::WorkingSetId(12),
|
|
TaskId::WorkingSetId(13),
|
|
])],
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["12,13", "info"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_debug_filter() {
|
|
let subcommand = Subcommand::Info {
|
|
debug: true,
|
|
filter: Filter {
|
|
conditions: vec![Condition::IdList(vec![TaskId::WorkingSetId(12)])],
|
|
},
|
|
};
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["12", "debug"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_gc() {
|
|
let subcommand = Subcommand::Gc;
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["gc"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_gc_extra_args() {
|
|
assert!(Subcommand::parse(argv!["gc", "foo"]).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_sync() {
|
|
let subcommand = Subcommand::Sync;
|
|
assert_eq!(
|
|
Subcommand::parse(argv!["sync"]).unwrap(),
|
|
(&EMPTY[..], subcommand)
|
|
);
|
|
}
|
|
}
|