use std::{
ffi::OsStr,
path::PathBuf,
process::{Child, Command, Stdio},
};
use super::{DiffOptions, ExclusiveOption, SubCommand, Unselected};
use crate::global::GlobalOpts;
use crate::spawn::ParameterizedSpawn;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BranchMode {
branch: String,
}
impl ExclusiveOption for BranchMode {
fn inject_args(&self, command: &mut Command) {
command.arg("-b").arg(&self.branch);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamMode {
stream: String,
parent: Option<String>,
}
impl ExclusiveOption for StreamMode {
fn inject_args(&self, command: &mut Command) {
command.arg("-S").arg(&self.stream);
if let Some(parent) = &self.parent {
command.arg("-P").arg(parent);
}
}
}
#[cfg(not(feature = "lt2019_1"))]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct StreamSpecMode;
#[cfg(not(feature = "lt2019_1"))]
impl ExclusiveOption for StreamSpecMode {
fn inject_args(&self, command: &mut Command) {
command.arg("-As");
}
}
#[derive(Debug, Clone, Default)]
pub struct DepotContent<M = Unselected> {
differing_only: bool,
quiet_mode: bool,
diff_nontext: bool,
unified_patch: bool,
mode: M,
}
impl<M: ExclusiveOption> ExclusiveOption for DepotContent<M> {
fn inject_args(&self, command: &mut Command) {
if self.differing_only {
command.arg("-Od");
}
if self.quiet_mode {
command.arg("-q");
}
if self.diff_nontext {
command.arg("-t");
}
if self.unified_patch {
command.arg("-u");
}
self.mode.inject_args(command);
}
}
#[cfg_attr(
feature = "lt2014_2",
doc = "`p4 [g-opts] diff2 [-dflags -Od -q -t -u] file1[rev] file2[rev]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-dflags -Od -q -t -u] -b branch [[fromfile[rev]] tofile[rev]]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-dflags -Od -q -t -u] -S stream [-P parent] [[fromfile[rev]] tofile[rev]]`"
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "`p4 [g-opts] diff2 [-doptions -Od -q -t -u] file1[rev] file2[rev]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions -Od -q -t -u] -b branch [[fromfile[rev]] tofile[rev]]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions -Od -q -t -u] -S stream [-P parent] [[fromfile[rev]] tofile[rev]]`"
)]
#[cfg_attr(
all(feature = "lt2019_1", not(feature = "lt2015_1")),
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] file1[rev] file2[rev]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] -b branch [[fromfile[rev]] tofile[rev]]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] [-S stream] [-P parent] [[fromfile[rev]] tofile[rev]]`"
)]
#[cfg_attr(
not(feature = "lt2019_1"),
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] file1[rev] file2[rev]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] -b branch [[fromfile[rev]] tofile[rev]]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions] [-Od -q -t -u] [-S stream] [-P parent] [[fromfile[rev]] tofile[rev]]`",
doc = "",
doc = "`p4 [g-opts] diff2 [-doptions] -As streamname1[@change1] streamname2[@change2]`"
)]
#[cfg_attr(
not(feature = "lt2019_1"),
doc = "Also compares two arbitrary stream specs with the -As option."
)]
#[cfg_attr(
feature = "lt2019_1",
doc = "The `M` type parameter tracks the command mode at compile time. The default [`Unselected`] state diffs the two depot paths given as spawn arguments; [`Self::differing_only`], [`Self::quiet_mode`], [`Self::diff_nontext`], and [`Self::unified_patch`] transition to the [`DepotContent`] state, and [`Self::branch`] and [`Self::stream`] transition to the depot content [`BranchMode`] and [`StreamMode`] sub-modes."
)]
#[cfg_attr(
not(feature = "lt2019_1"),
doc = "The `M` type parameter tracks the command mode at compile time. The default [`Unselected`] state diffs the two depot paths given as spawn arguments; [`Self::differing_only`], [`Self::quiet_mode`], [`Self::diff_nontext`], and [`Self::unified_patch`] transition to the [`DepotContent`] state, [`Self::branch`] and [`Self::stream`] transition to the depot content [`BranchMode`] and [`StreamMode`] sub-modes, and [`Self::stream_spec_mode`] transitions to the [`StreamSpecMode`] state."
)]
#[derive(Debug, Clone, Default)]
pub struct Diff2<M = Unselected> {
bin: PathBuf,
global_opts: GlobalOpts,
diff_opts: Option<DiffOptions>,
mode: M,
}
impl Diff2<Unselected> {
pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
Self {
bin: bin.into(),
global_opts,
diff_opts: None,
mode: Unselected,
}
}
pub fn differing_only(self, v: bool) -> Diff2<DepotContent<Unselected>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: v,
quiet_mode: false,
diff_nontext: false,
unified_patch: false,
mode: Unselected,
},
}
}
pub fn quiet_mode(self, v: bool) -> Diff2<DepotContent<Unselected>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: false,
quiet_mode: v,
diff_nontext: false,
unified_patch: false,
mode: Unselected,
},
}
}
pub fn diff_nontext(self, v: bool) -> Diff2<DepotContent<Unselected>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: false,
quiet_mode: false,
diff_nontext: v,
unified_patch: false,
mode: Unselected,
},
}
}
#[cfg_attr(feature = "lt2017_2", doc = "remain in Perforce syntax.")]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2017_2")),
doc = "remain in Helix Server syntax."
)]
#[cfg_attr(
all(feature = "lt2024_2", not(feature = "lt2024_1")),
doc = "remain in Helix Core Server syntax."
)]
#[cfg_attr(not(feature = "lt2024_2"), doc = "remain in P4 Server syntax.")]
pub fn unified_patch(self, v: bool) -> Diff2<DepotContent<Unselected>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: false,
quiet_mode: false,
diff_nontext: false,
unified_patch: v,
mode: Unselected,
},
}
}
pub fn branch(self, name: impl Into<String>) -> Diff2<DepotContent<BranchMode>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: false,
quiet_mode: false,
diff_nontext: false,
unified_patch: false,
mode: BranchMode {
branch: name.into(),
},
},
}
}
pub fn stream(self, name: impl Into<String>) -> Diff2<DepotContent<StreamMode>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: false,
quiet_mode: false,
diff_nontext: false,
unified_patch: false,
mode: StreamMode {
stream: name.into(),
parent: None,
},
},
}
}
#[cfg(not(feature = "lt2019_1"))]
pub fn stream_spec_mode(self) -> Diff2<StreamSpecMode> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: StreamSpecMode,
}
}
}
impl<M> Diff2<M> {
#[cfg_attr(
feature = "lt2014_2",
doc = "Runs the diff routine with one of a subset of the standard UNIX diff flags. See the Usage Notes below for a listing of these flags."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See the Usage Notes below for a listing of these options."
)]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2015_1")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage Notes for a listing of these options."
)]
#[cfg_attr(
not(feature = "lt2024_1"),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage notes for a listing of these options."
)]
pub fn get_diff_options(&self) -> Option<&DiffOptions> {
self.diff_opts.as_ref()
}
#[cfg_attr(
feature = "lt2014_2",
doc = "Runs the diff routine with one of a subset of the standard UNIX diff flags. See the Usage Notes below for a listing of these flags."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See the Usage Notes below for a listing of these options."
)]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2015_1")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage Notes for a listing of these options."
)]
#[cfg_attr(
not(feature = "lt2024_1"),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage notes for a listing of these options."
)]
pub fn set_diff_options(&mut self, v: impl Into<DiffOptions>) -> &mut Self {
self.diff_opts = Some(v.into());
self
}
#[cfg_attr(
feature = "lt2014_2",
doc = "Runs the diff routine with one of a subset of the standard UNIX diff flags. See the Usage Notes below for a listing of these flags."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See the Usage Notes below for a listing of these options."
)]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2015_1")),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage Notes for a listing of these options."
)]
#[cfg_attr(
not(feature = "lt2024_1"),
doc = "Runs the diff routine with one of a subset of the standard UNIX diff options. See Usage notes for a listing of these options."
)]
pub fn diff_options(mut self, v: impl Into<DiffOptions>) -> Self {
self.diff_opts = Some(v.into());
self
}
}
impl<M: ExclusiveOption> Diff2<M> {
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn get_global_opts(&self) -> &GlobalOpts {
&self.global_opts
}
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
self.global_opts = v;
self
}
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn global_opts(mut self, v: GlobalOpts) -> Self {
self.global_opts = v;
self
}
}
impl<M> Diff2<DepotContent<M>> {
pub fn get_differing_only(&self) -> bool {
self.mode.differing_only
}
pub fn set_differing_only(&mut self, v: bool) -> &mut Self {
self.mode.differing_only = v;
self
}
pub fn differing_only(mut self, v: bool) -> Self {
self.mode.differing_only = v;
self
}
pub fn get_quiet_mode(&self) -> bool {
self.mode.quiet_mode
}
pub fn set_quiet_mode(&mut self, v: bool) -> &mut Self {
self.mode.quiet_mode = v;
self
}
pub fn quiet_mode(mut self, v: bool) -> Self {
self.mode.quiet_mode = v;
self
}
pub fn get_diff_nontext(&self) -> bool {
self.mode.diff_nontext
}
pub fn set_diff_nontext(&mut self, v: bool) -> &mut Self {
self.mode.diff_nontext = v;
self
}
pub fn diff_nontext(mut self, v: bool) -> Self {
self.mode.diff_nontext = v;
self
}
#[cfg_attr(feature = "lt2017_2", doc = "remain in Perforce syntax.")]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2017_2")),
doc = "remain in Helix Server syntax."
)]
#[cfg_attr(
all(feature = "lt2024_2", not(feature = "lt2024_1")),
doc = "remain in Helix Core Server syntax."
)]
#[cfg_attr(not(feature = "lt2024_2"), doc = "remain in P4 Server syntax.")]
pub fn get_unified_patch(&self) -> bool {
self.mode.unified_patch
}
#[cfg_attr(feature = "lt2017_2", doc = "remain in Perforce syntax.")]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2017_2")),
doc = "remain in Helix Server syntax."
)]
#[cfg_attr(
all(feature = "lt2024_2", not(feature = "lt2024_1")),
doc = "remain in Helix Core Server syntax."
)]
#[cfg_attr(not(feature = "lt2024_2"), doc = "remain in P4 Server syntax.")]
pub fn set_unified_patch(&mut self, v: bool) -> &mut Self {
self.mode.unified_patch = v;
self
}
#[cfg_attr(feature = "lt2017_2", doc = "remain in Perforce syntax.")]
#[cfg_attr(
all(feature = "lt2024_1", not(feature = "lt2017_2")),
doc = "remain in Helix Server syntax."
)]
#[cfg_attr(
all(feature = "lt2024_2", not(feature = "lt2024_1")),
doc = "remain in Helix Core Server syntax."
)]
#[cfg_attr(not(feature = "lt2024_2"), doc = "remain in P4 Server syntax.")]
pub fn unified_patch(mut self, v: bool) -> Self {
self.mode.unified_patch = v;
self
}
}
impl Diff2<DepotContent<Unselected>> {
pub fn branch(self, name: impl Into<String>) -> Diff2<DepotContent<BranchMode>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: self.mode.differing_only,
quiet_mode: self.mode.quiet_mode,
diff_nontext: self.mode.diff_nontext,
unified_patch: self.mode.unified_patch,
mode: BranchMode {
branch: name.into(),
},
},
}
}
pub fn stream(self, name: impl Into<String>) -> Diff2<DepotContent<StreamMode>> {
Diff2 {
bin: self.bin,
global_opts: self.global_opts,
diff_opts: self.diff_opts,
mode: DepotContent {
differing_only: self.mode.differing_only,
quiet_mode: self.mode.quiet_mode,
diff_nontext: self.mode.diff_nontext,
unified_patch: self.mode.unified_patch,
mode: StreamMode {
stream: name.into(),
parent: None,
},
},
}
}
}
impl Diff2<DepotContent<BranchMode>> {
pub fn get_branch(&self) -> &str {
&self.mode.mode.branch
}
pub fn set_branch(&mut self, v: impl Into<String>) -> &mut Self {
self.mode.mode.branch = v.into();
self
}
pub fn branch(mut self, v: impl Into<String>) -> Self {
self.mode.mode.branch = v.into();
self
}
}
impl Diff2<DepotContent<StreamMode>> {
pub fn get_stream(&self) -> &str {
&self.mode.mode.stream
}
pub fn set_stream(&mut self, v: impl Into<String>) -> &mut Self {
self.mode.mode.stream = v.into();
self
}
pub fn stream(mut self, v: impl Into<String>) -> Self {
self.mode.mode.stream = v.into();
self
}
pub fn get_parent(&self) -> Option<&str> {
self.mode.mode.parent.as_deref()
}
pub fn set_parent(&mut self, v: impl Into<String>) -> &mut Self {
self.mode.mode.parent = Some(v.into());
self
}
pub fn parent(mut self, v: impl Into<String>) -> Self {
self.mode.mode.parent = Some(v.into());
self
}
}
impl<M: ExclusiveOption> SubCommand for Diff2<M> {
fn name(&self) -> &str {
"diff2"
}
fn inject_local_args(&self, command: &mut Command) {
if let Some(diff_opts) = &self.diff_opts {
diff_opts.inject_arg(command);
}
self.mode.inject_args(command);
}
fn global_opts(&self) -> Option<&GlobalOpts> {
Some(&self.global_opts)
}
}
impl<A, B> ParameterizedSpawn<(A, B)> for Diff2<Unselected>
where
A: AsRef<OsStr>,
B: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (file1, file2): (A, B)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(file1)
.arg(file2)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<A, B> ParameterizedSpawn<(A, B)> for Diff2<DepotContent<Unselected>>
where
A: AsRef<OsStr>,
B: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (file1, file2): (A, B)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(file1)
.arg(file2)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl ParameterizedSpawn<()> for Diff2<DepotContent<BranchMode>> {
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, _: ()) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<I> ParameterizedSpawn<(I,)> for Diff2<DepotContent<BranchMode>>
where
I: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (tofile,): (I,)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(tofile)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<A, B> ParameterizedSpawn<(A, B)> for Diff2<DepotContent<BranchMode>>
where
A: AsRef<OsStr>,
B: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (fromfile, tofile): (A, B)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(fromfile)
.arg(tofile)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl ParameterizedSpawn<()> for Diff2<DepotContent<StreamMode>> {
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, _: ()) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<I> ParameterizedSpawn<(I,)> for Diff2<DepotContent<StreamMode>>
where
I: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (tofile,): (I,)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(tofile)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<A, B> ParameterizedSpawn<(A, B)> for Diff2<DepotContent<StreamMode>>
where
A: AsRef<OsStr>,
B: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (fromfile, tofile): (A, B)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(fromfile)
.arg(tofile)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
#[cfg(not(feature = "lt2019_1"))]
impl<A, B> ParameterizedSpawn<(A, B)> for Diff2<StreamSpecMode>
where
A: AsRef<OsStr>,
B: AsRef<OsStr>,
{
type Output = Child;
type Error = std::io::Error;
fn spawn_with(&mut self, (spec1, spec2): (A, B)) -> Result<Self::Output, Self::Error> {
self.setup_command(&self.bin)
.arg(spec1)
.arg(spec2)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cmd::DiffOptionsBuilder;
use crate::cmd::args_of;
#[test]
fn without_options() {
let diff2 = Diff2::new("p4", GlobalOpts::new());
assert_eq!(args_of(&diff2.setup_command("p4")), ["diff2"]);
}
#[test]
fn depot_content_flags_are_injected() {
let diff2 = Diff2::new("p4", GlobalOpts::new())
.differing_only(true)
.quiet_mode(true)
.diff_nontext(true)
.unified_patch(true);
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-Od", "-q", "-t", "-u"]
);
}
#[test]
fn depot_content_flags_apply_to_branch_mode() {
let diff2 = Diff2::new("p4", GlobalOpts::new())
.quiet_mode(true)
.branch("branch2");
assert!(diff2.get_quiet_mode());
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-q", "-b", "branch2"]
);
}
#[test]
fn depot_content_flags_apply_after_branch_transition() {
let diff2 = Diff2::new("p4", GlobalOpts::new())
.branch("branch2")
.quiet_mode(true);
assert!(diff2.get_quiet_mode());
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-q", "-b", "branch2"]
);
}
#[test]
fn diff_options_are_injected() {
let mut diff2 =
Diff2::new("p4", GlobalOpts::new()).diff_options(DiffOptionsBuilder::unified(None));
diff2.set_diff_options(DiffOptionsBuilder::summary());
assert_eq!(args_of(&diff2.setup_command("p4")), ["diff2", "-ds"]);
}
#[test]
fn branch_mode_injects_branch() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).branch("branch2");
assert_eq!(diff2.get_branch(), "branch2");
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-b", "branch2"]
);
}
#[test]
fn branch_mode_with_files() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).branch("branch2");
let mut command = diff2.setup_command("p4");
command.arg(OsStr::new("//depot/rel1/..."));
command.arg(OsStr::new("//depot/rel2/...#4"));
assert_eq!(
args_of(&command),
[
"diff2",
"-b",
"branch2",
"//depot/rel1/...",
"//depot/rel2/...#4"
]
);
}
#[test]
fn branch_mode_with_tofile() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).branch("branch2");
let mut command = diff2.setup_command("p4");
command.arg(OsStr::new("//depot/rel2/...#4"));
assert_eq!(
args_of(&command),
["diff2", "-b", "branch2", "//depot/rel2/...#4"]
);
}
#[test]
fn stream_mode_injects_stream() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).stream("myStream");
assert_eq!(diff2.get_stream(), "myStream");
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-S", "myStream"]
);
}
#[test]
fn stream_mode_with_parent() {
let mut diff2 = Diff2::new("p4", GlobalOpts::new()).stream("myStream");
diff2.set_parent("mainStream");
assert_eq!(diff2.get_parent(), Some("mainStream"));
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-S", "myStream", "-P", "mainStream"]
);
}
#[test]
fn stream_mode_with_tofile() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).stream("myStream");
let mut command = diff2.setup_command("p4");
command.arg(OsStr::new("//depot/rel2/...#4"));
assert_eq!(
args_of(&command),
["diff2", "-S", "myStream", "//depot/rel2/...#4"]
);
}
#[test]
fn stream_mode_preserves_diff_options() {
let diff2 = Diff2::new("p4", GlobalOpts::new())
.diff_options(DiffOptionsBuilder::summary())
.stream("myStream");
assert_eq!(
args_of(&diff2.setup_command("p4")),
["diff2", "-ds", "-S", "myStream"]
);
}
#[cfg(not(feature = "lt2019_1"))]
#[test]
fn stream_spec_mode_bare() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).stream_spec_mode();
assert_eq!(args_of(&diff2.setup_command("p4")), ["diff2", "-As"]);
}
#[cfg(not(feature = "lt2019_1"))]
#[test]
fn stream_spec_mode_with_specs() {
let diff2 = Diff2::new("p4", GlobalOpts::new()).stream_spec_mode();
let mut command = diff2.setup_command("p4");
command.arg("myStream@=1");
command.arg("yourStream@2");
assert_eq!(
args_of(&command),
["diff2", "-As", "myStream@=1", "yourStream@2"]
);
}
}