- 1
#![allow(clippy::unwrap_used, clippy::expect_used)] - 2
- 3
//! `vak office` (docs/design/72, P5): each verb prints the worker's JSON, - 4
//! apply never changes its source or overwrites, and verify's exit code - 5
//! is the verdict. - 6
- 7
use std::path::Path; - 8
use std::process::{Command, Output}; - 9
- 10
fn vak(dir: &Path, args: &[&str], stdin: Option<&str>) -> Output { - 11
use std::io::Write as _; - 12
let mut child = Command::new(env!("CARGO_BIN_EXE_vak")) - 13
.current_dir(dir) - 14
.args(args) - 15
.stdin(std::process::Stdio::piped()) - 16
.stdout(std::process::Stdio::piped()) - 17
.stderr(std::process::Stdio::piped()) - 18
.spawn() - 19
.unwrap(); - 20
if let Some(text) = stdin { - 21
child - 22
.stdin - 23
.take() - 24
.unwrap() - 25
.write_all(text.as_bytes()) - 26
.unwrap(); - 27
} - 28
drop(child.stdin.take()); - 29
child.wait_with_output().unwrap() - 30
} - 31
- 32
fn json(output: &Output) -> serde_json::Value { - 33
assert!( - 34
output.status.success(), - 35
"{}", - 36
String::from_utf8_lossy(&output.stderr) - 37
); - 38
serde_json::from_slice(&output.stdout).unwrap() - 39
} - 40
- 41
#[test] - 42
fn read_apply_diff_and_verify_a_workbook_from_the_command_line() { - 43
let dir = tempfile::tempdir().unwrap(); - 44
let source = vak_ooxml::fixtures::xlsx(); - 45
std::fs::write(dir.path().join("budget.xlsx"), &source).unwrap(); - 46
- 47
let facts = json(&vak( - 48
dir.path(), - 49
&["office", "read", "budget.xlsx", "--facts"], - 50
None, - 51
)); - 52
assert_eq!(facts["kind"], "Excel workbook"); - 53
assert!(facts["units"].as_array().unwrap().is_empty()); - 54
let digest = facts["sha256"].as_str().unwrap()[..16].to_string(); - 55
- 56
let ops = r#"[{"op":"set_cells","sheet":"Budget","cells":{"B2":150}}]"#; - 57
let applied = json(&vak( - 58
dir.path(), - 59
&[ - 60
"office", - 61
"apply", - 62
"budget.xlsx", - 63
"--ops", - 64
"-", - 65
"--base-digest", - 66
&digest, - 67
"--out", - 68
"budget-2.xlsx", - 69
], - 70
Some(ops), - 71
)); - 72
assert_eq!(applied["results"][0]["op"], "set_cells"); - 73
assert_eq!( - 74
applied["changes"]["summary"][0], "Budget: 1 changed", - 75
"{applied}" - 76
); - 77
assert_eq!( - 78
std::fs::read(dir.path().join("budget.xlsx")).unwrap(), - 79
source, - 80
"the source is unchanged" - 81
); - 82
- 83
let again = vak( - 84
dir.path(), - 85
&[ - 86
"office", - 87
"apply", - 88
"budget.xlsx", - 89
"--ops", - 90
"-", - 91
"--base-digest", - 92
&digest, - 93
"--out", - 94
"budget-2.xlsx", - 95
], - 96
Some(ops), - 97
); - 98
assert_eq!(again.status.code(), Some(2)); - 99
assert!(String::from_utf8_lossy(&again.stderr).contains("already exists")); - 100
- 101
let stale = vak( - 102
dir.path(), - 103
&[ - 104
"office", - 105
"apply", - 106
"budget.xlsx", - 107
"--ops", - 108
"-", - 109
"--base-digest", - 110
"0000000000000000", - 111
"--out", - 112
"budget-3.xlsx", - 113
], - 114
Some(ops), - 115
); - 116
assert_eq!(stale.status.code(), Some(2)); - 117
assert!(!dir.path().join("budget-3.xlsx").exists()); - 118
- 119
let diff = json(&vak( - 120
dir.path(), - 121
&["office", "diff", "budget.xlsx", "budget-2.xlsx"], - 122
None, - 123
)); - 124
assert_eq!(diff["changes"][0]["anchor"], "Budget!B2", "{diff}"); - 125
- 126
let verified = json(&vak( - 127
dir.path(), - 128
&["office", "verify", "budget-2.xlsx"], - 129
None, - 130
)); - 131
assert_eq!(verified["passed"], true); - 132
std::fs::copy( - 133
dir.path().join("budget-2.xlsx"), - 134
dir.path().join("budget.docx"), - 135
) - 136
.unwrap(); - 137
let renamed = vak(dir.path(), &["office", "verify", "budget.docx"], None); - 138
assert_eq!( - 139
renamed.status.code(), - 140
Some(1), - 141
"a workbook named .docx fails" - 142
); - 143
} - 144
- 145
#[test] - 146
fn a_file_is_created_from_scratch_verified_and_read_from_the_command_line() { - 147
let dir = tempfile::tempdir().unwrap(); - 148
let cases = [ - 149
( - 150
"memo.docx", - 151
r#"[{"op":"add_paragraph","text":"Q3 review","style":"Title"}, - 152
{"op":"add_paragraph","text":"Steps","style":"Heading 1"}, - 153
{"op":"add_paragraph","text":"Draft the budget","style":"List Number"}, - 154
{"op":"add_table","rows":[["Region","Revenue"],["North",120]]}]"#, - 155
"Word document", - 156
), - 157
( - 158
"budget.xlsx", - 159
r##"[{"op":"rename_sheet","sheet":"Sheet1","name":"Budget"}, - 160
{"op":"set_cells","sheet":"Budget","cells":{"A1":"Item","B1":"Cost","A2":"Rent","B2":1200,"B3":"=SUM(B2:B2)"}}, - 161
{"op":"format_cells","sheet":"Budget","range":"A1:B1","bold":true,"fill":"#D9E2F3"}, - 162
{"op":"set_column_widths","sheet":"Budget","widths":{"A":24}}]"##, - 163
"Excel workbook", - 164
), - 165
( - 166
"launch.pptx", - 167
r#"[{"op":"add_slide_from_layout","layout":"Title Slide","placeholders":{"title":"Launch plan","subtitle":"October"}}, - 168
{"op":"add_slide_from_layout","layout":"Title and Content","placeholders":{"title":"Goals","body":["Ship v1","Sign ten partners"]},"notes":"Keep it short."}]"#, - 169
"PowerPoint presentation", - 170
), - 171
]; - 172
for (name, ops, kind) in cases { - 173
let created = json(&vak( - 174
dir.path(), - 175
&["office", "apply", "--ops", "-", "--out", name], - 176
Some(ops), - 177
)); - 178
assert!( - 179
created["changes"]["changes"][0]["after"] - 180
.as_str() - 181
.unwrap() - 182
.starts_with("new file: "), - 183
"{created}" - 184
); - 185
let verified = json(&vak(dir.path(), &["office", "verify", name], None)); - 186
assert_eq!(verified["passed"], true, "{name}: {verified}"); - 187
let facts = json(&vak(dir.path(), &["office", "read", name, "--facts"], None)); - 188
assert_eq!(facts["kind"], kind, "{facts}"); - 189
assert!( - 190
facts["flags"].as_array().is_none_or(Vec::is_empty), - 191
"{name}: {facts}" - 192
); - 193
} - 194
- 195
let digest_without_file = vak( - 196
dir.path(), - 197
&[ - 198
"office", - 199
"apply", - 200
"--ops", - 201
"-", - 202
"--base-digest", - 203
"0123456789abcdef", - 204
"--out", - 205
"other.docx", - 206
], - 207
Some(r#"[{"op":"add_paragraph","text":"x"}]"#), - 208
); - 209
assert_eq!(digest_without_file.status.code(), Some(2)); - 210
assert!(String::from_utf8_lossy(&digest_without_file.stderr).contains("give the file")); - 211
assert!(!dir.path().join("other.docx").exists()); - 212
} - 213
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.