///|
pub fn build_replay_envelopes(matrix : ScenarioMatrix) -> Array[ReplayEnvelope] {
let result : Array[ReplayEnvelope] = []
let mut spec_index = 0
while spec_index < matrix.specs.length() {
let spec = matrix.specs[spec_index]
let mut target_index = 0
while target_index < spec.targets.length() {
let target = spec.targets[target_index]
match observation_for(matrix.observations, spec.id, target) {
None => ()
Some(observation) =>
result.push(ReplayEnvelope::{
case_id: spec.id,
target,
command: spec.command,
expected: spec.expected,
stdout: redact_machine_paths(observation.stdout),
stderr: redact_machine_paths(observation.stderr),
duration_ms: observation.duration_ms,
evidence_digest: observation.evidence_digest,
replay_key: replay_key(spec, observation),
})
}
target_index += 1
}
spec_index += 1
}
result
}
///|
pub fn replay_key(
spec : ScenarioSpec,
observation : ScenarioObservation,
) -> String {
let content = spec.id +
"|" +
observation.target.name() +
"|" +
spec.command +
"|" +
spec.expected.name() +
"|" +
observation.evidence_digest
scenario_evidence_digest(content, "")
}
///|
pub fn replay_envelope_to_text(envelope : ReplayEnvelope) -> String {
"replay case=" +
envelope.case_id +
" target=" +
envelope.target.name() +
" expected=" +
envelope.expected.name() +
" duration_ms=" +
envelope.duration_ms.to_string() +
" key=" +
envelope.replay_key +
" command=" +
quote_field(envelope.command) +
" stdout=" +
quote_field(envelope.stdout) +
" stderr=" +
quote_field(envelope.stderr) +
" digest=" +
quote_field(envelope.evidence_digest)
}
///|
pub fn replay_envelopes_to_text(envelopes : Array[ReplayEnvelope]) -> String {
let mut out = "# CakeCheck replay envelopes\n"
let mut index = 0
while index < envelopes.length() {
out = out + replay_envelope_to_text(envelopes[index]) + "\n"
index += 1
}
out
}
///|
pub fn replay_envelope_to_json(envelope : ReplayEnvelope) -> String {
let mut out = "{\"case\":\"" + json_escape(envelope.case_id) + "\","
out = out + "\"target\":\"" + envelope.target.name() + "\","
out = out + "\"expected\":\"" + envelope.expected.name() + "\","
out = out + "\"command\":\"" + json_escape(envelope.command) + "\","
out = out + "\"stdout\":\"" + json_escape(envelope.stdout) + "\","
out = out + "\"stderr\":\"" + json_escape(envelope.stderr) + "\","
out = out + "\"duration_ms\":" + envelope.duration_ms.to_string() + ","
out = out + "\"digest\":\"" + json_escape(envelope.evidence_digest) + "\","
out + "\"replay_key\":\"" + envelope.replay_key + "\"}"
}
///|
pub fn replay_envelopes_to_json(envelopes : Array[ReplayEnvelope]) -> String {
let mut out = "["
let mut index = 0
while index < envelopes.length() {
if index > 0 {
out = out + ","
}
out = out + replay_envelope_to_json(envelopes[index])
index += 1
}
out + "]"
}
///|
pub fn replay_envelopes_are_unique(envelopes : Array[ReplayEnvelope]) -> Bool {
let mut left = 0
while left < envelopes.length() {
let mut right = left + 1
while right < envelopes.length() {
if envelopes[left].replay_key == envelopes[right].replay_key {
return false
}
right += 1
}
left += 1
}
true
}
///|
pub fn replay_envelopes_digest(envelopes : Array[ReplayEnvelope]) -> String {
let lines : Array[String] = []
let mut index = 0
while index < envelopes.length() {
lines.push(envelopes[index].replay_key)
index += 1
}
digest_for_lines(lines)
}
///|
pub fn redact_machine_paths(value : String) -> String {
let normalized = replace_all(value, "C:\\Users\\", "/")
replace_all(normalized, "/home/", "/")
}
///|
fn replace_all(text : String, from : String, to : String) -> String {
if from.length() == 0 {
return text
}
let mut out = ""
let mut cursor = 0
while cursor < text.length() {
match index_of_from(text, from, cursor) {
None => {
out = out + slice(text, cursor, text.length())
cursor = text.length()
}
Some(position) => {
out = out + slice(text, cursor, position) + to
cursor = position + from.length()
}
}
}
out
}
///|
fn index_of_from(text : String, needle : String, start : Int) -> Int? {
if needle.length() > text.length() {
return None
}
let limit = text.length() - needle.length()
let mut index = start
while index <= limit {
if slice(text, index, index + needle.length()) == needle {
return Some(index)
}
index += 1
}
None
}