use std::collections::HashMap;
use std::time::Duration;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
use super::SourceLocation;
use super::span::SpanId;
pub type EventSeq = u64;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
#[cfg_attr(
feature = "ts-export",
ts(export, export_to = "../../../viewer/src/types/")
)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum TimeoutValue {
Tolerance {
duration: String,
multiplier: String,
total_duration: String,
source: Option<SourceLocation>,
},
Assertion {
duration: String,
source: Option<SourceLocation>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[cfg_attr(
feature = "ts-export",
ts(export, export_to = "../../../viewer/src/types/")
)]
pub struct MultiMatchPattern {
pub pattern: String,
pub is_regex: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[cfg_attr(
feature = "ts-export",
ts(export, export_to = "../../../viewer/src/types/")
)]
pub struct Event {
pub seq: EventSeq,
#[serde(with = "super::ts_duration_ms")]
#[ts(as = "f64")]
pub ts: Duration,
pub span: SpanId,
pub shell: Option<String>,
pub shell_marker: Option<String>,
pub source: Option<SourceLocation>,
#[serde(flatten)]
pub kind: EventKind,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[cfg_attr(
feature = "ts-export",
ts(export, export_to = "../../../viewer/src/types/")
)]
#[serde(tag = "kind", rename_all = "kebab-case")]
pub enum EventKind {
ShellSpawn {
name: String,
command: String,
},
ShellReady {
name: String,
},
ShellSwitch {
name: String,
},
ShellTerminate {
name: String,
},
EffectExposeShell {
name: String,
target: String,
qualifier: Option<String>,
},
EffectExposeVar {
name: String,
target: String,
qualifier: Option<String>,
value: String,
},
Send {
data: String,
},
Recv {
data: String,
},
MatchStart {
pattern: String,
is_regex: bool,
effective: TimeoutValue,
},
MatchDone {
matched: String,
#[serde(with = "super::ts_duration_ms")]
#[ts(as = "f64")]
elapsed: Duration,
captures: Option<HashMap<String, String>>,
buffer_seq: EventSeq,
},
Timeout {
pattern: String,
buffer_seq: Option<EventSeq>,
effective: TimeoutValue,
},
FailPatternSet {
pattern: String,
is_regex: bool,
},
FailPatternCleared,
FailPatternTriggered {
pattern: String,
is_regex: bool,
matched_line: String,
buffer_seq: Option<EventSeq>,
},
SleepStart {
#[serde(with = "super::ts_duration_ms")]
#[ts(as = "f64")]
duration: Duration,
},
SleepDone,
TimeoutSet {
timeout: TimeoutValue,
previous: TimeoutValue,
},
VarLet {
name: String,
value: String,
},
VarAssign {
name: String,
value: String,
previous: String,
},
StringEval {
result: String,
},
Interpolation {
template: String,
result: String,
bindings: Vec<(String, String)>,
},
PureMatch {
match_kind: super::span::MatchKind,
value: String,
pattern: String,
result: String,
captures: HashMap<String, String>,
},
VarRead {
name: String,
value: String,
},
BoolCheck {
evaluation: super::span::MarkerEvalDetail,
},
Annotate {
text: String,
},
Log {
message: String,
},
Warning {
message: String,
},
Error {
message: String,
},
Cancelled {
reason: CancelReasonRecord,
},
MultiMatchStart {
effective: TimeoutValue,
patterns: Vec<MultiMatchPattern>,
},
MultiMatchPatternDone {
index: usize,
#[serde(with = "super::ts_duration_ms")]
#[ts(as = "f64")]
elapsed: Duration,
buffer_seq: EventSeq,
},
MultiMatchDone {
advance_to: EventSeq,
},
MultiMatchTimeout {
unmatched: Vec<usize>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
#[cfg_attr(
feature = "ts-export",
ts(export, export_to = "../../../viewer/src/types/")
)]
#[serde(tag = "type", rename_all = "kebab-case")]
pub enum CancelReasonRecord {
TestTimeout { duration_ms: u64 },
SuiteTimeout { duration_ms: u64 },
FailFast { trigger_test: String },
Sigint,
}
impl CancelReasonRecord {
pub fn tag(&self) -> &'static str {
match self {
Self::TestTimeout { .. } => "test-timeout",
Self::SuiteTimeout { .. } => "suite-timeout",
Self::FailFast { .. } => "fail-fast",
Self::Sigint => "sigint",
}
}
}
impl From<&crate::cancel::CancelReason> for CancelReasonRecord {
fn from(r: &crate::cancel::CancelReason) -> Self {
use crate::cancel::CancelReason;
match r {
CancelReason::TestTimeout { duration } => Self::TestTimeout {
duration_ms: duration.as_millis() as u64,
},
CancelReason::SuiteTimeout { duration } => Self::SuiteTimeout {
duration_ms: duration.as_millis() as u64,
},
CancelReason::FailFast { trigger_test } => Self::FailFast {
trigger_test: trigger_test.clone(),
},
CancelReason::Sigint => Self::Sigint,
}
}
}
#[cfg(test)]
mod pure_match_tests {
use super::*;
use std::collections::HashMap;
#[test]
fn pure_match_event_kind_serialises() {
let mut caps = HashMap::new();
caps.insert("0".to_string(), "abc".to_string());
let k = EventKind::PureMatch {
match_kind: super::super::span::MatchKind::Regex,
value: "abc".into(),
pattern: "^a.c$".into(),
result: "abc".into(),
captures: caps,
};
let v = serde_json::to_value(&k).unwrap();
assert_eq!(v["kind"], serde_json::json!("pure-match"));
assert_eq!(v["match_kind"], serde_json::json!("regex"));
assert_eq!(v["result"], serde_json::json!("abc"));
}
#[test]
fn multimatch_start_event_kind_serialises() {
let k = EventKind::MultiMatchStart {
effective: TimeoutValue::Assertion {
duration: "5s".into(),
source: None,
},
patterns: vec![
MultiMatchPattern {
pattern: "^ok$".into(),
is_regex: true,
},
MultiMatchPattern {
pattern: "batch complete".into(),
is_regex: false,
},
],
};
let v = serde_json::to_value(&k).unwrap();
assert_eq!(v["kind"], serde_json::json!("multi-match-start"));
assert_eq!(v["patterns"][0]["is_regex"], serde_json::json!(true));
assert_eq!(
v["patterns"][1]["pattern"],
serde_json::json!("batch complete")
);
}
#[test]
fn multimatch_pattern_done_event_kind_serialises() {
let k = EventKind::MultiMatchPatternDone {
index: 1,
elapsed: Duration::from_millis(42),
buffer_seq: 17,
};
let v = serde_json::to_value(&k).unwrap();
assert_eq!(v["kind"], serde_json::json!("multi-match-pattern-done"));
assert_eq!(v["index"], serde_json::json!(1));
assert_eq!(v["buffer_seq"], serde_json::json!(17));
}
#[test]
fn multimatch_done_event_kind_serialises() {
let k = EventKind::MultiMatchDone { advance_to: 23 };
let v = serde_json::to_value(&k).unwrap();
assert_eq!(v["kind"], serde_json::json!("multi-match-done"));
assert_eq!(v["advance_to"], serde_json::json!(23));
}
#[test]
fn multimatch_timeout_event_kind_serialises() {
let k = EventKind::MultiMatchTimeout {
unmatched: vec![0, 2],
};
let v = serde_json::to_value(&k).unwrap();
assert_eq!(v["kind"], serde_json::json!("multi-match-timeout"));
assert_eq!(v["unmatched"], serde_json::json!([0, 2]));
}
}