diff --git a/Justfile b/Justfile index d6c6f54..135f054 100755 --- a/Justfile +++ b/Justfile @@ -31,6 +31,6 @@ test_dockerfile: docker run --rm \ --cap-add=SYS_PTRACE \ -v $(pwd)/tests/examples/bigger/script:/root/script \ - -v $(pwd)/tests/examples/bigger/script.protocols.yaml:/root/script.protocols.yaml \ + -v $(pwd)/tests/examples/bigger/script.test.yaml:/root/script.test.yaml \ scriptkeeper \ script diff --git a/README.md b/README.md index 9d900e8..848a4dc 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ Feel free to open (or vote on) ## Usage -`scriptkeeper` allows you to write tests -- so-called protocols -- for -scripts (or other executables) -- without the need to modify your executables. +`scriptkeeper` allows you to write tests for scripts (or other executables) -- +without the need to modify your executables. Here's an example script `./build-image.sh`: @@ -47,38 +47,41 @@ else fi ``` -And here's a matching protocols file `./build-image.sh.protocols.yaml`: +For `scriptkeeper` to be able to test this script, you need to add a yaml file +in the same directory as the script that has the additional file extension +`.test.yaml`. So here's the matching test file +`./build-image.sh.test.yaml`: ```yaml -protocols: +tests: # builds a docker image when git repo is clean - - protocol: + - steps: - command: /usr/bin/git status --porcelain stdout: "" - command: /usr/bin/git rev-parse HEAD stdout: "mock_commit_hash\n" - /usr/bin/docker build --tag image_name:mock_commit_hash . # aborts when git repo is not clean - - protocol: + - steps: - command: /usr/bin/git status --porcelain stdout: " M some-file" exitcode: 1 ``` Now running `scriptkeeper ./build-image.sh` will tell you whether your script -`./build-image.sh` conforms to your protocols in -`./build-image.sh.protocols.yaml`. +`./build-image.sh` conforms to your tests in +`./build-image.sh.test.yaml`. There are more example test cases in the [tests/examples](./tests/examples) folder. -### `.protocols.yaml` format +### `.test.yaml` format Here's all the fields that are available in the yaml declarations for the -protocols: (`?` marks optional fields.) +tests: (`?` marks optional fields.) ``` yaml -protocols: +tests: - arguments?: string # List of arguments given to the tested script, seperated by spaces. # Example: "-rf /", default: "" @@ -99,7 +102,7 @@ protocols: exitcode?: number # Exitcode that the tested script is expected to exit with. # Default: 0. - protocol: + steps: # List of commands that your script is expected to execute. - command|regex: string # One of either `command` or `regex` is required @@ -132,7 +135,7 @@ unmockedCommands: [string] For convenience you can specify commands as a string directly. So this ``` yaml -protocol: +steps: - command: git add . - command: git push ``` @@ -140,79 +143,79 @@ protocol: can be written as ``` yaml -protocol: +steps: - git add . - git push ``` -#### Multiple protocols +#### Multiple tests -Multiple protocols can be specified using a YAML array: +Multiple tests can be specified using a YAML array: ``` yaml # when given the 'push' argument, it pushes to the remote - arguments: push - protocol: + steps: - git add . - git push # when given the 'pull' argument, it just pulls - arguments: push - protocol: + steps: - git pull ``` -You can also put everything into a `protocols` field: +You can also put everything into a `tests` field: ``` yaml -protocols: +tests: # when given the 'push' argument, it pushes to the remote - arguments: push - protocol: + steps: - git add . - git push # when given the 'pull' argument, it just pulls - arguments: push - protocol: + steps: - git pull ``` -## Recording protocols +## Recording tests -There is **experimental** support for recording protocols. You can either record -protocols by passing in the `--record` command line flag, or you can put -so-called holes into your protocols: +There is **experimental** support for recording tests. You can either record +tests by passing in the `--record` command line flag, or you can put so-called +holes into your tests: ``` yaml -protocols: - - protocol: +tests: + - steps: - _ ``` This will actually execute the sub-commands that your script performs, without -mocking them out. And it will overwrite your protocols file with the recorded +mocking them out. And it will overwrite your tests file with the recorded version. -You can also start with a partial protocol and have `scriptkeeper` fill in the +You can also start with a partial test and have `scriptkeeper` fill in the specified holes: ``` yaml -protocols: +tests: - arguments: foo - protocol: + steps: - git add . - _ ``` -This allows for an iterative process to create a protocol: +This allows for an iterative process to create a test: -1. Start with an empty protocol with a hole. +1. Start with an empty test with a hole. 2. Run `scriptkeeper`. -3. Identify the step in the recorded protocol where it deviates from the +3. Identify the step in the recorded test where it deviates from the intended test. (If it doesn't, you're done.) -4. Refine the protocol by modifying the inputs to the tested script, i.e. the +4. Refine the test by modifying the inputs to the tested script, i.e. the arguments, the environment, etc. This can be guided by both the recorded script and the script's output to `stdout` and `stderr`. -5. Remove all protocol steps after the step identified in 3. +5. Remove all test steps after the step identified in 3. 6. Add a hole at the end. 7. Re-iterate from step 2. diff --git a/build-docker-image.sh.protocols.yaml b/build-docker-image.sh.test.yaml similarity index 81% rename from build-docker-image.sh.protocols.yaml rename to build-docker-image.sh.test.yaml index 214beb2..2a4aa36 100644 --- a/build-docker-image.sh.protocols.yaml +++ b/build-docker-image.sh.test.yaml @@ -1,2 +1,2 @@ -protocol: +steps: - /usr/bin/docker build -t scriptkeeper . diff --git a/scriptkeeper-in-docker.sh b/scriptkeeper-in-docker.sh index cb64525..1a83769 100755 --- a/scriptkeeper-in-docker.sh +++ b/scriptkeeper-in-docker.sh @@ -9,5 +9,5 @@ fi docker run --rm -it --cap-add=SYS_PTRACE \ --mount type=bind,source=$script,target=/root/$(basename $script) \ - --mount type=bind,source=$script.protocols.yaml,target=/root/$(basename $script).protocols.yaml \ + --mount type=bind,source=$script.test.yaml,target=/root/$(basename $script).test.yaml \ scriptkeeper $(basename $script) diff --git a/scriptkeeper-in-docker.sh.protocols.yaml b/scriptkeeper-in-docker.sh.test.yaml similarity index 67% rename from scriptkeeper-in-docker.sh.protocols.yaml rename to scriptkeeper-in-docker.sh.test.yaml index 84c9dce..38c8ca3 100644 --- a/scriptkeeper-in-docker.sh.protocols.yaml +++ b/scriptkeeper-in-docker.sh.test.yaml @@ -1,20 +1,20 @@ unmockedCommands: - /usr/bin/basename -protocols: +tests: # works for relative paths - arguments: ./script cwd: /basedir - protocol: + steps: - /usr/bin/docker run --rm -it --cap-add=SYS_PTRACE --mount type=bind,source=/basedir/./script,target=/root/script - --mount type=bind,source=/basedir/./script.protocols.yaml,target=/root/script.protocols.yaml + --mount type=bind,source=/basedir/./script.test.yaml,target=/root/script.test.yaml scriptkeeper script # works for absolute paths - arguments: /test/script - protocol: + steps: - /usr/bin/docker run --rm -it --cap-add=SYS_PTRACE --mount type=bind,source=/test/script,target=/root/script - --mount type=bind,source=/test/script.protocols.yaml,target=/root/script.protocols.yaml + --mount type=bind,source=/test/script.test.yaml,target=/root/script.test.yaml scriptkeeper script diff --git a/src/cli.rs b/src/cli.rs index db101b2..ee9a192 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -26,7 +26,7 @@ fn parse_args_safe(args: impl Iterator) -> Result { let matches = App::new("scriptkeeper") .arg(Arg::with_name("record").short("r").long("record").help( "[EXPERIMENTAL] Runs the script (without mocking out anything), \ - records a protocol and prints it to stdout", + records a test case and prints it to stdout", )) .arg( Arg::with_name("program") diff --git a/src/lib.rs b/src/lib.rs index 9d3f103..e7adb5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,17 +14,17 @@ extern crate memoffset; pub mod cli; pub mod context; -mod protocol; -mod protocol_checker; mod recorder; +mod test_checker; +mod test_spec; mod tracer; pub mod utils; use crate::context::Context; -use crate::protocol::yaml::write_yaml; -use crate::protocol::Protocols; -use crate::protocol_checker::executable_mock; -use crate::recorder::{hole_recorder::run_against_protocols, Recorder}; +use crate::recorder::{hole_recorder::run_against_tests, Recorder}; +use crate::test_checker::executable_mock; +use crate::test_spec::yaml::write_yaml; +use crate::test_spec::Tests; use crate::tracer::stdio_redirecting::CaptureStderr; use crate::tracer::Tracer; use std::collections::HashMap; @@ -86,7 +86,7 @@ pub fn run_main(context: &Context, args: &cli::Args) -> R { record, } => { if *record { - print_recorded_protocol(context, script_path)? + print_recorded_test(context, script_path)? } else { run_scriptkeeper(context, &script_path)? } @@ -129,12 +129,12 @@ pub fn run_scriptkeeper(context: &Context, script: &Path) -> R { script.to_string_lossy() ))? } - let (protocols_file_path, expected_protocols) = Protocols::load(script)?; - run_against_protocols(&context, script, &protocols_file_path, expected_protocols) + let (test_file_path, tests) = Tests::load(script)?; + run_against_tests(&context, script, &test_file_path, tests) } -fn print_recorded_protocol(context: &Context, program: &Path) -> R { - let protocol = Tracer::run_against_mock( +fn print_recorded_test(context: &Context, program: &Path) -> R { + let test = Tracer::run_against_mock( context, &None, program, @@ -143,9 +143,6 @@ fn print_recorded_protocol(context: &Context, program: &Path) -> R { CaptureStderr::NoCapture, Recorder::empty(), )?; - write_yaml( - &mut *context.stdout(), - &Protocols::new(vec![protocol]).serialize()?, - )?; + write_yaml(&mut *context.stdout(), &Tests::new(vec![test]).serialize()?)?; Ok(ExitCode(0)) } diff --git a/src/recorder/hole_recorder.rs b/src/recorder/hole_recorder.rs index 3321be7..5a21cbe 100644 --- a/src/recorder/hole_recorder.rs +++ b/src/recorder/hole_recorder.rs @@ -1,9 +1,9 @@ -use super::protocol_result::ProtocolResult; use crate::context::Context; -use crate::protocol::{Protocol, Protocols}; -use crate::protocol_checker::checker_result::CheckerResult; -use crate::protocol_checker::ProtocolChecker; +use crate::recorder::result::RecorderResult; use crate::recorder::Recorder; +use crate::test_checker::checker_result::CheckerResult; +use crate::test_checker::TestChecker; +use crate::test_spec::{Test, Tests}; use crate::tracer::stdio_redirecting::Redirector; use crate::tracer::SyscallMock; use crate::{ExitCode, R}; @@ -14,8 +14,8 @@ use std::path::{Path, PathBuf}; pub enum HoleRecorder { Checker { - checker: ProtocolChecker, - original_protocol: Protocol, + checker: TestChecker, + original_test: Test, }, Recorder { recorder: Recorder, @@ -23,20 +23,16 @@ pub enum HoleRecorder { } impl HoleRecorder { - pub fn new( - context: &Context, - unmocked_commands: &[PathBuf], - protocol: Protocol, - ) -> HoleRecorder { + pub fn new(context: &Context, unmocked_commands: &[PathBuf], test: Test) -> HoleRecorder { HoleRecorder::Checker { - checker: ProtocolChecker::new(context, protocol.clone(), unmocked_commands), - original_protocol: protocol, + checker: TestChecker::new(context, test.clone(), unmocked_commands), + original_test: test, } } } impl SyscallMock for HoleRecorder { - type Result = ProtocolResult; + type Result = RecorderResult; fn handle_execve_enter( &mut self, @@ -48,9 +44,9 @@ impl SyscallMock for HoleRecorder { match self { HoleRecorder::Checker { checker, - original_protocol, + original_test, } => { - if !checker.protocol.steps.is_empty() { + if !checker.test.steps.is_empty() { checker.handle_execve_enter(pid, registers, executable, arguments) } else { match checker.result { @@ -60,7 +56,7 @@ impl SyscallMock for HoleRecorder { CheckerResult::Pass => { *self = HoleRecorder::Recorder { recorder: Recorder::new( - original_protocol.clone(), + original_test.clone(), &checker.unmocked_commands, ), }; @@ -82,44 +78,39 @@ impl SyscallMock for HoleRecorder { } } - fn handle_end(self, exitcode: i32, redirector: &Redirector) -> R { + fn handle_end(self, exitcode: i32, redirector: &Redirector) -> R { Ok(match self { HoleRecorder::Checker { checker, - mut original_protocol, + mut original_test, } => match checker.result { CheckerResult::Pass => { - original_protocol.ends_with_hole = false; - let recorder = Recorder::new(original_protocol, &checker.unmocked_commands); - ProtocolResult::Recorded(recorder.handle_end(exitcode, redirector)?) + original_test.ends_with_hole = false; + let recorder = Recorder::new(original_test, &checker.unmocked_commands); + RecorderResult::Recorded(recorder.handle_end(exitcode, redirector)?) } failure @ CheckerResult::Failure(_) => { - ProtocolResult::Checked(original_protocol, failure) + RecorderResult::Checked(original_test, failure) } }, HoleRecorder::Recorder { recorder } => { - ProtocolResult::Recorded(recorder.handle_end(exitcode, redirector)?) + RecorderResult::Recorded(recorder.handle_end(exitcode, redirector)?) } }) } } -pub fn run_against_protocols( +pub fn run_against_tests( context: &Context, program: &Path, - protocols_file: &Path, - Protocols { - protocols, + test_file: &Path, + Tests { + tests, unmocked_commands, interpreter, - }: Protocols, + }: Tests, ) -> R { - let results = ProtocolResult::collect_results( - context, - &interpreter, - program, - protocols, - &unmocked_commands, - )?; - ProtocolResult::handle_results(context, protocols_file, unmocked_commands, &results) + let results = + RecorderResult::collect_results(context, &interpreter, program, tests, &unmocked_commands)?; + RecorderResult::handle_results(context, test_file, unmocked_commands, &results) } diff --git a/src/recorder/mod.rs b/src/recorder/mod.rs index 6f8741b..602c397 100644 --- a/src/recorder/mod.rs +++ b/src/recorder/mod.rs @@ -1,9 +1,9 @@ pub mod hole_recorder; -mod protocol_result; +mod result; -use crate::protocol::command::Command; -use crate::protocol::command_matcher::CommandMatcher; -use crate::protocol::{compare_executables, Protocol, Step}; +use crate::test_spec::command::Command; +use crate::test_spec::command_matcher::CommandMatcher; +use crate::test_spec::{compare_executables, Step, Test}; use crate::tracer::stdio_redirecting::Redirector; use crate::tracer::SyscallMock; use crate::R; @@ -13,7 +13,7 @@ use std::ffi::OsString; use std::path::PathBuf; pub struct Recorder { - protocol: Protocol, + test: Test, command: Option, unmocked_commands: Vec, } @@ -21,15 +21,15 @@ pub struct Recorder { impl Recorder { pub fn empty() -> Recorder { Recorder { - protocol: Protocol::new(vec![]), + test: Test::new(vec![]), command: None, unmocked_commands: vec![], } } - pub fn new(protocol: Protocol, unmocked_commands: &[PathBuf]) -> Recorder { + pub fn new(test: Test, unmocked_commands: &[PathBuf]) -> Recorder { Recorder { - protocol, + test, command: None, unmocked_commands: unmocked_commands.to_vec(), } @@ -37,7 +37,7 @@ impl Recorder { } impl SyscallMock for Recorder { - type Result = Protocol; + type Result = Test; fn handle_execve_enter( &mut self, @@ -62,7 +62,7 @@ impl SyscallMock for Recorder { fn handle_exited(&mut self, _pid: Pid, exitcode: i32) -> R<()> { if let Some(command) = self.command.clone() { self.command = None; - self.protocol.steps.push_back(Step { + self.test.steps.push_back(Step { command_matcher: CommandMatcher::ExactMatch(command), stdout: vec![], exitcode, @@ -71,10 +71,10 @@ impl SyscallMock for Recorder { Ok(()) } - fn handle_end(mut self, exitcode: i32, _redirector: &Redirector) -> R { + fn handle_end(mut self, exitcode: i32, _redirector: &Redirector) -> R { if exitcode != 0 { - self.protocol.exitcode = Some(exitcode); + self.test.exitcode = Some(exitcode); } - Ok(self.protocol) + Ok(self.test) } } diff --git a/src/recorder/protocol_result.rs b/src/recorder/result.rs similarity index 61% rename from src/recorder/protocol_result.rs rename to src/recorder/result.rs index 4dba55a..2bdb5f6 100644 --- a/src/recorder/protocol_result.rs +++ b/src/recorder/result.rs @@ -1,10 +1,10 @@ use super::hole_recorder::HoleRecorder; use crate::context::Context; -use crate::protocol::{yaml::write_yaml, Protocol, Protocols}; -use crate::protocol_checker::{ +use crate::test_checker::{ checker_result::{CheckerResult, CheckerResults}, - ProtocolChecker, + TestChecker, }; +use crate::test_spec::{yaml::write_yaml, Test, Tests}; use crate::tracer::stdio_redirecting::CaptureStderr; use crate::tracer::Tracer; use crate::{ExitCode, R}; @@ -12,30 +12,30 @@ use std::fs::OpenOptions; use std::path::{Path, PathBuf}; #[derive(Debug, PartialEq)] -pub enum ProtocolResult { - Checked(Protocol, CheckerResult), - Recorded(Protocol), +pub enum RecorderResult { + Checked(Test, CheckerResult), + Recorded(Test), } -impl ProtocolResult { +impl RecorderResult { fn is_recorded(&self) -> bool { match self { - ProtocolResult::Recorded(_) => true, - ProtocolResult::Checked(_, _) => false, + RecorderResult::Recorded(_) => true, + RecorderResult::Checked(_, _) => false, } } - fn get_protocol(&self) -> Protocol { + fn get_test(&self) -> Test { match self { - ProtocolResult::Checked(protocol, _) => protocol.clone(), - ProtocolResult::Recorded(protocol) => protocol.clone(), + RecorderResult::Checked(test, _) => test.clone(), + RecorderResult::Recorded(test) => test.clone(), } } fn get_test_result(&self) -> Option { match self { - ProtocolResult::Checked(_, test_result) => Some(test_result.clone()), - ProtocolResult::Recorded(_) => None, + RecorderResult::Checked(_, test_result) => Some(test_result.clone()), + RecorderResult::Recorded(_) => None, } } @@ -43,17 +43,17 @@ impl ProtocolResult { context: &Context, interpreter: &Option, program: &Path, - protocols: Vec, + tests: Vec, unmocked_commands: &[PathBuf], - ) -> R> { + ) -> R> { let mut results = vec![]; - for protocol in protocols.into_iter() { - results.push(run_against_protocol( + for test in tests.into_iter() { + results.push(run_against_test( context, &interpreter, program, unmocked_commands, - protocol, + test, )?); } Ok(results) @@ -61,9 +61,9 @@ impl ProtocolResult { pub fn handle_results( context: &Context, - protocols_file: &Path, + test_file: &Path, unmocked_commands: Vec, - results: &[ProtocolResult], + results: &[RecorderResult], ) -> R { let checker_results = CheckerResults( results @@ -71,9 +71,9 @@ impl ProtocolResult { .filter_map(|result| result.get_test_result()) .collect(), ); - ProtocolResult::handle_recorded( + RecorderResult::handle_recorded( context, - protocols_file, + test_file, unmocked_commands, &results, &checker_results, @@ -84,20 +84,20 @@ impl ProtocolResult { fn handle_recorded( context: &Context, - protocols_file: &Path, + test_file: &Path, unmocked_commands: Vec, - results: &[ProtocolResult], + results: &[RecorderResult], checker_results: &CheckerResults, ) -> R<()> { if checker_results.is_pass() && results.iter().any(|result| result.is_recorded()) { let mut file = OpenOptions::new() .write(true) .truncate(true) - .open(protocols_file)?; + .open(test_file)?; write_yaml( &mut file, - &Protocols { - protocols: results.iter().map(|result| result.get_protocol()).collect(), + &Tests { + tests: results.iter().map(|result| result.get_test()).collect(), unmocked_commands, interpreter: None, } @@ -105,30 +105,30 @@ impl ProtocolResult { )?; writeln!( context.stdout(), - "Protocol holes filled in {}.", - protocols_file.to_string_lossy() + "Test holes filled in {}.", + test_file.to_string_lossy() )?; } Ok(()) } } -fn run_against_protocol( +fn run_against_test( context: &Context, interpreter: &Option, program: &Path, unmocked_commands: &[PathBuf], - protocol: Protocol, -) -> R { + test: Test, +) -> R { macro_rules! run_against_mock { ($syscall_mock:expr) => { Tracer::run_against_mock( context, interpreter, program, - protocol.arguments.clone(), - protocol.env.clone(), - if protocol.stderr.is_some() { + test.arguments.clone(), + test.env.clone(), + if test.stderr.is_some() { CaptureStderr::Capture } else { CaptureStderr::NoCapture @@ -137,12 +137,12 @@ fn run_against_protocol( ) }; } - if protocol.ends_with_hole { - run_against_mock!(HoleRecorder::new(context, unmocked_commands, protocol)) + if test.ends_with_hole { + run_against_mock!(HoleRecorder::new(context, unmocked_commands, test)) } else { - Ok(ProtocolResult::Checked( - protocol.clone(), - run_against_mock!(ProtocolChecker::new(context, protocol, unmocked_commands))?, + Ok(RecorderResult::Checked( + test.clone(), + run_against_mock!(TestChecker::new(context, test, unmocked_commands))?, )) } } diff --git a/src/protocol_checker/checker_result.rs b/src/test_checker/checker_result.rs similarity index 91% rename from src/protocol_checker/checker_result.rs rename to src/test_checker/checker_result.rs index 60d96d4..87702ae 100644 --- a/src/protocol_checker/checker_result.rs +++ b/src/test_checker/checker_result.rs @@ -18,13 +18,13 @@ impl CheckerResult { match self { CheckerResult::Failure(error) => { let header = number.map_or("error".to_string(), |number| { - format!("error in protocol {}", number) + format!("error in test {}", number) }); format!("{}:\n{}", header, error) } CheckerResult::Pass => match number { None => panic!("CheckerResult.format: shouldn't happen"), - Some(number) => format!("protocol {}:\n Tests passed.\n", number), + Some(number) => format!("test {}:\n Tests passed.\n", number), }, } } diff --git a/src/protocol_checker/executable_mock.rs b/src/test_checker/executable_mock.rs similarity index 100% rename from src/protocol_checker/executable_mock.rs rename to src/test_checker/executable_mock.rs diff --git a/src/protocol_checker/mod.rs b/src/test_checker/mod.rs similarity index 77% rename from src/protocol_checker/mod.rs rename to src/test_checker/mod.rs index ec4ba33..08ed203 100644 --- a/src/protocol_checker/mod.rs +++ b/src/test_checker/mod.rs @@ -2,8 +2,8 @@ pub mod checker_result; pub mod executable_mock; use crate::context::Context; -use crate::protocol; -use crate::protocol::Protocol; +use crate::test_spec; +use crate::test_spec::Test; use crate::tracer::stdio_redirecting::Redirector; use crate::tracer::{tracee_memory, SyscallMock}; use crate::utils::short_temp_files::ShortTempFile; @@ -17,23 +17,19 @@ use std::os::unix::ffi::OsStrExt; use std::path::PathBuf; #[derive(Debug)] -pub struct ProtocolChecker { +pub struct TestChecker { context: Context, - pub protocol: Protocol, + pub test: Test, pub unmocked_commands: Vec, pub result: CheckerResult, temporary_executables: Vec, } -impl ProtocolChecker { - pub fn new( - context: &Context, - protocol: Protocol, - unmocked_commands: &[PathBuf], - ) -> ProtocolChecker { - ProtocolChecker { +impl TestChecker { + pub fn new(context: &Context, test: Test, unmocked_commands: &[PathBuf]) -> TestChecker { + TestChecker { context: context.clone(), - protocol, + test, unmocked_commands: unmocked_commands.to_vec(), result: CheckerResult::Pass, temporary_executables: vec![], @@ -47,23 +43,23 @@ impl ProtocolChecker { } } - fn handle_step(&mut self, received: protocol::Command) -> R { - let mock_config = match self.protocol.steps.pop_front() { - Some(next_protocol_step) => { - if !next_protocol_step.command_matcher.matches(&received) { + fn handle_step(&mut self, received: test_spec::Command) -> R { + let mock_config = match self.test.steps.pop_front() { + Some(next_test_step) => { + if !next_test_step.command_matcher.matches(&received) { self.register_step_error( - &next_protocol_step.command_matcher.format(), + &next_test_step.command_matcher.format(), &received.format(), ); } executable_mock::Config { - stdout: next_protocol_step.stdout, - exitcode: next_protocol_step.exitcode, + stdout: next_test_step.stdout, + exitcode: next_test_step.exitcode, } } None => { - self.register_step_error("", &received.format()); - ProtocolChecker::allow_failing_scripts_to_continue() + self.register_step_error("