1use std::{
2 ffi::OsStr,
3 path::{Path, PathBuf},
4 process::{Child, Command, Stdio},
5};
6
7use super::{DiffOptions, ExclusiveOption, SubCommand, Unselected};
8
9use crate::global::GlobalOpts;
10use crate::spawn::ParameterizedSpawn;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum DisplayOptions {
19 OpenedChangedOrMissing,
24
25 ResolvedThenModified,
30
31 UnopenedMissing,
36
37 UnopenedChanged,
42
43 #[cfg_attr(
49 feature = "lt2014_2",
50 doc = "If you use the `-f` flag together with the `-sl` flag, files that are open for edit are also compared and their status is listed."
51 )]
52 #[cfg_attr(
53 not(feature = "lt2014_2"),
54 doc = "If you use the `-f` option together with the `-sl` option, files that are open for edit are also compared and their status is listed."
55 )]
56 ListWithStatus,
60
61 OpenedIdentical,
66}
67
68impl DisplayOptions {
69 pub fn as_str(&self) -> &'static str {
71 match self {
72 DisplayOptions::OpenedChangedOrMissing => "-sa",
73 DisplayOptions::ResolvedThenModified => "-sb",
74 DisplayOptions::UnopenedMissing => "-sd",
75 DisplayOptions::UnopenedChanged => "-se",
76 DisplayOptions::ListWithStatus => "-sl",
77 DisplayOptions::OpenedIdentical => "-sr",
78 }
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub struct WorkspaceDisplayMode {
88 display_opts: DisplayOptions,
89}
90
91impl ExclusiveOption for WorkspaceDisplayMode {
92 fn inject_args(&self, command: &mut Command) {
93 command.arg(self.display_opts.as_str());
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub struct WorkspaceRegularMode {
103 limit: u64,
104}
105
106impl ExclusiveOption for WorkspaceRegularMode {
107 fn inject_args(&self, command: &mut Command) {
108 command.arg("-m").arg(self.limit.to_string());
109 }
110}
111
112#[derive(Debug, Clone, Default)]
123pub struct WorkspaceMode<M = Unselected> {
124 force: bool,
125
126 differing_only: bool,
127
128 diff_nontext: bool,
129
130 mode: M,
131}
132
133impl<M: ExclusiveOption> ExclusiveOption for WorkspaceMode<M> {
134 fn inject_args(&self, command: &mut Command) {
135 if self.force {
136 command.arg("-f");
137 }
138
139 if self.diff_nontext {
140 command.arg("-t");
141 }
142
143 if self.differing_only {
144 command.arg("-Od");
145 }
146
147 self.mode.inject_args(command);
148 }
149}
150
151#[cfg(not(feature = "lt2019_1"))]
158#[derive(Debug, Clone, Default, PartialEq, Eq)]
159pub struct StreamSpecMode;
160
161#[cfg(not(feature = "lt2019_1"))]
162impl ExclusiveOption for StreamSpecMode {
163 fn inject_args(&self, command: &mut Command) {
164 command.arg("-As");
165 }
166}
167
168#[cfg_attr(
169 feature = "lt2014_2",
170 doc = "`p4 [g-opts] diff [-dflags -f -m max -Od -sa -sb -sd -se -sr -sl -t] [file[rev#]...]`"
171)]
172#[cfg_attr(
173 all(feature = "lt2015_1", not(feature = "lt2014_2")),
174 doc = "`p4 [g-opts] diff [-doptions -f -m max -Od -sa -sb -sd -se -sr -sl -t] [file[rev#]...]`"
175)]
176#[cfg_attr(
177 all(feature = "lt2016_1", not(feature = "lt2015_1")),
178 doc = "`p4 [g-opts] diff [-doptions] [-f -t -Od] [-m max] [-soptions] [file[rev] …]`"
179)]
180#[cfg_attr(
181 all(feature = "lt2019_1", not(feature = "lt2016_1")),
182 doc = "`p4 [g-opts] diff [-doptions] [-f -t -Od] [-m max] [-soptions] [file[rev] ...]`"
183)]
184#[cfg_attr(
185 not(feature = "lt2019_1"),
186 doc = "`p4 [g-opts] diff [-doptions] [-f -t -Od] [-m max] [-soptions] [file[rev] ...]`",
187 doc = "",
188 doc = "`p4 [g-opts] diff [-doptions] -As [streamname[@change]]`"
189)]
190#[cfg_attr(not(feature = "lt2019_1"), doc = "Also for stream spec comparison.")]
195#[cfg_attr(
197 feature = "lt2019_1",
198 doc = "The `M` type parameter tracks the command mode at compile time. The default [`Unselected`] state offers the workspace content options; [`Self::force`], [`Self::differing_only`], and [`Self::diff_nontext`] transition to the [`WorkspaceMode`] state."
199)]
200#[cfg_attr(
201 not(feature = "lt2019_1"),
202 doc = "The `M` type parameter tracks the command mode at compile time. The default [`Unselected`] state offers neither the workspace content options nor `-As`; [`Self::force`], [`Self::differing_only`], and [`Self::diff_nontext`] transition to the [`WorkspaceMode`] state, while [`Self::stream_spec_mode`] transitions to the [`StreamSpecMode`] state."
203)]
204#[derive(Debug, Clone, Default)]
205pub struct Diff<M = Unselected> {
206 bin: PathBuf,
207
208 global_opts: GlobalOpts,
209
210 diff_opts: Option<DiffOptions>,
211
212 mode: M,
213}
214
215impl Diff<Unselected> {
216 pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
220 Self {
221 bin: bin.into(),
222 global_opts,
223 diff_opts: None,
224 mode: Unselected,
225 }
226 }
227
228 pub fn force(self, v: bool) -> Diff<WorkspaceMode<Unselected>> {
238 Diff {
239 bin: self.bin,
240 global_opts: self.global_opts,
241 diff_opts: self.diff_opts,
242 mode: WorkspaceMode {
243 force: v,
244 differing_only: false,
245 diff_nontext: false,
246 mode: Unselected,
247 },
248 }
249 }
250
251 pub fn differing_only(self, v: bool) -> Diff<WorkspaceMode<Unselected>> {
260 Diff {
261 bin: self.bin,
262 global_opts: self.global_opts,
263 diff_opts: self.diff_opts,
264 mode: WorkspaceMode {
265 force: false,
266 differing_only: v,
267 diff_nontext: false,
268 mode: Unselected,
269 },
270 }
271 }
272
273 pub fn diff_nontext(self, v: bool) -> Diff<WorkspaceMode<Unselected>> {
282 Diff {
283 bin: self.bin,
284 global_opts: self.global_opts,
285 diff_opts: self.diff_opts,
286 mode: WorkspaceMode {
287 force: false,
288 differing_only: false,
289 diff_nontext: v,
290 mode: Unselected,
291 },
292 }
293 }
294
295 #[cfg_attr(
304 feature = "lt2024_2",
305 doc = "Limitation: Although this option requires the user have at least the `list` access to the stream path, it ignores any other entry in the protections table, including any minus sign (`-`) that would otherwise block the operation."
306 )]
307 #[cfg_attr(
308 not(feature = "lt2024_2"),
309 doc = "Although this option requires the user have at least the `list` access to the stream path, it ignores any other entry in the protections table, including any minus sign (`-`) that would otherwise block the operation."
310 )]
311 #[cfg(not(feature = "lt2019_1"))]
317 pub fn stream_spec_mode(self) -> Diff<StreamSpecMode> {
318 Diff {
319 bin: self.bin,
320 global_opts: self.global_opts,
321 diff_opts: self.diff_opts,
322 mode: StreamSpecMode,
323 }
324 }
325}
326
327impl<M> Diff<M> {
328 #[cfg_attr(
333 feature = "lt2014_2",
334 doc = "Pass flags to the underlying diff routine (see the Usage Notes below for details)"
335 )]
336 #[cfg_attr(
337 all(feature = "lt2015_1", not(feature = "lt2014_2")),
338 doc = "Pass options to the underlying diff routine (see the Usage Notes below for details)."
339 )]
340 #[cfg_attr(
341 all(feature = "lt2024_1", not(feature = "lt2015_1")),
342 doc = "Pass options to the underlying diff routine (see Usage Notes for details)."
343 )]
344 #[cfg_attr(
345 not(feature = "lt2024_1"),
346 doc = "Pass options to the underlying diff routine (see Usage notes for details)."
347 )]
348 pub fn get_diff_options(&self) -> Option<&DiffOptions> {
349 self.diff_opts.as_ref()
350 }
351
352 #[cfg_attr(
357 feature = "lt2014_2",
358 doc = "Pass flags to the underlying diff routine (see the Usage Notes below for details)"
359 )]
360 #[cfg_attr(
361 all(feature = "lt2015_1", not(feature = "lt2014_2")),
362 doc = "Pass options to the underlying diff routine (see the Usage Notes below for details)."
363 )]
364 #[cfg_attr(
365 all(feature = "lt2024_1", not(feature = "lt2015_1")),
366 doc = "Pass options to the underlying diff routine (see Usage Notes for details)."
367 )]
368 #[cfg_attr(
369 not(feature = "lt2024_1"),
370 doc = "Pass options to the underlying diff routine (see Usage notes for details)."
371 )]
372 pub fn set_diff_options(&mut self, v: impl Into<DiffOptions>) -> &mut Self {
373 self.diff_opts = Some(v.into());
374 self
375 }
376
377 #[cfg_attr(
382 feature = "lt2014_2",
383 doc = "Pass flags to the underlying diff routine (see the Usage Notes below for details)"
384 )]
385 #[cfg_attr(
386 all(feature = "lt2015_1", not(feature = "lt2014_2")),
387 doc = "Pass options to the underlying diff routine (see the Usage Notes below for details)."
388 )]
389 #[cfg_attr(
390 all(feature = "lt2024_1", not(feature = "lt2015_1")),
391 doc = "Pass options to the underlying diff routine (see Usage Notes for details)."
392 )]
393 #[cfg_attr(
394 not(feature = "lt2024_1"),
395 doc = "Pass options to the underlying diff routine (see Usage notes for details)."
396 )]
397 pub fn diff_options(mut self, v: impl Into<DiffOptions>) -> Self {
398 self.diff_opts = Some(v.into());
399 self
400 }
401}
402
403impl<M: ExclusiveOption> Diff<M> {
404 pub fn get_bin(&self) -> &Path {
406 &self.bin
407 }
408
409 pub fn set_bin(&mut self, bin: impl Into<PathBuf>) -> &mut Self {
411 self.bin = bin.into();
412 self
413 }
414
415 pub fn bin(mut self, bin: impl Into<PathBuf>) -> Self {
417 self.set_bin(bin);
418 self
419 }
420
421 #[cfg_attr(
426 feature = "lt2014_2",
427 doc = "See the [Global Options](GlobalOpts) section."
428 )]
429 #[cfg_attr(
430 all(feature = "lt2015_1", not(feature = "lt2014_2")),
431 doc = "See the [“Global Options”](GlobalOpts) section."
432 )]
433 #[cfg_attr(
434 all(feature = "lt2017_1", not(feature = "lt2015_1")),
435 doc = "See [“Global Options”](GlobalOpts)."
436 )]
437 #[cfg_attr(
438 all(feature = "lt2018_2", not(feature = "lt2017_1")),
439 doc = "See [Global Options](GlobalOpts)."
440 )]
441 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
442 pub fn get_global_opts(&self) -> &GlobalOpts {
443 &self.global_opts
444 }
445
446 #[cfg_attr(
451 feature = "lt2014_2",
452 doc = "See the [Global Options](GlobalOpts) section."
453 )]
454 #[cfg_attr(
455 all(feature = "lt2015_1", not(feature = "lt2014_2")),
456 doc = "See the [“Global Options”](GlobalOpts) section."
457 )]
458 #[cfg_attr(
459 all(feature = "lt2017_1", not(feature = "lt2015_1")),
460 doc = "See [“Global Options”](GlobalOpts)."
461 )]
462 #[cfg_attr(
463 all(feature = "lt2018_2", not(feature = "lt2017_1")),
464 doc = "See [Global Options](GlobalOpts)."
465 )]
466 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
467 pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
468 self.global_opts = v;
469 self
470 }
471
472 #[cfg_attr(
477 feature = "lt2014_2",
478 doc = "See the [Global Options](GlobalOpts) section."
479 )]
480 #[cfg_attr(
481 all(feature = "lt2015_1", not(feature = "lt2014_2")),
482 doc = "See the [“Global Options”](GlobalOpts) section."
483 )]
484 #[cfg_attr(
485 all(feature = "lt2017_1", not(feature = "lt2015_1")),
486 doc = "See [“Global Options”](GlobalOpts)."
487 )]
488 #[cfg_attr(
489 all(feature = "lt2018_2", not(feature = "lt2017_1")),
490 doc = "See [Global Options](GlobalOpts)."
491 )]
492 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
493 pub fn global_opts(mut self, v: GlobalOpts) -> Self {
494 self.global_opts = v;
495 self
496 }
497}
498
499impl<M> Diff<WorkspaceMode<M>> {
500 pub fn get_force(&self) -> bool {
507 self.mode.force
508 }
509
510 pub fn set_force(&mut self, v: bool) -> &mut Self {
517 self.mode.force = v;
518 self
519 }
520
521 pub fn force(mut self, v: bool) -> Self {
528 self.mode.force = v;
529 self
530 }
531
532 pub fn get_differing_only(&self) -> bool {
538 self.mode.differing_only
539 }
540
541 pub fn set_differing_only(&mut self, v: bool) -> &mut Self {
547 self.mode.differing_only = v;
548 self
549 }
550
551 pub fn differing_only(mut self, v: bool) -> Self {
557 self.mode.differing_only = v;
558 self
559 }
560
561 pub fn get_diff_nontext(&self) -> bool {
567 self.mode.diff_nontext
568 }
569
570 pub fn set_diff_nontext(&mut self, v: bool) -> &mut Self {
576 self.mode.diff_nontext = v;
577 self
578 }
579
580 pub fn diff_nontext(mut self, v: bool) -> Self {
586 self.mode.diff_nontext = v;
587 self
588 }
589}
590
591impl Diff<WorkspaceMode<Unselected>> {
592 #[cfg_attr(feature = "lt2015_1", doc = "-sa, -sb, -sd, -se, -sr, -sl file ...")]
595 #[cfg_attr(not(feature = "lt2015_1"), doc = "-soptions")]
596 #[cfg_attr(
598 feature = "lt2015_1",
599 doc = "Pass one of the display options; see the individual option descriptions for details."
600 )]
601 #[cfg_attr(
602 all(feature = "lt2024_1", not(feature = "lt2015_1")),
603 doc = "Pass display options to the underlying diff routine (see Usage Notes for details)."
604 )]
605 #[cfg_attr(
606 not(feature = "lt2024_1"),
607 doc = "Pass display options to the underlying diff routine (see Usage notes for details)."
608 )]
609 pub fn display_options(self, v: DisplayOptions) -> Diff<WorkspaceMode<WorkspaceDisplayMode>> {
613 Diff {
614 bin: self.bin,
615 global_opts: self.global_opts,
616 diff_opts: self.diff_opts,
617 mode: WorkspaceMode {
618 force: self.mode.force,
619 differing_only: self.mode.differing_only,
620 diff_nontext: self.mode.diff_nontext,
621 mode: WorkspaceDisplayMode { display_opts: v },
622 },
623 }
624 }
625
626 #[cfg_attr(
631 feature = "lt2014_2",
632 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` flag is used, in which case the `-m` flag is ignored."
633 )]
634 #[cfg_attr(
635 not(feature = "lt2014_2"),
636 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` option is used, in which case the `-m` option is ignored."
637 )]
638 pub fn limit(self, max: u64) -> Diff<WorkspaceMode<WorkspaceRegularMode>> {
642 Diff {
643 bin: self.bin,
644 global_opts: self.global_opts,
645 diff_opts: self.diff_opts,
646 mode: WorkspaceMode {
647 force: self.mode.force,
648 differing_only: self.mode.differing_only,
649 diff_nontext: self.mode.diff_nontext,
650 mode: WorkspaceRegularMode { limit: max },
651 },
652 }
653 }
654}
655
656impl Diff<WorkspaceMode<WorkspaceDisplayMode>> {
657 #[cfg_attr(feature = "lt2015_1", doc = "-sa, -sb, -sd, -se, -sr, -sl file ...")]
660 #[cfg_attr(not(feature = "lt2015_1"), doc = "-soptions")]
661 #[cfg_attr(
663 feature = "lt2015_1",
664 doc = "Pass one of the display options; see the individual option descriptions for details."
665 )]
666 #[cfg_attr(
667 all(feature = "lt2024_1", not(feature = "lt2015_1")),
668 doc = "Pass display options to the underlying diff routine (see Usage Notes for details)."
669 )]
670 #[cfg_attr(
671 not(feature = "lt2024_1"),
672 doc = "Pass display options to the underlying diff routine (see Usage notes for details)."
673 )]
674 pub fn get_display_options(&self) -> &DisplayOptions {
675 &self.mode.mode.display_opts
676 }
677
678 #[cfg_attr(feature = "lt2015_1", doc = "-sa, -sb, -sd, -se, -sr, -sl file ...")]
681 #[cfg_attr(not(feature = "lt2015_1"), doc = "-soptions")]
682 #[cfg_attr(
684 feature = "lt2015_1",
685 doc = "Pass one of the display options; see the individual option descriptions for details."
686 )]
687 #[cfg_attr(
688 all(feature = "lt2024_1", not(feature = "lt2015_1")),
689 doc = "Pass display options to the underlying diff routine (see Usage Notes for details)."
690 )]
691 #[cfg_attr(
692 not(feature = "lt2024_1"),
693 doc = "Pass display options to the underlying diff routine (see Usage notes for details)."
694 )]
695 pub fn set_display_options(&mut self, v: DisplayOptions) -> &mut Self {
696 self.mode.mode.display_opts = v;
697 self
698 }
699}
700
701impl Diff<WorkspaceMode<WorkspaceRegularMode>> {
702 #[cfg_attr(
707 feature = "lt2014_2",
708 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` flag is used, in which case the `-m` flag is ignored."
709 )]
710 #[cfg_attr(
711 not(feature = "lt2014_2"),
712 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` option is used, in which case the `-m` option is ignored."
713 )]
714 pub fn get_limit(&self) -> u64 {
715 self.mode.mode.limit
716 }
717
718 #[cfg_attr(
723 feature = "lt2014_2",
724 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` flag is used, in which case the `-m` flag is ignored."
725 )]
726 #[cfg_attr(
727 not(feature = "lt2014_2"),
728 doc = "Limit output to diffs (or status) of only the first `max` files, unless the `-s` option is used, in which case the `-m` option is ignored."
729 )]
730 pub fn set_limit(&mut self, v: u64) -> &mut Self {
731 self.mode.mode.limit = v;
732 self
733 }
734}
735
736impl<M: ExclusiveOption> SubCommand for Diff<M> {
737 fn name(&self) -> &str {
738 "diff"
739 }
740
741 fn inject_local_args(&self, command: &mut Command) {
742 if let Some(diff_opts) = &self.diff_opts {
743 diff_opts.inject_arg(command);
744 }
745
746 self.mode.inject_args(command);
747 }
748
749 fn global_opts(&self) -> Option<&GlobalOpts> {
750 Some(&self.global_opts)
751 }
752}
753
754impl<S, I> ParameterizedSpawn<(S,)> for Diff<Unselected>
755where
756 S: IntoIterator<Item = I>,
757 I: AsRef<OsStr>,
758{
759 type Output = Child;
760 type Error = std::io::Error;
761
762 fn spawn_with(&mut self, (files,): (S,)) -> Result<Self::Output, Self::Error> {
766 self.setup_command(&self.bin)
767 .args(files)
768 .stdout(Stdio::piped())
769 .stderr(Stdio::piped())
770 .spawn()
771 }
772}
773
774impl<M: ExclusiveOption, S, I> ParameterizedSpawn<(S,)> for Diff<WorkspaceMode<M>>
775where
776 S: IntoIterator<Item = I>,
777 I: AsRef<OsStr>,
778{
779 type Output = Child;
780 type Error = std::io::Error;
781
782 fn spawn_with(&mut self, (files,): (S,)) -> Result<Self::Output, Self::Error> {
786 self.setup_command(&self.bin)
787 .args(files)
788 .stdout(Stdio::piped())
789 .stderr(Stdio::piped())
790 .spawn()
791 }
792}
793
794#[cfg(not(feature = "lt2019_1"))]
795impl<I> ParameterizedSpawn<(I,)> for Diff<StreamSpecMode>
796where
797 I: AsRef<OsStr>,
798{
799 type Output = Child;
800 type Error = std::io::Error;
801
802 fn spawn_with(&mut self, (stream_spec,): (I,)) -> Result<Self::Output, Self::Error> {
814 self.setup_command(&self.bin)
815 .arg(stream_spec)
816 .stdout(Stdio::piped())
817 .stderr(Stdio::piped())
818 .spawn()
819 }
820}
821
822#[cfg(not(feature = "lt2019_1"))]
823impl ParameterizedSpawn<()> for Diff<StreamSpecMode> {
824 type Output = Child;
825 type Error = std::io::Error;
826
827 fn spawn_with(&mut self, _: ()) -> Result<Self::Output, Self::Error> {
832 self.setup_command(&self.bin)
833 .stdout(Stdio::piped())
834 .stderr(Stdio::piped())
835 .spawn()
836 }
837}
838
839#[cfg(test)]
840mod tests {
841 use super::*;
842 use crate::cmd::DiffOptionsBuilder;
843 use crate::cmd::args_of;
844
845 #[test]
846 fn bin_accessors_update_executable_path() {
847 let mut command = Diff::new("p4", GlobalOpts::new());
848 assert_eq!(command.get_bin(), Path::new("p4"));
849
850 command.set_bin("/usr/local/bin/p4");
851 assert_eq!(command.get_bin(), Path::new("/usr/local/bin/p4"));
852
853 let command = command.bin("p4.exe");
854 assert_eq!(command.get_bin(), Path::new("p4.exe"));
855 }
856
857 #[test]
860 fn without_options() {
861 let diff = Diff::new("p4", GlobalOpts::new());
862
863 assert_eq!(args_of(&diff.setup_command("p4")), ["diff"]);
864 }
865
866 #[test]
867 fn workspace_mode_via_force() {
868 let diff = Diff::new("p4", GlobalOpts::new()).force(true);
869
870 assert!(diff.get_force());
871 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-f"]);
872 }
873
874 #[test]
875 fn workspace_mode_via_differing_only() {
876 let diff = Diff::new("p4", GlobalOpts::new()).differing_only(true);
877
878 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-Od"]);
879 }
880
881 #[test]
882 fn workspace_mode_via_diff_nontext() {
883 let diff = Diff::new("p4", GlobalOpts::new()).diff_nontext(true);
884
885 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-t"]);
886 }
887
888 #[test]
889 fn workspace_mode_combines_options() {
890 let mut diff = Diff::new("p4", GlobalOpts::new()).diff_nontext(true);
891 diff.set_force(true).set_differing_only(true);
892
893 assert_eq!(
894 args_of(&diff.setup_command("p4")),
895 ["diff", "-f", "-t", "-Od"]
896 );
897 }
898
899 #[test]
900 fn workspace_mode_preserves_diff_options() {
901 let mut diff = Diff::new("p4", GlobalOpts::new())
902 .diff_options(DiffOptionsBuilder::unified(None))
903 .force(true);
904 diff.set_diff_options(DiffOptionsBuilder::summary());
905
906 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-ds", "-f"]);
907 }
908
909 #[test]
910 fn display_mode_injects_filter() {
911 let diff = Diff::new("p4", GlobalOpts::new())
912 .force(true)
913 .display_options(DisplayOptions::UnopenedChanged);
914
915 assert_eq!(diff.get_display_options(), &DisplayOptions::UnopenedChanged);
916 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-f", "-se"]);
917 }
918
919 #[test]
920 fn display_mode_flag_mapping() {
921 assert_eq!(DisplayOptions::OpenedChangedOrMissing.as_str(), "-sa");
922 assert_eq!(DisplayOptions::ResolvedThenModified.as_str(), "-sb");
923 assert_eq!(DisplayOptions::UnopenedMissing.as_str(), "-sd");
924 assert_eq!(DisplayOptions::UnopenedChanged.as_str(), "-se");
925 assert_eq!(DisplayOptions::ListWithStatus.as_str(), "-sl");
926 assert_eq!(DisplayOptions::OpenedIdentical.as_str(), "-sr");
927 }
928
929 #[test]
930 fn regular_mode_injects_limit() {
931 let diff = Diff::new("p4", GlobalOpts::new()).force(false).limit(10);
932
933 assert_eq!(diff.get_limit(), 10);
934 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-m", "10"]);
935 }
936
937 #[cfg(not(feature = "lt2019_1"))]
938 #[test]
939 fn stream_spec_mode_bare() {
940 let diff = Diff::new("p4", GlobalOpts::new()).stream_spec_mode();
941
942 assert_eq!(args_of(&diff.setup_command("p4")), ["diff", "-As"]);
943 }
944
945 #[cfg(not(feature = "lt2019_1"))]
946 #[test]
947 fn stream_spec_mode_with_spec() {
948 let diff = Diff::new("p4", GlobalOpts::new()).stream_spec_mode();
949
950 let mut command = diff.setup_command("p4");
953 command.arg("myStream@head");
954
955 assert_eq!(args_of(&command), ["diff", "-As", "myStream@head"]);
956 }
957
958 #[cfg(not(feature = "lt2019_1"))]
959 #[test]
960 fn stream_spec_mode_preserves_diff_options() {
961 let diff = Diff::new("p4", GlobalOpts::new())
962 .diff_options(DiffOptionsBuilder::unified(None))
963 .stream_spec_mode();
964
965 let mut command = diff.setup_command("p4");
968 command.arg("myStream");
969
970 assert_eq!(args_of(&command), ["diff", "-du", "-As", "myStream"]);
971 }
972}