1use crate::{
2 AuditEntry, ClearReason, OutputFrameKind, OutputKey, RebaselineReason, ResourceCommand,
3 ResourceKey, ScopeId, TransactionId, TransactionPhase, TransactionResult,
4};
5use crate::{NodeId, Revision};
6
7#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct TransactionTrace {
10 pub transaction_id: TransactionId,
12 pub revision: Revision,
14 pub changed_inputs: Vec<NodeId>,
16 pub changed_derived_nodes: Vec<NodeId>,
18 pub changed_collection_nodes: Vec<NodeId>,
20 pub resource_commands: Vec<ResourceCommandTrace>,
22 pub output_frames: Vec<OutputFrameTrace>,
24 pub audit_log: Vec<AuditEntry>,
26 pub phase_trace: Vec<TransactionPhase>,
28}
29
30impl TransactionTrace {
31 pub fn from_result<C, O>(result: &TransactionResult<C, O>) -> Self {
33 Self {
34 transaction_id: result.transaction_id,
35 revision: result.revision,
36 changed_inputs: result.changed_inputs.clone(),
37 changed_derived_nodes: result.changed_derived_nodes.clone(),
38 changed_collection_nodes: result.changed_collection_nodes.clone(),
39 resource_commands: result
40 .resource_plan
41 .commands()
42 .iter()
43 .map(ResourceCommandTrace::from_command)
44 .collect(),
45 output_frames: result
46 .output_frames
47 .iter()
48 .map(|frame| OutputFrameTrace {
49 output_key: frame.output_key,
50 scope: frame.scope,
51 transaction_id: frame.transaction_id,
52 revision: frame.revision,
53 kind: OutputFrameKindTrace::from_kind(&frame.kind),
54 })
55 .collect(),
56 audit_log: result.audit_log.clone(),
57 phase_trace: result.phase_trace.clone(),
58 }
59 }
60}
61
62#[derive(Clone, Debug, Eq, PartialEq)]
64pub struct ResourceCommandTrace {
65 pub key: ResourceKey,
67 pub scope: ScopeId,
69 pub kind: ResourceCommandKind,
71}
72
73impl ResourceCommandTrace {
74 fn from_command<C>(command: &ResourceCommand<C>) -> Self {
75 Self {
76 key: command.key().clone(),
77 scope: command.scope(),
78 kind: ResourceCommandKind::from_command(command),
79 }
80 }
81}
82
83#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85pub enum ResourceCommandKind {
86 Open,
88 Close,
90 Replace,
92 Refresh,
94}
95
96impl ResourceCommandKind {
97 pub(crate) fn from_command<C>(command: &ResourceCommand<C>) -> Self {
98 match command {
99 ResourceCommand::Open { .. } => Self::Open,
100 ResourceCommand::Close { .. } => Self::Close,
101 ResourceCommand::Replace { .. } => Self::Replace,
102 ResourceCommand::Refresh { .. } => Self::Refresh,
103 }
104 }
105}
106
107#[derive(Clone, Debug, Eq, PartialEq)]
109pub struct OutputFrameTrace {
110 pub output_key: OutputKey,
112 pub scope: ScopeId,
114 pub transaction_id: TransactionId,
116 pub revision: Revision,
118 pub kind: OutputFrameKindTrace,
120}
121
122#[derive(Copy, Clone, Debug, Eq, PartialEq)]
124pub enum OutputFrameKindTrace {
125 Baseline,
127 Delta,
129 Clear(ClearReason),
131 Rebaseline(RebaselineReason),
133}
134
135impl OutputFrameKindTrace {
136 pub(crate) fn from_kind<O>(kind: &OutputFrameKind<O>) -> Self {
137 match kind {
138 OutputFrameKind::Baseline(_) => Self::Baseline,
139 OutputFrameKind::Delta(_) => Self::Delta,
140 OutputFrameKind::Clear(reason) => Self::Clear(*reason),
141 OutputFrameKind::Rebaseline(_, reason) => Self::Rebaseline(*reason),
142 }
143 }
144}
145
146impl<C, O> TransactionResult<C, O> {
147 pub fn trace(&self) -> TransactionTrace {
149 TransactionTrace::from_result(self)
150 }
151}
152
153#[derive(Clone, Debug, Eq, PartialEq)]
155pub struct TraceMismatch {
156 pub expected: Vec<TransactionTrace>,
158 pub actual: Vec<TransactionTrace>,
160}
161
162pub fn assert_transaction_traces_match(
164 expected: &[TransactionTrace],
165 actual: &[TransactionTrace],
166) -> Result<(), TraceMismatch> {
167 if expected == actual {
168 Ok(())
169 } else {
170 Err(TraceMismatch {
171 expected: expected.to_vec(),
172 actual: actual.to_vec(),
173 })
174 }
175}