@@ -15,14 +15,20 @@ use crate::{
1515/// This is a custom command wrapper that simplifies working with commands and makes it easier to
1616/// ensure that we check the exit status of executed processes.
1717///
18- /// # A [`Command`] must be executed
18+ /// # A [`Command`] must be executed exactly once
1919///
2020/// A [`Command`] is armed by a [`DropBomb`] on construction to enforce that it will be executed. If
2121/// a [`Command`] is constructed but never executed, the drop bomb will explode and cause the test
2222/// to panic. Execution methods [`run`] and [`run_fail`] will defuse the drop bomb. A test
2323/// containing constructed but never executed commands is dangerous because it can give a false
2424/// sense of confidence.
2525///
26+ /// Each [`Command`] invocation can also only be executed once, because we want to enforce
27+ /// `std{in,out,err}` config via [`std::process::Stdio`] but [`std::process::Stdio`] is not
28+ /// cloneable.
29+ ///
30+ /// In this sense, [`Command`] exhibits linear type semantics but enforced at run-time.
31+ ///
2632/// [`run`]: Self::run
2733/// [`run_fail`]: Self::run_fail
2834/// [`run_unchecked`]: Self::run_unchecked
@@ -37,7 +43,9 @@ pub struct Command {
3743 stdout : Option < Stdio > ,
3844 stderr : Option < Stdio > ,
3945
46+ // Emulate linear type semantics.
4047 drop_bomb : DropBomb ,
48+ already_executed : bool ,
4149}
4250
4351impl Command {
@@ -51,6 +59,7 @@ impl Command {
5159 stdin : None ,
5260 stdout : None ,
5361 stderr : None ,
62+ already_executed : false ,
5463 }
5564 }
5665
@@ -177,6 +186,12 @@ impl Command {
177186
178187 #[ track_caller]
179188 fn command_output ( & mut self ) -> CompletedProcess {
189+ if self . already_executed {
190+ panic ! ( "command was already executed" ) ;
191+ } else {
192+ self . already_executed = true ;
193+ }
194+
180195 self . drop_bomb . defuse ( ) ;
181196 // let's make sure we piped all the input and outputs
182197 self . cmd . stdin ( self . stdin . take ( ) . unwrap_or ( Stdio :: piped ( ) ) ) ;
0 commit comments