use crate::breakpoint::*;
use crate::config::Config;
use crate::errors::RunError;
use crate::ptrace_control::*;
use crate::traces::*;
use log::error;
use std::time::Instant;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use linux::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TestState {
Start { start_time: Instant },
Initialise,
Waiting { start_time: Instant },
Stopped,
End(i32),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TracerAction<T> {
TryContinue(T),
Continue(T),
Step(T),
Detach(T),
Nothing,
}
impl<T> TracerAction<T> {
pub fn is_detach(&self) -> bool {
if let TracerAction::Detach(_) = self {
true
} else {
false
}
}
pub fn is_continue(&self) -> bool {
if let TracerAction::Continue(_) = self {
true
} else {
false
}
}
pub fn is_step(&self) -> bool {
if let TracerAction::Step(_) = self {
true
} else {
false
}
}
pub fn get_data(&self) -> Option<&T> {
match self {
TracerAction::Continue(d) => Some(d),
TracerAction::Step(d) => Some(d),
TracerAction::Detach(d) => Some(d),
_ => None,
}
}
}
pub trait StateData {
fn start(&mut self) -> Result<Option<TestState>, RunError>;
fn init(&mut self) -> Result<TestState, RunError>;
fn wait(&mut self) -> Result<Option<TestState>, RunError>;
fn stop(&mut self) -> Result<TestState, RunError>;
}
impl TestState {
pub fn is_finished(self) -> bool {
match self {
TestState::End(_) => true,
_ => false,
}
}
fn start_state() -> TestState {
TestState::Start {
start_time: Instant::now(),
}
}
fn wait_state() -> TestState {
TestState::Waiting {
start_time: Instant::now(),
}
}
pub fn step<T: StateData>(self, data: &mut T, config: &Config) -> Result<TestState, RunError> {
match self {
TestState::Start { start_time } => {
if let Some(s) = data.start()? {
Ok(s)
} else if start_time.elapsed() >= config.test_timeout {
Err(RunError::TestRuntime(
"Error: Timed out when starting test".to_string(),
))
} else {
Ok(TestState::Start { start_time })
}
}
TestState::Initialise => data.init(),
TestState::Waiting { start_time } => {
if let Some(s) = data.wait()? {
Ok(s)
} else if start_time.elapsed() >= config.test_timeout {
Err(RunError::TestRuntime(
"Error: Timed out waiting for test response".to_string(),
))
} else {
Ok(TestState::Waiting { start_time })
}
}
TestState::Stopped => data.stop(),
_ => {
if config.verbose {
error!("Tarpaulin error: unhandled test state");
}
Ok(TestState::End(-1))
}
}
}
}